mirror of
https://github.com/nushell/nushell.git
synced 2024-11-16 05:23:44 +01:00
Port str lpad and str rpad (#334)
* Port str lpad and str rpad * Remove useless comment Co-authored-by: Stefan Stanciulescu <contact@stefanstanciulescu.com>
This commit is contained in:
parent
0f107b2830
commit
f1b2ab0b27
@ -113,6 +113,8 @@ pub fn create_default_context() -> EngineState {
|
||||
StrPascalCase,
|
||||
StrScreamingSnakeCase,
|
||||
StrSnakeCase,
|
||||
StrLpad,
|
||||
StrRpad,
|
||||
Sys,
|
||||
Table,
|
||||
To,
|
||||
|
180
crates/nu-command/src/strings/str_/lpad.rs
Normal file
180
crates/nu-command/src/strings/str_/lpad.rs
Normal file
@ -0,0 +1,180 @@
|
||||
use nu_engine::CallExt;
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::ast::CellPath;
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value};
|
||||
use std::sync::Arc;
|
||||
|
||||
struct Arguments {
|
||||
length: Option<i64>,
|
||||
character: Option<String>,
|
||||
column_paths: Vec<CellPath>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SubCommand;
|
||||
|
||||
impl Command 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(
|
||||
"rest",
|
||||
SyntaxShape::CellPath,
|
||||
"optionally check if string contains pattern by column paths",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"pad a string with a character a certain length"
|
||||
}
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
operate(engine_state, stack, call, input)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Left pad a string with a character a number of places",
|
||||
example: "'nushell' | str lpad -l 10 -c '*'",
|
||||
result: Some(Value::String {
|
||||
val: "***nushell".to_string(),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
},
|
||||
Example {
|
||||
description: "Left pad a string with a character a number of places",
|
||||
example: "'123' | str lpad -l 10 -c '0'",
|
||||
result: Some(Value::String {
|
||||
val: "0000000123".to_string(),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
},
|
||||
Example {
|
||||
description: "Use lpad to truncate a string",
|
||||
example: "'123456789' | str lpad -l 3 -c '0'",
|
||||
result: Some(Value::String {
|
||||
val: "123".to_string(),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
},
|
||||
Example {
|
||||
description: "Use lpad to pad Unicode",
|
||||
example: "'▉' | str lpad -l 10 -c '▉'",
|
||||
result: Some(Value::String {
|
||||
val: "▉▉▉▉▉▉▉▉▉▉".to_string(),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
fn operate(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let options = Arc::new(Arguments {
|
||||
length: call.get_flag(engine_state, stack, "length")?,
|
||||
character: call.get_flag(engine_state, stack, "character")?,
|
||||
column_paths: call.rest(engine_state, stack, 0)?,
|
||||
});
|
||||
|
||||
let head = call.head;
|
||||
input.map(
|
||||
move |v| {
|
||||
if options.column_paths.is_empty() {
|
||||
action(&v, &options, head)
|
||||
} else {
|
||||
let mut ret = v;
|
||||
for path in &options.column_paths {
|
||||
let opt = options.clone();
|
||||
let r = ret.update_cell_path(
|
||||
&path.members,
|
||||
Box::new(move |old| action(old, &opt, head)),
|
||||
);
|
||||
if let Err(error) = r {
|
||||
return Value::Error { error };
|
||||
}
|
||||
}
|
||||
ret
|
||||
}
|
||||
},
|
||||
engine_state.ctrlc.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn action(
|
||||
input: &Value,
|
||||
Arguments {
|
||||
character, length, ..
|
||||
}: &Arguments,
|
||||
head: Span,
|
||||
) -> Value {
|
||||
match &input {
|
||||
Value::String { val, .. } => match length {
|
||||
Some(x) => {
|
||||
let s = *x as usize;
|
||||
if s < val.len() {
|
||||
Value::String {
|
||||
val: val.chars().take(s).collect::<String>(),
|
||||
span: head,
|
||||
}
|
||||
} else {
|
||||
let c = character.as_ref().unwrap(); // we already know this flag needs to exist because the command is type checked before we call the action function
|
||||
let mut res = c.repeat(s - val.chars().count());
|
||||
res += val;
|
||||
Value::String {
|
||||
val: res,
|
||||
span: head,
|
||||
}
|
||||
}
|
||||
}
|
||||
None => Value::Error {
|
||||
error: ShellError::UnsupportedInput(
|
||||
String::from("Length argument is missing"),
|
||||
Span::unknown(),
|
||||
),
|
||||
},
|
||||
},
|
||||
other => Value::Error {
|
||||
error: ShellError::UnsupportedInput(
|
||||
format!(
|
||||
"Input's type is {}. This command only works with strings.",
|
||||
other.get_type()
|
||||
),
|
||||
Span::unknown(),
|
||||
),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_examples() {
|
||||
use crate::test_examples;
|
||||
|
||||
test_examples(SubCommand {})
|
||||
}
|
||||
}
|
@ -7,6 +7,8 @@ mod ends_with;
|
||||
mod find_replace;
|
||||
mod index_of;
|
||||
mod length;
|
||||
mod lpad;
|
||||
mod rpad;
|
||||
|
||||
pub use capitalize::SubCommand as StrCapitalize;
|
||||
pub use case::*;
|
||||
@ -17,3 +19,5 @@ pub use ends_with::SubCommand as StrEndswith;
|
||||
pub use find_replace::SubCommand as StrFindReplace;
|
||||
pub use index_of::SubCommand as StrIndexOf;
|
||||
pub use length::SubCommand as StrLength;
|
||||
pub use lpad::SubCommand as StrLpad;
|
||||
pub use rpad::SubCommand as StrRpad;
|
||||
|
180
crates/nu-command/src/strings/str_/rpad.rs
Normal file
180
crates/nu-command/src/strings/str_/rpad.rs
Normal file
@ -0,0 +1,180 @@
|
||||
use nu_engine::CallExt;
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::ast::CellPath;
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value};
|
||||
use std::sync::Arc;
|
||||
|
||||
struct Arguments {
|
||||
length: Option<i64>,
|
||||
character: Option<String>,
|
||||
column_paths: Vec<CellPath>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SubCommand;
|
||||
|
||||
impl Command for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"str rpad"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("str rpad")
|
||||
.required_named("length", SyntaxShape::Int, "length to pad to", Some('l'))
|
||||
.required_named(
|
||||
"character",
|
||||
SyntaxShape::String,
|
||||
"character to pad with",
|
||||
Some('c'),
|
||||
)
|
||||
.rest(
|
||||
"rest",
|
||||
SyntaxShape::CellPath,
|
||||
"optionally check if string contains pattern by column paths",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"pad a string with a character a certain length"
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
operate(engine_state, stack, call, input)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Right pad a string with a character a number of places",
|
||||
example: "'nushell' | str rpad -l 10 -c '*'",
|
||||
result: Some(Value::String {
|
||||
val: "nushell***".to_string(),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
},
|
||||
Example {
|
||||
description: "Right pad a string with a character a number of places",
|
||||
example: "'123' | str rpad -l 10 -c '0'",
|
||||
result: Some(Value::String {
|
||||
val: "1230000000".to_string(),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
},
|
||||
Example {
|
||||
description: "Use rpad to truncate a string",
|
||||
example: "'123456789' | str rpad -l 3 -c '0'",
|
||||
result: Some(Value::String {
|
||||
val: "123".to_string(),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
},
|
||||
Example {
|
||||
description: "Use rpad to pad Unicode",
|
||||
example: "'▉' | str rpad -l 10 -c '▉'",
|
||||
result: Some(Value::String {
|
||||
val: "▉▉▉▉▉▉▉▉▉▉".to_string(),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
fn operate(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let options = Arc::new(Arguments {
|
||||
length: call.get_flag(engine_state, stack, "length")?,
|
||||
character: call.get_flag(engine_state, stack, "character")?,
|
||||
column_paths: call.rest(engine_state, stack, 0)?,
|
||||
});
|
||||
|
||||
let head = call.head;
|
||||
input.map(
|
||||
move |v| {
|
||||
if options.column_paths.is_empty() {
|
||||
action(&v, &options, head)
|
||||
} else {
|
||||
let mut ret = v;
|
||||
for path in &options.column_paths {
|
||||
let opt = options.clone();
|
||||
let r = ret.update_cell_path(
|
||||
&path.members,
|
||||
Box::new(move |old| action(old, &opt, head)),
|
||||
);
|
||||
if let Err(error) = r {
|
||||
return Value::Error { error };
|
||||
}
|
||||
}
|
||||
ret
|
||||
}
|
||||
},
|
||||
engine_state.ctrlc.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn action(
|
||||
input: &Value,
|
||||
Arguments {
|
||||
character, length, ..
|
||||
}: &Arguments,
|
||||
head: Span,
|
||||
) -> Value {
|
||||
match &input {
|
||||
Value::String { val, .. } => match length {
|
||||
Some(x) => {
|
||||
let s = *x as usize;
|
||||
if s < val.len() {
|
||||
Value::String {
|
||||
val: val.chars().take(s).collect::<String>(),
|
||||
span: head,
|
||||
}
|
||||
} else {
|
||||
let mut res = val.to_string();
|
||||
res += &character.as_ref().unwrap().repeat(s - val.chars().count());
|
||||
Value::String {
|
||||
val: res,
|
||||
span: head,
|
||||
}
|
||||
}
|
||||
}
|
||||
None => Value::Error {
|
||||
error: ShellError::UnsupportedInput(
|
||||
String::from("Length argument is missing"),
|
||||
Span::unknown(),
|
||||
),
|
||||
},
|
||||
},
|
||||
other => Value::Error {
|
||||
error: ShellError::UnsupportedInput(
|
||||
format!(
|
||||
"Input's type is {}. This command only works with strings.",
|
||||
other.get_type()
|
||||
),
|
||||
Span::unknown(),
|
||||
),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_examples() {
|
||||
use crate::test_examples;
|
||||
|
||||
test_examples(SubCommand {})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user