From 60355ad7349f1f202f7470a64f3f2b159fb7f0a8 Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Wed, 11 Oct 2023 11:45:09 +0200 Subject: [PATCH] Parameter field (#16) https://en.wikipedia.org/wiki/Printf#Parameter_field --- src/lib.rs | 22 +++++++++++++++------- tests/test-crate/src/my_module.rs | 1 + tests/test-crate/translations.ini | 3 +++ tests/ui.rs | 3 +++ 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7d620c2..d0247b8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -119,7 +119,7 @@ use std::path::Path; // regex that tries to parse printf's format placeholders // see: https://docs.microsoft.com/en-us/cpp/c-runtime-library/format-specification-syntax-printf-and-wprintf-functions?view=msvc-160 static RE_PRINTF: Lazy = Lazy::new(|| { - Regex::new(r#"%([-+#])?(\d+)?(\.\d+)?([dis@xXf])|\\u([0-9a-fA-F]{4})|\\.|%%|%$|"|[^%"\\]+"#) + Regex::new(r#"%((?P\d+)\$)?(?P[-+#])?(?P\d+)?(?P\.\d+)?(?P[dis@xXf])|\\u(?P[0-9a-fA-F]{4})|\\.|%%|%$|"|[^%"\\]+"#) .unwrap() }); static RE_LANG: Lazy = Lazy::new(|| Regex::new(r"(\w+)(-(\w+))?").unwrap()); @@ -434,15 +434,23 @@ impl TwineFormatter { // transform all printf's format placeholder to Rust's format let mut out = String::new(); for caps in RE_PRINTF.captures_iter(text.as_str()) { - if let Some(type_) = caps.get(4) { - out.push_str("{:"); - if let Some(flag) = caps.get(1) { + if let Some(type_) = caps.name("type") { + out.push_str("{"); + if let Some(parameter) = caps.name("parameter") { + let parameter: usize = parameter + .as_str() + .parse() + .expect("could not parse parameter index"); + write!(out, "{}", parameter.saturating_sub(1))?; + } + out.push_str(":"); + if let Some(flag) = caps.name("flags") { out.push_str(flag.as_str()); } - if let Some(width) = caps.get(2) { + if let Some(width) = caps.name("width") { out.push_str(width.as_str()); } - if let Some(precision) = caps.get(3) { + if let Some(precision) = caps.name("precision") { out.push_str(precision.as_str()); } match type_.as_str() { @@ -454,7 +462,7 @@ impl TwineFormatter { out.push_str("%"); } else if &caps[0] == "\"" { out.push_str("\\\""); - } else if let Some(unicode) = caps.get(5) { + } else if let Some(unicode) = caps.name("unicode") { out.push_str(r"\u{"); out.push_str(unicode.as_str()); out.push_str(r"}"); diff --git a/tests/test-crate/src/my_module.rs b/tests/test-crate/src/my_module.rs index 9e0b39f..00ab3e5 100644 --- a/tests/test-crate/src/my_module.rs +++ b/tests/test-crate/src/my_module.rs @@ -11,6 +11,7 @@ pub fn basic() { println!("{}", t!(fallback_to_default_lang => lang)); println!("{}", t!(name_with_dot_in_it => lang)); println!("{}", t!(stuff_with_escaped_sequences_and_double_quotes => lang)); + println!("{}", t!(format_parameter_posix_extension, 1, 2 => lang)); } assert_eq!( diff --git a/tests/test-crate/translations.ini b/tests/test-crate/translations.ini index e711e5b..9acf31c 100644 --- a/tests/test-crate/translations.ini +++ b/tests/test-crate/translations.ini @@ -32,3 +32,6 @@ en = Name with a dot [stuff_with_escaped_sequences_and_double_quotes] en = Stuff with\nescaped\tsequences and "double quotes" +[format_parameter_posix_extension] + en = %1$s %2$4s + fr = %2$s %1$4s diff --git a/tests/ui.rs b/tests/ui.rs index 5c4d5f2..4fdf82b 100644 --- a/tests/ui.rs +++ b/tests/ui.rs @@ -7,6 +7,7 @@ Hello, World ! Hello Name with a dot Stuff with\nescaped\tsequences and \"double quotes\" +2 1 Ruin a band name by translating it in French Rage Against the Machine Hello, World! @@ -15,6 +16,7 @@ badcafe Hello Name with a dot Stuff with\nescaped\tsequences and \"double quotes\" +1 2 Ruin a band name by translating it in French Wrath Against the Machine Hello, World! @@ -23,6 +25,7 @@ badcafe Hello Name with a dot Stuff with\nescaped\tsequences and \"double quotes\" +1 2 "; #[test]