From 585786318f16ecee08845c995c0ac4b486821a44 Mon Sep 17 00:00:00 2001 From: ConnorSkees <39542938+ConnorSkees@users.noreply.github.com> Date: Sun, 22 Mar 2020 17:49:21 -0400 Subject: [PATCH] handle double wide characters in str-insert --- src/builtin/string.rs | 39 ++++++++++++++++++++++++++------------- tests/strings.rs | 13 +++++++++---- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/src/builtin/string.rs b/src/builtin/string.rs index 637bc6a..fef5acb 100644 --- a/src/builtin/string.rs +++ b/src/builtin/string.rs @@ -150,7 +150,7 @@ pub(crate) fn register(f: &mut HashMap) { "str-insert".to_owned(), Box::new(|args, _| { max_args!(args, 3); - let (mut string, q) = match arg!(args, 0, "string") { + let (s1, q) = match arg!(args, 0, "string") { Value::Ident(i, q) => (i, q), v => return Err(format!("$string: {} is not a string.", v).into()), }; @@ -176,27 +176,40 @@ pub(crate) fn register(f: &mut HashMap) { QuoteKind::None => QuoteKind::None, }; - let len = string.len(); + let len = s1.len(); - if index > Number::from(0) { - string.insert_str( + // Insert substring at char position, rather than byte position + let insert = |idx, s1: String, s2| { + s1.chars() + .enumerate() + .map(|(i, c)| { + if i + 1 == idx { + c.to_string() + s2 + } else if idx == 0 && i == 0 { + s2.to_string() + &c.to_string() + } else { + c.to_string() + } + }) + .collect::() + }; + + let string = if index > Number::from(0) { + insert( index.to_integer().to_usize().unwrap().min(len + 1) - 1, + s1, &substr, - ); + ) } else if index == Number::from(0) { - string.insert_str(0, &substr); + insert(0, s1, &substr) } else { let idx = index.abs().to_integer().to_usize().unwrap(); if idx > len { - string.insert_str(0, &substr) + insert(0, s1, &substr) } else { - string.insert_str( - len - idx + 1, - &substr, - ); - + insert(len - idx + 1, s1, &substr) } - } + }; Ok(Value::Ident(string, quotes)) }), diff --git a/tests/strings.rs b/tests/strings.rs index c263ede..17e9bbd 100644 --- a/tests/strings.rs +++ b/tests/strings.rs @@ -165,21 +165,26 @@ test!( "a {\n color: aXbc;\n}\n" ); error!( - float_idx, + str_insert_float_idx, "a {\n color: str-insert(abcd, \"X\", .5);\n}\n", "Error: $index: 0.5 is not an int." ); error!( - idx_with_units, + str_insert_idx_with_units, "a {\n color: str-insert(abcd, \"X\", 5px);\n}\n", "Error: $index: Expected 5px to have no units." ); test!( - idx_larger_than_string, + str_insert_idx_larger_than_string, "a {\n color: str-insert(abcd, \"X\", 20);\n}\n", "a {\n color: abcdX;\n}\n" ); test!( - idx_larger_than_string_negative, + str_insert_idx_larger_than_string_negative, "a {\n color: str-insert(abcd, \"X\", -20);\n}\n", "a {\n color: Xabcd;\n}\n" ); +test!( + str_insert_double_width_char, + "a {\n color: str-insert(\"👭\", \"c\", 2);\n}\n", + "@charset \"UTF-8\";\na {\n color: \"👭c\";\n}\n" +);