Files
nushell/crates/nu-cli/src/commands/str_/lpad.rs
Andrés N. Robalino b6d19cc9fa Move command changes. Refactorings. (#2683)
Continuing on anchoring and improvements on Nu's overall internal commands (#2635).
`move column` sub command has been turned into the command `move` since
we use it to move exclusively columns. Examples added as well.

Fixed it to carry along any anchor locations that might be in place if
table to be moved originates from other sources.
2020-10-20 04:07:13 -05:00

181 lines
5.1 KiB
Rust

use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_errors::ShellError;
use nu_protocol::ShellTypeName;
use nu_protocol::{
ColumnPath, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
};
use nu_source::{Tag, Tagged};
use nu_value_ext::ValueExt;
#[derive(Deserialize)]
struct Arguments {
length: Tagged<usize>,
character: Tagged<char>,
rest: Vec<ColumnPath>,
}
pub struct SubCommand;
#[async_trait]
impl WholeStreamCommand for SubCommand {
fn name(&self) -> &str {
"str lpad"
}
fn signature(&self) -> Signature {
Signature::build("str lpad")
.required_named("length", SyntaxShape::Int, "length to pad to", Some('l'))
.required_named(
"character",
SyntaxShape::String,
"character to pad with",
Some('c'),
)
.rest(
SyntaxShape::ColumnPath,
"optionally check if string contains pattern by column paths",
)
}
fn usage(&self) -> &str {
"pad a string with a character a certain length"
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
operate(args, registry).await
}
fn examples(&self) -> Vec<Example> {
vec![
Example {
description: "Left pad a string with a character a number of places",
example: "echo 'nushell' | str lpad -l 10 -c '*'",
result: Some(vec![
UntaggedValue::string("***nushell").into_untagged_value()
]),
},
Example {
description: "Left pad a string with a character a number of places",
example: "echo '123' | str lpad -l 10 -c '0'",
result: Some(vec![
UntaggedValue::string("0000000123").into_untagged_value()
]),
},
Example {
description: "Use lpad to truncate a string",
example: "echo '123456789' | str lpad -l 3 -c '0'",
result: Some(vec![UntaggedValue::string("123").into_untagged_value()]),
},
]
}
}
async fn operate(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let registry = registry.clone();
let (
Arguments {
length,
character,
rest,
},
input,
) = args.process(&registry).await?;
let column_paths: Vec<_> = rest;
Ok(input
.map(move |v| {
let len = length.item;
let character = character.item;
if column_paths.is_empty() {
ReturnSuccess::value(action(&v, len, character, v.tag())?)
} else {
let mut ret = v;
for path in &column_paths {
ret = ret.swap_data_by_column_path(
path,
Box::new(move |old| action(old, len, character, old.tag())),
)?;
}
ReturnSuccess::value(ret)
}
})
.to_output_stream())
}
fn action(
input: &Value,
length: usize,
character: char,
tag: impl Into<Tag>,
) -> Result<Value, ShellError> {
match &input.value {
UntaggedValue::Primitive(Primitive::Line(s))
| UntaggedValue::Primitive(Primitive::String(s)) => {
if length < s.len() {
Ok(UntaggedValue::string(&s[0..length]).into_value(tag))
} else {
let mut res = character.to_string().repeat(length - s.len());
res += s.as_ref();
Ok(UntaggedValue::string(res).into_value(tag))
}
}
other => {
let got = format!("got {}", other.type_name());
Err(ShellError::labeled_error(
"value is not string",
got,
tag.into().span,
))
}
}
}
#[cfg(test)]
mod tests {
use super::{action, SubCommand};
use nu_errors::ShellError;
use nu_protocol::UntaggedValue;
use nu_source::Tag;
use nu_test_support::value::string;
#[test]
fn examples_work_as_expected() -> Result<(), ShellError> {
use crate::examples::test as test_examples;
Ok(test_examples(SubCommand {})?)
}
#[test]
fn left_pad_with_zeros() {
let word = string("123");
let pad_char = '0';
let pad_len = 10;
let expected = UntaggedValue::string("0000000123").into_untagged_value();
let actual = action(&word, pad_len, pad_char, Tag::unknown()).unwrap();
assert_eq!(actual, expected);
}
#[test]
fn left_pad_but_truncate() {
let word = string("123456789");
let pad_char = '0';
let pad_len = 3;
let expected = UntaggedValue::string("123").into_untagged_value();
let actual = action(&word, pad_len, pad_char, Tag::unknown()).unwrap();
assert_eq!(actual, expected);
}
}