From 7244d34c7c0ec3651a595ccd6c2d51b567dcf2bd Mon Sep 17 00:00:00 2001 From: Federico Terzi Date: Sun, 7 Nov 2021 14:21:59 +0100 Subject: [PATCH] feat(migrate): implement form syntax auto migration #856 --- espanso-migrate/src/convert.rs | 67 ++++++++++++++++++- espanso-migrate/src/lib.rs | 2 + .../form_syntax/expected/config/default.yml | 0 .../test/form_syntax/expected/match/base.yml | 25 +++++++ .../test/form_syntax/legacy/default.yml | 25 +++++++ 5 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 espanso-migrate/test/form_syntax/expected/config/default.yml create mode 100644 espanso-migrate/test/form_syntax/expected/match/base.yml create mode 100644 espanso-migrate/test/form_syntax/legacy/default.yml diff --git a/espanso-migrate/src/convert.rs b/espanso-migrate/src/convert.rs index 9fd8613..4e9b4c5 100644 --- a/espanso-migrate/src/convert.rs +++ b/espanso-migrate/src/convert.rs @@ -17,6 +17,7 @@ * along with espanso. If not, see . */ +use regex::{Captures, Regex}; use std::{cmp::Ordering, collections::HashMap, path::PathBuf}; use yaml_rust::{yaml::Hash, Yaml}; @@ -69,24 +70,32 @@ pub fn convert(input_files: HashMap) -> HashMap = global_vars.clone(); + patched_global_vars + .iter_mut() + .for_each(apply_form_syntax_patch_to_variable); + let output_global_vars = output_yaml .content .entry(Yaml::String("global_vars".to_string())) .or_insert(Yaml::Array(Vec::new())); 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 { eprintln!("unable to transform global_vars for file: {}", input_path); } } if let Some(matches) = yaml_matches { + let mut patched_matches = matches.clone(); + apply_form_syntax_patch(&mut patched_matches); + let output_matches = output_yaml .content .entry(Yaml::String("matches".to_string())) .or_insert(Yaml::Array(Vec::new())); if let Yaml::Array(out_matches) = output_matches { - out_matches.extend(matches.clone()); + out_matches.extend(patched_matches); } else { 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) { + 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.*?)\}\}").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() +} diff --git a/espanso-migrate/src/lib.rs b/espanso-migrate/src/lib.rs index 1208053..d3c9710 100644 --- a/espanso-migrate/src/lib.rs +++ b/espanso-migrate/src/lib.rs @@ -200,12 +200,14 @@ mod tests { static BASE_CASE: Dir = include_dir!("test/base"); static ALL_PARAMS_CASE: Dir = include_dir!("test/all_params"); static OTHER_DIRS_CASE: Dir = include_dir!("test/other_dirs"); + static FORM_SYNTAX: Dir = include_dir!("test/form_syntax"); #[allow(clippy::unused_unit)] #[test_case(&SIMPLE_CASE; "simple case")] #[test_case(&BASE_CASE; "base case")] #[test_case(&ALL_PARAMS_CASE; "all config parameters case")] #[test_case(&OTHER_DIRS_CASE; "other directories case")] + #[test_case(&FORM_SYNTAX; "form syntax")] fn test_migration(test_data: &Dir) { run_with_temp_dir(test_data, |legacy, expected| { let tmp_out_dir = TempDir::new("espanso-migrate-out").unwrap(); diff --git a/espanso-migrate/test/form_syntax/expected/config/default.yml b/espanso-migrate/test/form_syntax/expected/config/default.yml new file mode 100644 index 0000000..e69de29 diff --git a/espanso-migrate/test/form_syntax/expected/match/base.yml b/espanso-migrate/test/form_syntax/expected/match/base.yml new file mode 100644 index 0000000..474aecc --- /dev/null +++ b/espanso-migrate/test/form_syntax/expected/match/base.yml @@ -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" \ No newline at end of file diff --git a/espanso-migrate/test/form_syntax/legacy/default.yml b/espanso-migrate/test/form_syntax/legacy/default.yml new file mode 100644 index 0000000..22324a1 --- /dev/null +++ b/espanso-migrate/test/form_syntax/legacy/default.yml @@ -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" \ No newline at end of file