allow pad to use multi-byte chars (#2973)

This commit is contained in:
Darren Schroeder 2021-01-26 03:09:38 -06:00 committed by GitHub
parent 82f122525c
commit 2129ec7558
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 16 deletions

View File

@ -11,7 +11,7 @@ use nu_value_ext::ValueExt;
#[derive(Deserialize)]
struct Arguments {
length: Tagged<usize>,
character: Tagged<char>,
character: Tagged<String>,
rest: Vec<ColumnPath>,
}
@ -67,6 +67,13 @@ impl WholeStreamCommand for SubCommand {
example: "echo '123456789' | str lpad -l 3 -c '0'",
result: Some(vec![UntaggedValue::string("123").into_untagged_value()]),
},
Example {
description: "Use lpad to pad unicode",
example: "echo '▉' | str lpad -l 10 -c '▉'",
result: Some(vec![
UntaggedValue::string("▉▉▉▉▉▉▉▉▉▉").into_untagged_value()
]),
},
]
}
}
@ -85,16 +92,17 @@ async fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
Ok(input
.map(move |v| {
let len = length.item;
let character = character.item;
let character = character.item.clone();
if column_paths.is_empty() {
ReturnSuccess::value(action(&v, len, character, v.tag())?)
} else {
let mut ret = v;
for path in &column_paths {
let str_clone = character.clone();
ret = ret.swap_data_by_column_path(
path,
Box::new(move |old| action(old, len, character, old.tag())),
Box::new(move |old| action(old, len, str_clone, old.tag())),
)?;
}
@ -107,15 +115,18 @@ async fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
fn action(
input: &Value,
length: usize,
character: char,
character: String,
tag: impl Into<Tag>,
) -> Result<Value, ShellError> {
match &input.value {
UntaggedValue::Primitive(Primitive::String(s)) => {
if length < s.len() {
Ok(UntaggedValue::string(&s[0..length]).into_value(tag))
Ok(
UntaggedValue::string(s.chars().take(length).collect::<String>())
.into_value(tag),
)
} else {
let mut res = character.to_string().repeat(length - s.len());
let mut res = character.repeat(length - s.chars().count());
res += s.as_ref();
Ok(UntaggedValue::string(res).into_value(tag))
}
@ -149,7 +160,7 @@ mod tests {
#[test]
fn left_pad_with_zeros() {
let word = string("123");
let pad_char = '0';
let pad_char = '0'.to_string();
let pad_len = 10;
let expected = UntaggedValue::string("0000000123").into_untagged_value();
@ -160,7 +171,7 @@ mod tests {
#[test]
fn left_pad_but_truncate() {
let word = string("123456789");
let pad_char = '0';
let pad_char = '0'.to_string();
let pad_len = 3;
let expected = UntaggedValue::string("123").into_untagged_value();

View File

@ -11,7 +11,7 @@ use nu_value_ext::ValueExt;
#[derive(Deserialize)]
struct Arguments {
length: Tagged<usize>,
character: Tagged<char>,
character: Tagged<String>,
rest: Vec<ColumnPath>,
}
@ -67,6 +67,13 @@ impl WholeStreamCommand for SubCommand {
example: "echo '123456789' | str rpad -l 3 -c '0'",
result: Some(vec![UntaggedValue::string("123").into_untagged_value()]),
},
Example {
description: "Use rpad to pad unicode",
example: "echo '▉' | str rpad -l 10 -c '▉'",
result: Some(vec![
UntaggedValue::string("▉▉▉▉▉▉▉▉▉▉").into_untagged_value()
]),
},
]
}
}
@ -85,16 +92,17 @@ async fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
Ok(input
.map(move |v| {
let len = length.item;
let character = character.item;
let character = character.item.clone();
if column_paths.is_empty() {
ReturnSuccess::value(action(&v, len, character, v.tag())?)
} else {
let mut ret = v;
for path in &column_paths {
let str_clone = character.clone();
ret = ret.swap_data_by_column_path(
path,
Box::new(move |old| action(old, len, character, old.tag())),
Box::new(move |old| action(old, len, str_clone, old.tag())),
)?;
}
@ -107,16 +115,19 @@ async fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
fn action(
input: &Value,
length: usize,
character: char,
character: String,
tag: impl Into<Tag>,
) -> Result<Value, ShellError> {
match &input.value {
UntaggedValue::Primitive(Primitive::String(s)) => {
if length < s.len() {
Ok(UntaggedValue::string(&s[0..length]).into_value(tag))
Ok(
UntaggedValue::string(s.chars().take(length).collect::<String>())
.into_value(tag),
)
} else {
let mut res = s.to_string();
res += character.to_string().repeat(length - s.len()).as_str();
res += character.repeat(length - s.chars().count()).as_str();
Ok(UntaggedValue::string(res).into_value(tag))
}
}
@ -149,7 +160,7 @@ mod tests {
#[test]
fn right_pad_with_zeros() {
let word = string("123");
let pad_char = '0';
let pad_char = '0'.to_string();
let pad_len = 10;
let expected = UntaggedValue::string("1230000000").into_untagged_value();
@ -160,7 +171,7 @@ mod tests {
#[test]
fn right_pad_but_truncate() {
let word = string("123456789");
let pad_char = '0';
let pad_char = '0'.to_string();
let pad_len = 3;
let expected = UntaggedValue::string("123").into_untagged_value();