feat(migrate): implement form syntax auto migration #856
This commit is contained in:
parent
fa26b1ffde
commit
7244d34c7c
|
@ -17,6 +17,7 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use regex::{Captures, Regex};
|
||||||
use std::{cmp::Ordering, collections::HashMap, path::PathBuf};
|
use std::{cmp::Ordering, collections::HashMap, path::PathBuf};
|
||||||
use yaml_rust::{yaml::Hash, Yaml};
|
use yaml_rust::{yaml::Hash, Yaml};
|
||||||
|
|
||||||
|
@ -69,24 +70,32 @@ pub fn convert(input_files: HashMap<String, Hash>) -> HashMap<String, ConvertedF
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(global_vars) = yaml_global_vars {
|
if let Some(global_vars) = yaml_global_vars {
|
||||||
|
let mut patched_global_vars: Vec<Yaml> = global_vars.clone();
|
||||||
|
patched_global_vars
|
||||||
|
.iter_mut()
|
||||||
|
.for_each(apply_form_syntax_patch_to_variable);
|
||||||
|
|
||||||
let output_global_vars = output_yaml
|
let output_global_vars = output_yaml
|
||||||
.content
|
.content
|
||||||
.entry(Yaml::String("global_vars".to_string()))
|
.entry(Yaml::String("global_vars".to_string()))
|
||||||
.or_insert(Yaml::Array(Vec::new()));
|
.or_insert(Yaml::Array(Vec::new()));
|
||||||
if let Yaml::Array(out_global_vars) = output_global_vars {
|
if let Yaml::Array(out_global_vars) = output_global_vars {
|
||||||
out_global_vars.extend(global_vars.clone());
|
out_global_vars.extend(patched_global_vars);
|
||||||
} else {
|
} else {
|
||||||
eprintln!("unable to transform global_vars for file: {}", input_path);
|
eprintln!("unable to transform global_vars for file: {}", input_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(matches) = yaml_matches {
|
if let Some(matches) = yaml_matches {
|
||||||
|
let mut patched_matches = matches.clone();
|
||||||
|
apply_form_syntax_patch(&mut patched_matches);
|
||||||
|
|
||||||
let output_matches = output_yaml
|
let output_matches = output_yaml
|
||||||
.content
|
.content
|
||||||
.entry(Yaml::String("matches".to_string()))
|
.entry(Yaml::String("matches".to_string()))
|
||||||
.or_insert(Yaml::Array(Vec::new()));
|
.or_insert(Yaml::Array(Vec::new()));
|
||||||
if let Yaml::Array(out_matches) = output_matches {
|
if let Yaml::Array(out_matches) = output_matches {
|
||||||
out_matches.extend(matches.clone());
|
out_matches.extend(patched_matches);
|
||||||
} else {
|
} else {
|
||||||
eprintln!("unable to transform matches for file: {}", input_path);
|
eprintln!("unable to transform matches for file: {}", input_path);
|
||||||
}
|
}
|
||||||
|
@ -324,3 +333,57 @@ fn map_field_if_present(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is needed to convert the old form's {{control}} syntax to the new [[control]] one.
|
||||||
|
fn apply_form_syntax_patch(matches: &mut Vec<Yaml>) {
|
||||||
|
matches.iter_mut().for_each(|m| {
|
||||||
|
if let Yaml::Hash(fields) = m {
|
||||||
|
if let Some(Yaml::String(form_option)) = fields.get_mut(&Yaml::String("form".to_string())) {
|
||||||
|
let converted = replace_legacy_form_syntax_with_new_one(form_option);
|
||||||
|
if &converted != form_option {
|
||||||
|
form_option.clear();
|
||||||
|
form_option.push_str(&converted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(Yaml::Array(vars)) = fields.get_mut(&Yaml::String("vars".to_string())) {
|
||||||
|
vars
|
||||||
|
.iter_mut()
|
||||||
|
.for_each(apply_form_syntax_patch_to_variable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_form_syntax_patch_to_variable(variable: &mut Yaml) {
|
||||||
|
if let Yaml::Hash(fields) = variable {
|
||||||
|
if let Some(Yaml::String(var_type)) = fields.get(&Yaml::String("type".to_string())) {
|
||||||
|
if var_type != "form" {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(Yaml::Hash(params)) = fields.get_mut(&Yaml::String("params".to_string())) {
|
||||||
|
if let Some(Yaml::String(layout)) = params.get_mut(&Yaml::String("layout".to_string())) {
|
||||||
|
let converted = replace_legacy_form_syntax_with_new_one(layout);
|
||||||
|
if &converted != layout {
|
||||||
|
layout.clear();
|
||||||
|
layout.push_str(&converted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref LEGACY_FIELD_REGEX: Regex = Regex::new(r"\{\{(?P<name>.*?)\}\}").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn replace_legacy_form_syntax_with_new_one(layout: &str) -> String {
|
||||||
|
LEGACY_FIELD_REGEX
|
||||||
|
.replace_all(layout, |caps: &Captures| {
|
||||||
|
let field_name = caps.name("name").unwrap().as_str();
|
||||||
|
format!("[[{}]]", field_name)
|
||||||
|
})
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
|
@ -200,12 +200,14 @@ mod tests {
|
||||||
static BASE_CASE: Dir = include_dir!("test/base");
|
static BASE_CASE: Dir = include_dir!("test/base");
|
||||||
static ALL_PARAMS_CASE: Dir = include_dir!("test/all_params");
|
static ALL_PARAMS_CASE: Dir = include_dir!("test/all_params");
|
||||||
static OTHER_DIRS_CASE: Dir = include_dir!("test/other_dirs");
|
static OTHER_DIRS_CASE: Dir = include_dir!("test/other_dirs");
|
||||||
|
static FORM_SYNTAX: Dir = include_dir!("test/form_syntax");
|
||||||
|
|
||||||
#[allow(clippy::unused_unit)]
|
#[allow(clippy::unused_unit)]
|
||||||
#[test_case(&SIMPLE_CASE; "simple case")]
|
#[test_case(&SIMPLE_CASE; "simple case")]
|
||||||
#[test_case(&BASE_CASE; "base case")]
|
#[test_case(&BASE_CASE; "base case")]
|
||||||
#[test_case(&ALL_PARAMS_CASE; "all config parameters case")]
|
#[test_case(&ALL_PARAMS_CASE; "all config parameters case")]
|
||||||
#[test_case(&OTHER_DIRS_CASE; "other directories case")]
|
#[test_case(&OTHER_DIRS_CASE; "other directories case")]
|
||||||
|
#[test_case(&FORM_SYNTAX; "form syntax")]
|
||||||
fn test_migration(test_data: &Dir) {
|
fn test_migration(test_data: &Dir) {
|
||||||
run_with_temp_dir(test_data, |legacy, expected| {
|
run_with_temp_dir(test_data, |legacy, expected| {
|
||||||
let tmp_out_dir = TempDir::new("espanso-migrate-out").unwrap();
|
let tmp_out_dir = TempDir::new("espanso-migrate-out").unwrap();
|
||||||
|
|
25
espanso-migrate/test/form_syntax/expected/match/base.yml
Normal file
25
espanso-migrate/test/form_syntax/expected/match/base.yml
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
global_vars:
|
||||||
|
- name: global_form
|
||||||
|
type: form
|
||||||
|
params:
|
||||||
|
layout: |
|
||||||
|
Reverse [[name]]
|
||||||
|
|
||||||
|
matches:
|
||||||
|
- trigger: ":greet"
|
||||||
|
form: |
|
||||||
|
Hey [[name]],
|
||||||
|
Happy Birthday!
|
||||||
|
|
||||||
|
- trigger: ":rev"
|
||||||
|
replace: "{{reversed}}"
|
||||||
|
vars:
|
||||||
|
- name: form1
|
||||||
|
type: form
|
||||||
|
params:
|
||||||
|
layout: |
|
||||||
|
Reverse [[name]]
|
||||||
|
- name: reversed
|
||||||
|
type: shell
|
||||||
|
params:
|
||||||
|
cmd: "echo $ESPANSO_FORM1_NAME | rev"
|
25
espanso-migrate/test/form_syntax/legacy/default.yml
Normal file
25
espanso-migrate/test/form_syntax/legacy/default.yml
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
global_vars:
|
||||||
|
- name: global_form
|
||||||
|
type: form
|
||||||
|
params:
|
||||||
|
layout: |
|
||||||
|
Reverse {{name}}
|
||||||
|
|
||||||
|
matches:
|
||||||
|
- trigger: ":greet"
|
||||||
|
form: |
|
||||||
|
Hey {{name}},
|
||||||
|
Happy Birthday!
|
||||||
|
|
||||||
|
- trigger: ":rev"
|
||||||
|
replace: "{{reversed}}"
|
||||||
|
vars:
|
||||||
|
- name: form1
|
||||||
|
type: form
|
||||||
|
params:
|
||||||
|
layout: |
|
||||||
|
Reverse {{name}}
|
||||||
|
- name: reversed
|
||||||
|
type: shell
|
||||||
|
params:
|
||||||
|
cmd: "echo $ESPANSO_FORM1_NAME | rev"
|
Loading…
Reference in New Issue
Block a user