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)] #[derive(Deserialize)]
struct Arguments { struct Arguments {
length: Tagged<usize>, length: Tagged<usize>,
character: Tagged<char>, character: Tagged<String>,
rest: Vec<ColumnPath>, rest: Vec<ColumnPath>,
} }
@ -67,6 +67,13 @@ impl WholeStreamCommand for SubCommand {
example: "echo '123456789' | str lpad -l 3 -c '0'", example: "echo '123456789' | str lpad -l 3 -c '0'",
result: Some(vec![UntaggedValue::string("123").into_untagged_value()]), 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 Ok(input
.map(move |v| { .map(move |v| {
let len = length.item; let len = length.item;
let character = character.item; let character = character.item.clone();
if column_paths.is_empty() { if column_paths.is_empty() {
ReturnSuccess::value(action(&v, len, character, v.tag())?) ReturnSuccess::value(action(&v, len, character, v.tag())?)
} else { } else {
let mut ret = v; let mut ret = v;
for path in &column_paths { for path in &column_paths {
let str_clone = character.clone();
ret = ret.swap_data_by_column_path( ret = ret.swap_data_by_column_path(
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( fn action(
input: &Value, input: &Value,
length: usize, length: usize,
character: char, character: String,
tag: impl Into<Tag>, tag: impl Into<Tag>,
) -> Result<Value, ShellError> { ) -> Result<Value, ShellError> {
match &input.value { match &input.value {
UntaggedValue::Primitive(Primitive::String(s)) => { UntaggedValue::Primitive(Primitive::String(s)) => {
if length < s.len() { 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 { } else {
let mut res = character.to_string().repeat(length - s.len()); let mut res = character.repeat(length - s.chars().count());
res += s.as_ref(); res += s.as_ref();
Ok(UntaggedValue::string(res).into_value(tag)) Ok(UntaggedValue::string(res).into_value(tag))
} }
@ -149,7 +160,7 @@ mod tests {
#[test] #[test]
fn left_pad_with_zeros() { fn left_pad_with_zeros() {
let word = string("123"); let word = string("123");
let pad_char = '0'; let pad_char = '0'.to_string();
let pad_len = 10; let pad_len = 10;
let expected = UntaggedValue::string("0000000123").into_untagged_value(); let expected = UntaggedValue::string("0000000123").into_untagged_value();
@ -160,7 +171,7 @@ mod tests {
#[test] #[test]
fn left_pad_but_truncate() { fn left_pad_but_truncate() {
let word = string("123456789"); let word = string("123456789");
let pad_char = '0'; let pad_char = '0'.to_string();
let pad_len = 3; let pad_len = 3;
let expected = UntaggedValue::string("123").into_untagged_value(); let expected = UntaggedValue::string("123").into_untagged_value();

View File

@ -11,7 +11,7 @@ use nu_value_ext::ValueExt;
#[derive(Deserialize)] #[derive(Deserialize)]
struct Arguments { struct Arguments {
length: Tagged<usize>, length: Tagged<usize>,
character: Tagged<char>, character: Tagged<String>,
rest: Vec<ColumnPath>, rest: Vec<ColumnPath>,
} }
@ -67,6 +67,13 @@ impl WholeStreamCommand for SubCommand {
example: "echo '123456789' | str rpad -l 3 -c '0'", example: "echo '123456789' | str rpad -l 3 -c '0'",
result: Some(vec![UntaggedValue::string("123").into_untagged_value()]), 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 Ok(input
.map(move |v| { .map(move |v| {
let len = length.item; let len = length.item;
let character = character.item; let character = character.item.clone();
if column_paths.is_empty() { if column_paths.is_empty() {
ReturnSuccess::value(action(&v, len, character, v.tag())?) ReturnSuccess::value(action(&v, len, character, v.tag())?)
} else { } else {
let mut ret = v; let mut ret = v;
for path in &column_paths { for path in &column_paths {
let str_clone = character.clone();
ret = ret.swap_data_by_column_path( ret = ret.swap_data_by_column_path(
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( fn action(
input: &Value, input: &Value,
length: usize, length: usize,
character: char, character: String,
tag: impl Into<Tag>, tag: impl Into<Tag>,
) -> Result<Value, ShellError> { ) -> Result<Value, ShellError> {
match &input.value { match &input.value {
UntaggedValue::Primitive(Primitive::String(s)) => { UntaggedValue::Primitive(Primitive::String(s)) => {
if length < s.len() { 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 { } else {
let mut res = s.to_string(); 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)) Ok(UntaggedValue::string(res).into_value(tag))
} }
} }
@ -149,7 +160,7 @@ mod tests {
#[test] #[test]
fn right_pad_with_zeros() { fn right_pad_with_zeros() {
let word = string("123"); let word = string("123");
let pad_char = '0'; let pad_char = '0'.to_string();
let pad_len = 10; let pad_len = 10;
let expected = UntaggedValue::string("1230000000").into_untagged_value(); let expected = UntaggedValue::string("1230000000").into_untagged_value();
@ -160,7 +171,7 @@ mod tests {
#[test] #[test]
fn right_pad_but_truncate() { fn right_pad_but_truncate() {
let word = string("123456789"); let word = string("123456789");
let pad_char = '0'; let pad_char = '0'.to_string();
let pad_len = 3; let pad_len = 3;
let expected = UntaggedValue::string("123").into_untagged_value(); let expected = UntaggedValue::string("123").into_untagged_value();