mirror of
https://github.com/nushell/nushell.git
synced 2025-03-30 01:28:11 +01:00
Refactor: finish refactor on commands which take optional cell paths. (#6961)
* refactor on conversions module * finish refactor on strings command * simplify code * rename from ArgumentsCp to CellPathOnlyArgs * fmt code * refactor on hash relative commands
This commit is contained in:
parent
1d95861a09
commit
e46d610f77
@ -1,4 +1,4 @@
|
|||||||
use crate::input_handler::{operate, CmdArgument};
|
use crate::input_handler::{operate, CellPathOnlyArgs};
|
||||||
use nu_engine::CallExt;
|
use nu_engine::CallExt;
|
||||||
use nu_protocol::ast::Call;
|
use nu_protocol::ast::Call;
|
||||||
use nu_protocol::ast::CellPath;
|
use nu_protocol::ast::CellPath;
|
||||||
@ -9,16 +9,6 @@ use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShap
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct BytesLen;
|
pub struct BytesLen;
|
||||||
|
|
||||||
struct Arguments {
|
|
||||||
cell_paths: Option<Vec<CellPath>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CmdArgument for Arguments {
|
|
||||||
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
|
|
||||||
self.cell_paths.take()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Command for BytesLen {
|
impl Command for BytesLen {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"bytes length"
|
"bytes length"
|
||||||
@ -50,8 +40,7 @@ impl Command for BytesLen {
|
|||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
|
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
|
||||||
let cell_paths = (!cell_paths.is_empty()).then(|| cell_paths);
|
let arg = CellPathOnlyArgs::from(cell_paths);
|
||||||
let arg = Arguments { cell_paths };
|
|
||||||
operate(length, arg, input, call.head, engine_state.ctrlc.clone())
|
operate(length, arg, input, call.head, engine_state.ctrlc.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,7 +63,7 @@ impl Command for BytesLen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn length(val: &Value, _args: &Arguments, span: Span) -> Value {
|
fn length(val: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
|
||||||
match val {
|
match val {
|
||||||
Value::Binary {
|
Value::Binary {
|
||||||
val,
|
val,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::input_handler::{operate, CmdArgument};
|
use crate::input_handler::{operate, CellPathOnlyArgs};
|
||||||
use nu_engine::CallExt;
|
use nu_engine::CallExt;
|
||||||
use nu_protocol::ast::Call;
|
use nu_protocol::ast::Call;
|
||||||
use nu_protocol::ast::CellPath;
|
use nu_protocol::ast::CellPath;
|
||||||
@ -6,16 +6,6 @@ use nu_protocol::engine::{Command, EngineState, Stack};
|
|||||||
use nu_protocol::Category;
|
use nu_protocol::Category;
|
||||||
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value};
|
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value};
|
||||||
|
|
||||||
struct Arguments {
|
|
||||||
cell_paths: Option<Vec<CellPath>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CmdArgument for Arguments {
|
|
||||||
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
|
|
||||||
self.cell_paths.take()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
||||||
pub struct BytesReverse;
|
pub struct BytesReverse;
|
||||||
@ -51,8 +41,7 @@ impl Command for BytesReverse {
|
|||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||||
let cell_paths = (!cell_paths.is_empty()).then(|| cell_paths);
|
let arg = CellPathOnlyArgs::from(cell_paths);
|
||||||
let arg = Arguments { cell_paths };
|
|
||||||
operate(reverse, arg, input, call.head, engine_state.ctrlc.clone())
|
operate(reverse, arg, input, call.head, engine_state.ctrlc.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +67,7 @@ impl Command for BytesReverse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reverse(val: &Value, _args: &Arguments, span: Span) -> Value {
|
fn reverse(val: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
|
||||||
match val {
|
match val {
|
||||||
Value::Binary {
|
Value::Binary {
|
||||||
val,
|
val,
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::input_handler::{operate, CellPathOnlyArgs};
|
||||||
use nu_engine::CallExt;
|
use nu_engine::CallExt;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{Call, CellPath},
|
ast::{Call, CellPath},
|
||||||
@ -96,31 +97,12 @@ fn fmt(
|
|||||||
call: &Call,
|
call: &Call,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
let head = call.head;
|
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||||
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
let args = CellPathOnlyArgs::from(cell_paths);
|
||||||
|
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||||
input.map(
|
|
||||||
move |v| {
|
|
||||||
if column_paths.is_empty() {
|
|
||||||
action(&v, head)
|
|
||||||
} else {
|
|
||||||
let mut ret = v;
|
|
||||||
for path in &column_paths {
|
|
||||||
let r =
|
|
||||||
ret.update_cell_path(&path.members, Box::new(move |old| action(old, head)));
|
|
||||||
if let Err(error) = r {
|
|
||||||
return Value::Error { error };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
},
|
|
||||||
engine_state.ctrlc.clone(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn action(input: &Value, span: Span) -> Value {
|
fn action(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
|
||||||
match input {
|
match input {
|
||||||
Value::Int { val, .. } => fmt_it(*val, span),
|
Value::Int { val, .. } => fmt_it(*val, span),
|
||||||
Value::Filesize { val, .. } => fmt_it(*val, span),
|
Value::Filesize { val, .. } => fmt_it(*val, span),
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::input_handler::{operate, CellPathOnlyArgs};
|
||||||
use nu_engine::CallExt;
|
use nu_engine::CallExt;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{Call, CellPath},
|
ast::{Call, CellPath},
|
||||||
@ -100,7 +101,7 @@ fn into_binary(
|
|||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
let head = call.head;
|
let head = call.head;
|
||||||
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||||
|
|
||||||
match input {
|
match input {
|
||||||
PipelineData::ExternalStream { stdout: None, .. } => Ok(Value::Binary {
|
PipelineData::ExternalStream { stdout: None, .. } => Ok(Value::Binary {
|
||||||
@ -120,27 +121,10 @@ fn into_binary(
|
|||||||
}
|
}
|
||||||
.into_pipeline_data())
|
.into_pipeline_data())
|
||||||
}
|
}
|
||||||
_ => input.map(
|
_ => {
|
||||||
move |v| {
|
let arg = CellPathOnlyArgs::from(cell_paths);
|
||||||
if column_paths.is_empty() {
|
operate(action, arg, input, call.head, engine_state.ctrlc.clone())
|
||||||
action(&v, head)
|
}
|
||||||
} else {
|
|
||||||
let mut ret = v;
|
|
||||||
for path in &column_paths {
|
|
||||||
let r = ret.update_cell_path(
|
|
||||||
&path.members,
|
|
||||||
Box::new(move |old| action(old, head)),
|
|
||||||
);
|
|
||||||
if let Err(error) = r {
|
|
||||||
return Value::Error { error };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
},
|
|
||||||
engine_state.ctrlc.clone(),
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,7 +144,7 @@ fn float_to_endian(n: f64) -> Vec<u8> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn action(input: &Value, span: Span) -> Value {
|
pub fn action(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
|
||||||
match input {
|
match input {
|
||||||
Value::Binary { .. } => input.clone(),
|
Value::Binary { .. } => input.clone(),
|
||||||
Value::Int { val, .. } => Value::Binary {
|
Value::Int { val, .. } => Value::Binary {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::input_handler::{operate, CellPathOnlyArgs};
|
||||||
use nu_engine::CallExt;
|
use nu_engine::CallExt;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{Call, CellPath},
|
ast::{Call, CellPath},
|
||||||
@ -108,28 +109,9 @@ fn into_bool(
|
|||||||
call: &Call,
|
call: &Call,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let head = call.head;
|
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||||
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
let args = CellPathOnlyArgs::from(cell_paths);
|
||||||
|
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||||
input.map(
|
|
||||||
move |v| {
|
|
||||||
if column_paths.is_empty() {
|
|
||||||
action(&v, head)
|
|
||||||
} else {
|
|
||||||
let mut ret = v;
|
|
||||||
for path in &column_paths {
|
|
||||||
let r =
|
|
||||||
ret.update_cell_path(&path.members, Box::new(move |old| action(old, head)));
|
|
||||||
if let Err(error) = r {
|
|
||||||
return Value::Error { error };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
},
|
|
||||||
engine_state.ctrlc.clone(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn string_to_boolean(s: &str, span: Span) -> Result<bool, ShellError> {
|
fn string_to_boolean(s: &str, span: Span) -> Result<bool, ShellError> {
|
||||||
@ -154,7 +136,7 @@ fn string_to_boolean(s: &str, span: Span) -> Result<bool, ShellError> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn action(input: &Value, span: Span) -> Value {
|
fn action(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
|
||||||
match input {
|
match input {
|
||||||
Value::Bool { .. } => input.clone(),
|
Value::Bool { .. } => input.clone(),
|
||||||
Value::Int { val, .. } => Value::Bool {
|
Value::Int { val, .. } => Value::Bool {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::input_handler::{operate, CmdArgument};
|
||||||
use crate::{generate_strftime_list, parse_date_from_string};
|
use crate::{generate_strftime_list, parse_date_from_string};
|
||||||
use chrono::{DateTime, FixedOffset, Local, TimeZone, Utc};
|
use chrono::{DateTime, FixedOffset, Local, TimeZone, Utc};
|
||||||
use nu_engine::CallExt;
|
use nu_engine::CallExt;
|
||||||
@ -5,14 +6,20 @@ use nu_protocol::ast::Call;
|
|||||||
use nu_protocol::ast::CellPath;
|
use nu_protocol::ast::CellPath;
|
||||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value,
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Spanned,
|
||||||
|
SyntaxShape, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
timezone: Option<Spanned<String>>,
|
zone_options: Option<Spanned<Zone>>,
|
||||||
offset: Option<Spanned<i64>>,
|
format_options: Option<DatetimeFormat>,
|
||||||
format: Option<String>,
|
cell_paths: Option<Vec<CellPath>>,
|
||||||
column_paths: Vec<CellPath>,
|
}
|
||||||
|
|
||||||
|
impl CmdArgument for Arguments {
|
||||||
|
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
|
||||||
|
self.cell_paths.take()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// In case it may be confused with chrono::TimeZone
|
// In case it may be confused with chrono::TimeZone
|
||||||
@ -95,7 +102,36 @@ impl Command for SubCommand {
|
|||||||
call: &Call,
|
call: &Call,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
operate(engine_state, stack, call, input)
|
if call.has_flag("list") {
|
||||||
|
Ok(generate_strftime_list(call.head, true).into_pipeline_data())
|
||||||
|
} else {
|
||||||
|
let cell_paths = call.rest(engine_state, stack, 0)?;
|
||||||
|
let cell_paths = (!cell_paths.is_empty()).then(|| cell_paths);
|
||||||
|
|
||||||
|
// if zone-offset is specified, then zone will be neglected
|
||||||
|
let timezone = call.get_flag::<Spanned<String>>(engine_state, stack, "timezone")?;
|
||||||
|
let zone_options =
|
||||||
|
match &call.get_flag::<Spanned<i64>>(engine_state, stack, "offset")? {
|
||||||
|
Some(zone_offset) => Some(Spanned {
|
||||||
|
item: Zone::new(zone_offset.item),
|
||||||
|
span: zone_offset.span,
|
||||||
|
}),
|
||||||
|
None => timezone.as_ref().map(|zone| Spanned {
|
||||||
|
item: Zone::from_string(zone.item.clone()),
|
||||||
|
span: zone.span,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
let format_options = call
|
||||||
|
.get_flag::<String>(engine_state, stack, "format")?
|
||||||
|
.as_ref()
|
||||||
|
.map(|fmt| DatetimeFormat(fmt.to_string()));
|
||||||
|
let args = Arguments {
|
||||||
|
format_options,
|
||||||
|
zone_options,
|
||||||
|
cell_paths,
|
||||||
|
};
|
||||||
|
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
@ -162,72 +198,9 @@ impl Command for SubCommand {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct DatetimeFormat(String);
|
struct DatetimeFormat(String);
|
||||||
|
|
||||||
fn operate(
|
fn action(input: &Value, args: &Arguments, head: Span) -> Value {
|
||||||
engine_state: &EngineState,
|
let timezone = &args.zone_options;
|
||||||
stack: &mut Stack,
|
let dateformat = &args.format_options;
|
||||||
call: &Call,
|
|
||||||
input: PipelineData,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
let head = call.head;
|
|
||||||
|
|
||||||
let options = Arguments {
|
|
||||||
timezone: call.get_flag(engine_state, stack, "timezone")?,
|
|
||||||
offset: call.get_flag(engine_state, stack, "offset")?,
|
|
||||||
format: call.get_flag(engine_state, stack, "format")?,
|
|
||||||
column_paths: call.rest(engine_state, stack, 0)?,
|
|
||||||
};
|
|
||||||
|
|
||||||
// if zone-offset is specified, then zone will be neglected
|
|
||||||
let zone_options = match &options.offset {
|
|
||||||
Some(zone_offset) => Some(Spanned {
|
|
||||||
item: Zone::new(zone_offset.item),
|
|
||||||
span: zone_offset.span,
|
|
||||||
}),
|
|
||||||
None => options.timezone.as_ref().map(|zone| Spanned {
|
|
||||||
item: Zone::from_string(zone.item.clone()),
|
|
||||||
span: zone.span,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
let list_flag = call.has_flag("list");
|
|
||||||
|
|
||||||
let format_options = options
|
|
||||||
.format
|
|
||||||
.as_ref()
|
|
||||||
.map(|fmt| DatetimeFormat(fmt.to_string()));
|
|
||||||
|
|
||||||
input.map(
|
|
||||||
move |v| {
|
|
||||||
if options.column_paths.is_empty() && !list_flag {
|
|
||||||
action(&v, &zone_options, &format_options, head)
|
|
||||||
} else if list_flag {
|
|
||||||
generate_strftime_list(head, true)
|
|
||||||
} else {
|
|
||||||
let mut ret = v;
|
|
||||||
for path in &options.column_paths {
|
|
||||||
let zone_options = zone_options.clone();
|
|
||||||
let format_options = format_options.clone();
|
|
||||||
let r = ret.update_cell_path(
|
|
||||||
&path.members,
|
|
||||||
Box::new(move |old| action(old, &zone_options, &format_options, head)),
|
|
||||||
);
|
|
||||||
if let Err(error) = r {
|
|
||||||
return Value::Error { error };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
},
|
|
||||||
engine_state.ctrlc.clone(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn action(
|
|
||||||
input: &Value,
|
|
||||||
timezone: &Option<Spanned<Zone>>,
|
|
||||||
dateformat: &Option<DatetimeFormat>,
|
|
||||||
head: Span,
|
|
||||||
) -> Value {
|
|
||||||
// Check to see if input looks like a Unix timestamp (i.e. can it be parsed to an int?)
|
// Check to see if input looks like a Unix timestamp (i.e. can it be parsed to an int?)
|
||||||
let timestamp = match input {
|
let timestamp = match input {
|
||||||
Value::Int { val, .. } => Ok(*val),
|
Value::Int { val, .. } => Ok(*val),
|
||||||
@ -359,7 +332,12 @@ mod tests {
|
|||||||
fn takes_a_date_format() {
|
fn takes_a_date_format() {
|
||||||
let date_str = Value::test_string("16.11.1984 8:00 am +0000");
|
let date_str = Value::test_string("16.11.1984 8:00 am +0000");
|
||||||
let fmt_options = Some(DatetimeFormat("%d.%m.%Y %H:%M %P %z".to_string()));
|
let fmt_options = Some(DatetimeFormat("%d.%m.%Y %H:%M %P %z".to_string()));
|
||||||
let actual = action(&date_str, &None, &fmt_options, Span::test_data());
|
let args = Arguments {
|
||||||
|
zone_options: None,
|
||||||
|
format_options: fmt_options,
|
||||||
|
cell_paths: None,
|
||||||
|
};
|
||||||
|
let actual = action(&date_str, &args, Span::test_data());
|
||||||
let expected = Value::Date {
|
let expected = Value::Date {
|
||||||
val: DateTime::parse_from_str("16.11.1984 8:00 am +0000", "%d.%m.%Y %H:%M %P %z")
|
val: DateTime::parse_from_str("16.11.1984 8:00 am +0000", "%d.%m.%Y %H:%M %P %z")
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
@ -371,7 +349,12 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn takes_iso8601_date_format() {
|
fn takes_iso8601_date_format() {
|
||||||
let date_str = Value::test_string("2020-08-04T16:39:18+00:00");
|
let date_str = Value::test_string("2020-08-04T16:39:18+00:00");
|
||||||
let actual = action(&date_str, &None, &None, Span::test_data());
|
let args = Arguments {
|
||||||
|
zone_options: None,
|
||||||
|
format_options: None,
|
||||||
|
cell_paths: None,
|
||||||
|
};
|
||||||
|
let actual = action(&date_str, &args, Span::test_data());
|
||||||
let expected = Value::Date {
|
let expected = Value::Date {
|
||||||
val: DateTime::parse_from_str("2020-08-04T16:39:18+00:00", "%Y-%m-%dT%H:%M:%S%z")
|
val: DateTime::parse_from_str("2020-08-04T16:39:18+00:00", "%Y-%m-%dT%H:%M:%S%z")
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
@ -387,7 +370,12 @@ mod tests {
|
|||||||
item: Zone::East(8),
|
item: Zone::East(8),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
});
|
});
|
||||||
let actual = action(&date_str, &timezone_option, &None, Span::test_data());
|
let args = Arguments {
|
||||||
|
zone_options: timezone_option,
|
||||||
|
format_options: None,
|
||||||
|
cell_paths: None,
|
||||||
|
};
|
||||||
|
let actual = action(&date_str, &args, Span::test_data());
|
||||||
let expected = Value::Date {
|
let expected = Value::Date {
|
||||||
val: DateTime::parse_from_str("2021-02-27 21:55:40 +08:00", "%Y-%m-%d %H:%M:%S %z")
|
val: DateTime::parse_from_str("2021-02-27 21:55:40 +08:00", "%Y-%m-%d %H:%M:%S %z")
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
@ -404,7 +392,12 @@ mod tests {
|
|||||||
item: Zone::East(8),
|
item: Zone::East(8),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
});
|
});
|
||||||
let actual = action(&date_int, &timezone_option, &None, Span::test_data());
|
let args = Arguments {
|
||||||
|
zone_options: timezone_option,
|
||||||
|
format_options: None,
|
||||||
|
cell_paths: None,
|
||||||
|
};
|
||||||
|
let actual = action(&date_int, &args, Span::test_data());
|
||||||
let expected = Value::Date {
|
let expected = Value::Date {
|
||||||
val: DateTime::parse_from_str("2021-02-27 21:55:40 +08:00", "%Y-%m-%d %H:%M:%S %z")
|
val: DateTime::parse_from_str("2021-02-27 21:55:40 +08:00", "%Y-%m-%d %H:%M:%S %z")
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
@ -421,7 +414,12 @@ mod tests {
|
|||||||
item: Zone::Local,
|
item: Zone::Local,
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
});
|
});
|
||||||
let actual = action(&date_str, &timezone_option, &None, Span::test_data());
|
let args = Arguments {
|
||||||
|
zone_options: timezone_option,
|
||||||
|
format_options: None,
|
||||||
|
cell_paths: None,
|
||||||
|
};
|
||||||
|
let actual = action(&date_str, &args, Span::test_data());
|
||||||
let expected = Value::Date {
|
let expected = Value::Date {
|
||||||
val: Local.timestamp(1614434140, 0).into(),
|
val: Local.timestamp(1614434140, 0).into(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
@ -433,8 +431,12 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn takes_timestamp_without_timezone() {
|
fn takes_timestamp_without_timezone() {
|
||||||
let date_str = Value::test_string("1614434140");
|
let date_str = Value::test_string("1614434140");
|
||||||
let timezone_option = None;
|
let args = Arguments {
|
||||||
let actual = action(&date_str, &timezone_option, &None, Span::test_data());
|
zone_options: None,
|
||||||
|
format_options: None,
|
||||||
|
cell_paths: None,
|
||||||
|
};
|
||||||
|
let actual = action(&date_str, &args, Span::test_data());
|
||||||
|
|
||||||
let expected = Value::Date {
|
let expected = Value::Date {
|
||||||
val: Utc.timestamp(1614434140, 0).into(),
|
val: Utc.timestamp(1614434140, 0).into(),
|
||||||
@ -451,7 +453,12 @@ mod tests {
|
|||||||
item: Zone::Utc,
|
item: Zone::Utc,
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
});
|
});
|
||||||
let actual = action(&date_str, &timezone_option, &None, Span::test_data());
|
let args = Arguments {
|
||||||
|
zone_options: timezone_option,
|
||||||
|
format_options: None,
|
||||||
|
cell_paths: None,
|
||||||
|
};
|
||||||
|
let actual = action(&date_str, &args, Span::test_data());
|
||||||
|
|
||||||
assert_eq!(actual.get_type(), Error);
|
assert_eq!(actual.get_type(), Error);
|
||||||
}
|
}
|
||||||
@ -460,7 +467,12 @@ mod tests {
|
|||||||
fn communicates_parsing_error_given_an_invalid_datetimelike_string() {
|
fn communicates_parsing_error_given_an_invalid_datetimelike_string() {
|
||||||
let date_str = Value::test_string("16.11.1984 8:00 am Oops0000");
|
let date_str = Value::test_string("16.11.1984 8:00 am Oops0000");
|
||||||
let fmt_options = Some(DatetimeFormat("%d.%m.%Y %H:%M %P %z".to_string()));
|
let fmt_options = Some(DatetimeFormat("%d.%m.%Y %H:%M %P %z".to_string()));
|
||||||
let actual = action(&date_str, &None, &fmt_options, Span::test_data());
|
let args = Arguments {
|
||||||
|
zone_options: None,
|
||||||
|
format_options: fmt_options,
|
||||||
|
cell_paths: None,
|
||||||
|
};
|
||||||
|
let actual = action(&date_str, &args, Span::test_data());
|
||||||
|
|
||||||
assert_eq!(actual.get_type(), Error);
|
assert_eq!(actual.get_type(), Error);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::input_handler::{operate, CellPathOnlyArgs};
|
||||||
use nu_engine::CallExt;
|
use nu_engine::CallExt;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{Call, CellPath},
|
ast::{Call, CellPath},
|
||||||
@ -36,7 +37,9 @@ impl Command for SubCommand {
|
|||||||
call: &Call,
|
call: &Call,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
operate(engine_state, stack, call, input)
|
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||||
|
let args = CellPathOnlyArgs::from(cell_paths);
|
||||||
|
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
@ -72,37 +75,7 @@ impl Command for SubCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn operate(
|
fn action(input: &Value, _args: &CellPathOnlyArgs, head: Span) -> Value {
|
||||||
engine_state: &EngineState,
|
|
||||||
stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
input: PipelineData,
|
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
|
||||||
let head = call.head;
|
|
||||||
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
|
||||||
|
|
||||||
input.map(
|
|
||||||
move |v| {
|
|
||||||
if column_paths.is_empty() {
|
|
||||||
action(&v, head)
|
|
||||||
} else {
|
|
||||||
let mut ret = v;
|
|
||||||
for path in &column_paths {
|
|
||||||
let r =
|
|
||||||
ret.update_cell_path(&path.members, Box::new(move |old| action(old, head)));
|
|
||||||
if let Err(error) = r {
|
|
||||||
return Value::Error { error };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
},
|
|
||||||
engine_state.ctrlc.clone(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn action(input: &Value, head: Span) -> Value {
|
|
||||||
match input {
|
match input {
|
||||||
Value::String { val: s, span } => {
|
Value::String { val: s, span } => {
|
||||||
let other = s.trim();
|
let other = s.trim();
|
||||||
@ -163,7 +136,7 @@ mod tests {
|
|||||||
let word = Value::test_string("3.1415");
|
let word = Value::test_string("3.1415");
|
||||||
let expected = Value::test_float(3.1415);
|
let expected = Value::test_float(3.1415);
|
||||||
|
|
||||||
let actual = action(&word, Span::test_data());
|
let actual = action(&word, &CellPathOnlyArgs::from(vec![]), Span::test_data());
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +144,11 @@ mod tests {
|
|||||||
fn communicates_parsing_error_given_an_invalid_decimallike_string() {
|
fn communicates_parsing_error_given_an_invalid_decimallike_string() {
|
||||||
let decimal_str = Value::test_string("11.6anra");
|
let decimal_str = Value::test_string("11.6anra");
|
||||||
|
|
||||||
let actual = action(&decimal_str, Span::test_data());
|
let actual = action(
|
||||||
|
&decimal_str,
|
||||||
|
&CellPathOnlyArgs::from(vec![]),
|
||||||
|
Span::test_data(),
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(actual.get_type(), Error);
|
assert_eq!(actual.get_type(), Error);
|
||||||
}
|
}
|
||||||
@ -180,7 +157,11 @@ mod tests {
|
|||||||
fn int_to_decimal() {
|
fn int_to_decimal() {
|
||||||
let decimal_str = Value::test_int(10);
|
let decimal_str = Value::test_int(10);
|
||||||
let expected = Value::test_float(10.0);
|
let expected = Value::test_float(10.0);
|
||||||
let actual = action(&decimal_str, Span::test_data());
|
let actual = action(
|
||||||
|
&decimal_str,
|
||||||
|
&CellPathOnlyArgs::from(vec![]),
|
||||||
|
Span::test_data(),
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::input_handler::{operate, CellPathOnlyArgs};
|
||||||
use nu_engine::CallExt;
|
use nu_engine::CallExt;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{Call, CellPath},
|
ast::{Call, CellPath},
|
||||||
@ -38,7 +39,9 @@ impl Command for SubCommand {
|
|||||||
call: &Call,
|
call: &Call,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
into_filesize(engine_state, stack, call, input)
|
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||||
|
let args = CellPathOnlyArgs::from(cell_paths);
|
||||||
|
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
@ -84,37 +87,7 @@ impl Command for SubCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_filesize(
|
pub fn action(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
|
||||||
engine_state: &EngineState,
|
|
||||||
stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
input: PipelineData,
|
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
|
||||||
let head = call.head;
|
|
||||||
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
|
||||||
|
|
||||||
input.map(
|
|
||||||
move |v| {
|
|
||||||
if column_paths.is_empty() {
|
|
||||||
action(&v, head)
|
|
||||||
} else {
|
|
||||||
let mut ret = v;
|
|
||||||
for path in &column_paths {
|
|
||||||
let r =
|
|
||||||
ret.update_cell_path(&path.members, Box::new(move |old| action(old, head)));
|
|
||||||
if let Err(error) = r {
|
|
||||||
return Value::Error { error };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
},
|
|
||||||
engine_state.ctrlc.clone(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn action(input: &Value, span: Span) -> Value {
|
|
||||||
if let Ok(value_span) = input.span() {
|
if let Ok(value_span) = input.span() {
|
||||||
match input {
|
match input {
|
||||||
Value::Filesize { .. } => input.clone(),
|
Value::Filesize { .. } => input.clone(),
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::input_handler::{operate, CmdArgument};
|
||||||
use nu_engine::CallExt;
|
use nu_engine::CallExt;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{Call, CellPath},
|
ast::{Call, CellPath},
|
||||||
@ -6,11 +7,17 @@ use nu_protocol::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
radix: Option<Value>,
|
radix: u32,
|
||||||
column_paths: Vec<CellPath>,
|
cell_paths: Option<Vec<CellPath>>,
|
||||||
little_endian: bool,
|
little_endian: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CmdArgument for Arguments {
|
||||||
|
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
|
||||||
|
self.cell_paths.take()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
|
|
||||||
@ -46,7 +53,29 @@ impl Command for SubCommand {
|
|||||||
call: &Call,
|
call: &Call,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
into_int(engine_state, stack, call, input)
|
let cell_paths = call.rest(engine_state, stack, 0)?;
|
||||||
|
let cell_paths = (!cell_paths.is_empty()).then(|| cell_paths);
|
||||||
|
|
||||||
|
let radix = call.get_flag::<Value>(engine_state, stack, "radix")?;
|
||||||
|
let radix: u32 = match radix {
|
||||||
|
Some(Value::Int { val, span }) => {
|
||||||
|
if !(2..=36).contains(&val) {
|
||||||
|
return Err(ShellError::UnsupportedInput(
|
||||||
|
"Radix must lie in the range [2, 36]".to_string(),
|
||||||
|
span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
val as u32
|
||||||
|
}
|
||||||
|
Some(_) => 10,
|
||||||
|
None => 10,
|
||||||
|
};
|
||||||
|
let args = Arguments {
|
||||||
|
radix,
|
||||||
|
little_endian: call.has_flag("little-endian"),
|
||||||
|
cell_paths,
|
||||||
|
};
|
||||||
|
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
@ -121,59 +150,9 @@ impl Command for SubCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_int(
|
fn action(input: &Value, args: &Arguments, span: Span) -> Value {
|
||||||
engine_state: &EngineState,
|
let radix = args.radix;
|
||||||
stack: &mut Stack,
|
let little_endian = args.little_endian;
|
||||||
call: &Call,
|
|
||||||
input: PipelineData,
|
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
|
||||||
let head = call.head;
|
|
||||||
|
|
||||||
let options = Arguments {
|
|
||||||
radix: call.get_flag(engine_state, stack, "radix")?,
|
|
||||||
little_endian: call.has_flag("little-endian"),
|
|
||||||
column_paths: call.rest(engine_state, stack, 0)?,
|
|
||||||
};
|
|
||||||
|
|
||||||
let radix: u32 = match options.radix {
|
|
||||||
Some(Value::Int { val, .. }) => val as u32,
|
|
||||||
Some(_) => 10,
|
|
||||||
None => 10,
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(val) = &options.radix {
|
|
||||||
if !(2..=36).contains(&radix) {
|
|
||||||
return Err(ShellError::UnsupportedInput(
|
|
||||||
"Radix must lie in the range [2, 36]".to_string(),
|
|
||||||
val.span()?,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
input.map(
|
|
||||||
move |v| {
|
|
||||||
if options.column_paths.is_empty() {
|
|
||||||
action(&v, head, radix, options.little_endian)
|
|
||||||
} else {
|
|
||||||
let mut ret = v;
|
|
||||||
for path in &options.column_paths {
|
|
||||||
let r = ret.update_cell_path(
|
|
||||||
&path.members,
|
|
||||||
Box::new(move |old| action(old, head, radix, options.little_endian)),
|
|
||||||
);
|
|
||||||
if let Err(error) = r {
|
|
||||||
return Value::Error { error };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
},
|
|
||||||
engine_state.ctrlc.clone(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn action(input: &Value, span: Span, radix: u32, little_endian: bool) -> Value {
|
|
||||||
match input {
|
match input {
|
||||||
Value::Int { val: _, .. } => {
|
Value::Int { val: _, .. } => {
|
||||||
if radix == 10 {
|
if radix == 10 {
|
||||||
@ -401,21 +380,45 @@ mod test {
|
|||||||
let word = Value::test_string("10");
|
let word = Value::test_string("10");
|
||||||
let expected = Value::test_int(10);
|
let expected = Value::test_int(10);
|
||||||
|
|
||||||
let actual = action(&word, Span::test_data(), 10, false);
|
let actual = action(
|
||||||
|
&word,
|
||||||
|
&Arguments {
|
||||||
|
radix: 10,
|
||||||
|
cell_paths: None,
|
||||||
|
little_endian: false,
|
||||||
|
},
|
||||||
|
Span::test_data(),
|
||||||
|
);
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn turns_binary_to_integer() {
|
fn turns_binary_to_integer() {
|
||||||
let s = Value::test_string("0b101");
|
let s = Value::test_string("0b101");
|
||||||
let actual = action(&s, Span::test_data(), 10, false);
|
let actual = action(
|
||||||
|
&s,
|
||||||
|
&Arguments {
|
||||||
|
radix: 10,
|
||||||
|
cell_paths: None,
|
||||||
|
little_endian: false,
|
||||||
|
},
|
||||||
|
Span::test_data(),
|
||||||
|
);
|
||||||
assert_eq!(actual, Value::test_int(5));
|
assert_eq!(actual, Value::test_int(5));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn turns_hex_to_integer() {
|
fn turns_hex_to_integer() {
|
||||||
let s = Value::test_string("0xFF");
|
let s = Value::test_string("0xFF");
|
||||||
let actual = action(&s, Span::test_data(), 16, false);
|
let actual = action(
|
||||||
|
&s,
|
||||||
|
&Arguments {
|
||||||
|
radix: 16,
|
||||||
|
cell_paths: None,
|
||||||
|
little_endian: false,
|
||||||
|
},
|
||||||
|
Span::test_data(),
|
||||||
|
);
|
||||||
assert_eq!(actual, Value::test_int(255));
|
assert_eq!(actual, Value::test_int(255));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -423,7 +426,15 @@ mod test {
|
|||||||
fn communicates_parsing_error_given_an_invalid_integerlike_string() {
|
fn communicates_parsing_error_given_an_invalid_integerlike_string() {
|
||||||
let integer_str = Value::test_string("36anra");
|
let integer_str = Value::test_string("36anra");
|
||||||
|
|
||||||
let actual = action(&integer_str, Span::test_data(), 10, false);
|
let actual = action(
|
||||||
|
&integer_str,
|
||||||
|
&Arguments {
|
||||||
|
radix: 10,
|
||||||
|
cell_paths: None,
|
||||||
|
little_endian: false,
|
||||||
|
},
|
||||||
|
Span::test_data(),
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(actual.get_type(), Error)
|
assert_eq!(actual.get_type(), Error)
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::input_handler::{operate, CmdArgument};
|
||||||
use nu_engine::CallExt;
|
use nu_engine::CallExt;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{Call, CellPath},
|
ast::{Call, CellPath},
|
||||||
@ -8,6 +9,19 @@ use nu_protocol::{
|
|||||||
use nu_utils::get_system_locale;
|
use nu_utils::get_system_locale;
|
||||||
use num_format::ToFormattedString;
|
use num_format::ToFormattedString;
|
||||||
|
|
||||||
|
struct Arguments {
|
||||||
|
decimals_value: Option<i64>,
|
||||||
|
decimals: bool,
|
||||||
|
cell_paths: Option<Vec<CellPath>>,
|
||||||
|
config: Config,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CmdArgument for Arguments {
|
||||||
|
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
|
||||||
|
self.cell_paths.take()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
|
|
||||||
@ -149,9 +163,6 @@ fn string_helper(
|
|||||||
let decimals = call.has_flag("decimals");
|
let decimals = call.has_flag("decimals");
|
||||||
let head = call.head;
|
let head = call.head;
|
||||||
let decimals_value: Option<i64> = call.get_flag(engine_state, stack, "decimals")?;
|
let decimals_value: Option<i64> = call.get_flag(engine_state, stack, "decimals")?;
|
||||||
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
|
||||||
let config = engine_state.get_config().clone();
|
|
||||||
|
|
||||||
if let Some(decimal_val) = decimals_value {
|
if let Some(decimal_val) = decimals_value {
|
||||||
if decimals && decimal_val.is_negative() {
|
if decimals && decimal_val.is_negative() {
|
||||||
return Err(ShellError::UnsupportedInput(
|
return Err(ShellError::UnsupportedInput(
|
||||||
@ -160,6 +171,15 @@ fn string_helper(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let cell_paths = call.rest(engine_state, stack, 0)?;
|
||||||
|
let cell_paths = (!cell_paths.is_empty()).then(|| cell_paths);
|
||||||
|
let config = engine_state.get_config().clone();
|
||||||
|
let args = Arguments {
|
||||||
|
decimals_value,
|
||||||
|
decimals,
|
||||||
|
cell_paths,
|
||||||
|
config,
|
||||||
|
};
|
||||||
|
|
||||||
match input {
|
match input {
|
||||||
PipelineData::ExternalStream { stdout: None, .. } => Ok(Value::String {
|
PipelineData::ExternalStream { stdout: None, .. } => Ok(Value::String {
|
||||||
@ -179,45 +199,18 @@ fn string_helper(
|
|||||||
}
|
}
|
||||||
.into_pipeline_data())
|
.into_pipeline_data())
|
||||||
}
|
}
|
||||||
_ => input.map(
|
_ => operate(action, args, input, head, engine_state.ctrlc.clone()),
|
||||||
move |v| {
|
|
||||||
if column_paths.is_empty() {
|
|
||||||
action(&v, head, decimals, decimals_value, false, &config)
|
|
||||||
} else {
|
|
||||||
let mut ret = v;
|
|
||||||
for path in &column_paths {
|
|
||||||
let config = config.clone();
|
|
||||||
let r = ret.update_cell_path(
|
|
||||||
&path.members,
|
|
||||||
Box::new(move |old| {
|
|
||||||
action(old, head, decimals, decimals_value, false, &config)
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
if let Err(error) = r {
|
|
||||||
return Value::Error { error };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
},
|
|
||||||
engine_state.ctrlc.clone(),
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn action(
|
fn action(input: &Value, args: &Arguments, span: Span) -> Value {
|
||||||
input: &Value,
|
let decimals = args.decimals;
|
||||||
span: Span,
|
let digits = args.decimals_value;
|
||||||
decimals: bool,
|
let config = &args.config;
|
||||||
digits: Option<i64>,
|
|
||||||
group_digits: bool,
|
|
||||||
config: &Config,
|
|
||||||
) -> Value {
|
|
||||||
match input {
|
match input {
|
||||||
Value::Int { val, .. } => {
|
Value::Int { val, .. } => {
|
||||||
let decimal_value = digits.unwrap_or(0) as usize;
|
let decimal_value = digits.unwrap_or(0) as usize;
|
||||||
let res = format_int(*val, group_digits, decimal_value);
|
let res = format_int(*val, false, decimal_value);
|
||||||
Value::String { val: res, span }
|
Value::String { val: res, span }
|
||||||
}
|
}
|
||||||
Value::Float { val, .. } => {
|
Value::Float { val, .. } => {
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
use crate::input_handler::{operate, CmdArgument};
|
||||||
use nu_engine::CallExt;
|
use nu_engine::CallExt;
|
||||||
use nu_protocol::ast::{Call, CellPath};
|
use nu_protocol::ast::{Call, CellPath};
|
||||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::Span;
|
||||||
use nu_protocol::{Example, PipelineData, ShellError, Signature, SyntaxShape, Value};
|
use nu_protocol::{Example, PipelineData, ShellError, Signature, SyntaxShape, Value};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
@ -26,6 +28,17 @@ impl<D: HashDigest> Default for GenericDigest<D> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) struct Arguments {
|
||||||
|
pub(super) cell_paths: Option<Vec<CellPath>>,
|
||||||
|
pub(super) binary: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CmdArgument for Arguments {
|
||||||
|
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
|
||||||
|
self.cell_paths.take()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<D> Command for GenericDigest<D>
|
impl<D> Command for GenericDigest<D>
|
||||||
where
|
where
|
||||||
D: HashDigest + Send + Sync + 'static,
|
D: HashDigest + Send + Sync + 'static,
|
||||||
@ -66,31 +79,19 @@ where
|
|||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
let binary = call.has_flag("binary");
|
let binary = call.has_flag("binary");
|
||||||
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||||
|
let cell_paths = (!cell_paths.is_empty()).then(|| cell_paths);
|
||||||
input.map(
|
let args = Arguments { binary, cell_paths };
|
||||||
move |v| {
|
operate(
|
||||||
if cell_paths.is_empty() {
|
action::<D>,
|
||||||
action::<D>(binary, &v)
|
args,
|
||||||
} else {
|
input,
|
||||||
let mut v = v;
|
call.head,
|
||||||
for path in &cell_paths {
|
|
||||||
let ret = v.update_cell_path(
|
|
||||||
&path.members,
|
|
||||||
Box::new(move |old| action::<D>(binary, old)),
|
|
||||||
);
|
|
||||||
if let Err(error) = ret {
|
|
||||||
return Value::Error { error };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
v
|
|
||||||
}
|
|
||||||
},
|
|
||||||
engine_state.ctrlc.clone(),
|
engine_state.ctrlc.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn action<D>(binary: bool, input: &Value) -> Value
|
pub(super) fn action<D>(input: &Value, args: &Arguments, _span: Span) -> Value
|
||||||
where
|
where
|
||||||
D: HashDigest,
|
D: HashDigest,
|
||||||
digest::Output<D>: core::fmt::LowerHex,
|
digest::Output<D>: core::fmt::LowerHex,
|
||||||
@ -119,7 +120,7 @@ where
|
|||||||
|
|
||||||
let digest = D::digest(bytes);
|
let digest = D::digest(bytes);
|
||||||
|
|
||||||
if binary {
|
if args.binary {
|
||||||
Value::Binary {
|
Value::Binary {
|
||||||
val: digest.to_vec(),
|
val: digest.to_vec(),
|
||||||
span,
|
span,
|
||||||
|
@ -42,7 +42,7 @@ impl HashDigest for Md5 {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::hash::generic_digest;
|
use crate::hash::generic_digest::{self, Arguments};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_examples() {
|
fn test_examples() {
|
||||||
@ -59,7 +59,14 @@ mod tests {
|
|||||||
val: "c3fcd3d76192e4007dfb496cca67e13b".to_owned(),
|
val: "c3fcd3d76192e4007dfb496cca67e13b".to_owned(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
};
|
};
|
||||||
let actual = generic_digest::action::<Md5>(false, &binary);
|
let actual = generic_digest::action::<Md5>(
|
||||||
|
&binary,
|
||||||
|
&Arguments {
|
||||||
|
cell_paths: None,
|
||||||
|
binary: false,
|
||||||
|
},
|
||||||
|
Span::test_data(),
|
||||||
|
);
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +80,14 @@ mod tests {
|
|||||||
val: "5f80e231382769b0102b1164cf722d83".to_owned(),
|
val: "5f80e231382769b0102b1164cf722d83".to_owned(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
};
|
};
|
||||||
let actual = generic_digest::action::<Md5>(false, &binary);
|
let actual = generic_digest::action::<Md5>(
|
||||||
|
&binary,
|
||||||
|
&Arguments {
|
||||||
|
cell_paths: None,
|
||||||
|
binary: false,
|
||||||
|
},
|
||||||
|
Span::test_data(),
|
||||||
|
);
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ impl HashDigest for Sha256 {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::hash::generic_digest;
|
use crate::hash::generic_digest::{self, Arguments};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_examples() {
|
fn test_examples() {
|
||||||
@ -61,7 +61,14 @@ mod tests {
|
|||||||
val: "71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73".to_owned(),
|
val: "71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73".to_owned(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
};
|
};
|
||||||
let actual = generic_digest::action::<Sha256>(false, &binary);
|
let actual = generic_digest::action::<Sha256>(
|
||||||
|
&binary,
|
||||||
|
&Arguments {
|
||||||
|
cell_paths: None,
|
||||||
|
binary: false,
|
||||||
|
},
|
||||||
|
Span::test_data(),
|
||||||
|
);
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +82,14 @@ mod tests {
|
|||||||
val: "c47a10dc272b1221f0380a2ae0f7d7fa830b3e378f2f5309bbf13f61ad211913".to_owned(),
|
val: "c47a10dc272b1221f0380a2ae0f7d7fa830b3e378f2f5309bbf13f61ad211913".to_owned(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
};
|
};
|
||||||
let actual = generic_digest::action::<Sha256>(false, &binary);
|
let actual = generic_digest::action::<Sha256>(
|
||||||
|
&binary,
|
||||||
|
&Arguments {
|
||||||
|
cell_paths: None,
|
||||||
|
binary: false,
|
||||||
|
},
|
||||||
|
Span::test_data(),
|
||||||
|
);
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,28 @@ pub trait CmdArgument {
|
|||||||
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>>;
|
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Arguments with only cell_path.
|
||||||
|
///
|
||||||
|
/// If commands is going to use `operate` function, and it only required optional cell_paths
|
||||||
|
/// Using this to simplify code.
|
||||||
|
pub struct CellPathOnlyArgs {
|
||||||
|
cell_paths: Option<Vec<CellPath>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CmdArgument for CellPathOnlyArgs {
|
||||||
|
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
|
||||||
|
self.cell_paths.take()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<CellPath>> for CellPathOnlyArgs {
|
||||||
|
fn from(cell_paths: Vec<CellPath>) -> Self {
|
||||||
|
Self {
|
||||||
|
cell_paths: (!cell_paths.is_empty()).then(|| cell_paths),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A simple wrapper for `PipelineData::map` method.
|
/// A simple wrapper for `PipelineData::map` method.
|
||||||
///
|
///
|
||||||
/// In detail, for each elements, invoking relative `cmd` with `arg`.
|
/// In detail, for each elements, invoking relative `cmd` with `arg`.
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::input_handler::{operate as general_operate, CmdArgument};
|
||||||
use base64::{decode_config, encode_config};
|
use base64::{decode_config, encode_config};
|
||||||
use nu_engine::CallExt;
|
use nu_engine::CallExt;
|
||||||
use nu_protocol::ast::{Call, CellPath};
|
use nu_protocol::ast::{Call, CellPath};
|
||||||
@ -20,6 +21,18 @@ pub enum ActionType {
|
|||||||
Decode,
|
Decode,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Arguments {
|
||||||
|
cell_paths: Option<Vec<CellPath>>,
|
||||||
|
binary: bool,
|
||||||
|
encoding_config: Base64Config,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CmdArgument for Arguments {
|
||||||
|
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
|
||||||
|
self.cell_paths.take()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn operate(
|
pub fn operate(
|
||||||
action_type: ActionType,
|
action_type: ActionType,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
@ -31,7 +44,8 @@ pub fn operate(
|
|||||||
let character_set: Option<Spanned<String>> =
|
let character_set: Option<Spanned<String>> =
|
||||||
call.get_flag(engine_state, stack, "character-set")?;
|
call.get_flag(engine_state, stack, "character-set")?;
|
||||||
let binary = call.has_flag("binary");
|
let binary = call.has_flag("binary");
|
||||||
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||||
|
let cell_paths = (!cell_paths.is_empty()).then(|| cell_paths);
|
||||||
|
|
||||||
// Default the character set to standard if the argument is not specified.
|
// Default the character set to standard if the argument is not specified.
|
||||||
let character_set = match character_set {
|
let character_set = match character_set {
|
||||||
@ -42,50 +56,27 @@ pub fn operate(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let encoding_config = Base64Config {
|
let args = Arguments {
|
||||||
character_set,
|
encoding_config: Base64Config {
|
||||||
action_type,
|
character_set,
|
||||||
|
action_type,
|
||||||
|
},
|
||||||
|
binary,
|
||||||
|
cell_paths,
|
||||||
};
|
};
|
||||||
|
|
||||||
input.map(
|
general_operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||||
move |v| {
|
|
||||||
if column_paths.is_empty() {
|
|
||||||
match action(&v, binary, &encoding_config, &head) {
|
|
||||||
Ok(v) => v,
|
|
||||||
Err(e) => Value::Error { error: e },
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let mut ret = v;
|
|
||||||
|
|
||||||
for path in &column_paths {
|
|
||||||
let config = encoding_config.clone();
|
|
||||||
|
|
||||||
let r = ret.update_cell_path(
|
|
||||||
&path.members,
|
|
||||||
Box::new(move |old| match action(old, binary, &config, &head) {
|
|
||||||
Ok(v) => v,
|
|
||||||
Err(e) => Value::Error { error: e },
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
if let Err(error) = r {
|
|
||||||
return Value::Error { error };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
},
|
|
||||||
engine_state.ctrlc.clone(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn action(
|
fn action(
|
||||||
input: &Value,
|
input: &Value,
|
||||||
// only used for `decode` action
|
// only used for `decode` action
|
||||||
output_binary: bool,
|
args: &Arguments,
|
||||||
base64_config: &Base64Config,
|
command_span: Span,
|
||||||
command_span: &Span,
|
) -> Value {
|
||||||
) -> Result<Value, ShellError> {
|
let base64_config = &args.encoding_config;
|
||||||
|
let output_binary = args.binary;
|
||||||
|
|
||||||
let config_character_set = &base64_config.character_set;
|
let config_character_set = &base64_config.character_set;
|
||||||
let base64_config_enum: base64::Config = match config_character_set.item.as_str() {
|
let base64_config_enum: base64::Config = match config_character_set.item.as_str() {
|
||||||
"standard" => base64::STANDARD,
|
"standard" => base64::STANDARD,
|
||||||
@ -95,7 +86,7 @@ fn action(
|
|||||||
"binhex" => base64::BINHEX,
|
"binhex" => base64::BINHEX,
|
||||||
"bcrypt" => base64::BCRYPT,
|
"bcrypt" => base64::BCRYPT,
|
||||||
"crypt" => base64::CRYPT,
|
"crypt" => base64::CRYPT,
|
||||||
not_valid => return Err(ShellError::GenericError(
|
not_valid => return Value::Error { error:ShellError::GenericError(
|
||||||
"value is not an accepted character set".to_string(),
|
"value is not an accepted character set".to_string(),
|
||||||
format!(
|
format!(
|
||||||
"{} is not a valid character-set.\nPlease use `help hash base64` to see a list of valid character sets.",
|
"{} is not a valid character-set.\nPlease use `help hash base64` to see a list of valid character sets.",
|
||||||
@ -104,28 +95,28 @@ fn action(
|
|||||||
Some(config_character_set.span),
|
Some(config_character_set.span),
|
||||||
None,
|
None,
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
))
|
)}
|
||||||
};
|
};
|
||||||
match input {
|
match input {
|
||||||
Value::Binary { val, .. } => match base64_config.action_type {
|
Value::Binary { val, .. } => match base64_config.action_type {
|
||||||
ActionType::Encode => Ok(Value::string(
|
ActionType::Encode => {
|
||||||
encode_config(&val, base64_config_enum),
|
Value::string(encode_config(&val, base64_config_enum), command_span)
|
||||||
*command_span,
|
}
|
||||||
)),
|
ActionType::Decode => Value::Error {
|
||||||
ActionType::Decode => Err(ShellError::UnsupportedInput(
|
error: ShellError::UnsupportedInput(
|
||||||
"Binary data can only support encoding".to_string(),
|
"Binary data can only support encoding".to_string(),
|
||||||
*command_span,
|
command_span,
|
||||||
)),
|
),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Value::String {
|
Value::String {
|
||||||
val,
|
val,
|
||||||
span: value_span,
|
span: value_span,
|
||||||
} => {
|
} => {
|
||||||
match base64_config.action_type {
|
match base64_config.action_type {
|
||||||
ActionType::Encode => Ok(Value::string(
|
ActionType::Encode => {
|
||||||
encode_config(&val, base64_config_enum),
|
Value::string(encode_config(&val, base64_config_enum), command_span)
|
||||||
*command_span,
|
}
|
||||||
)),
|
|
||||||
|
|
||||||
ActionType::Decode => {
|
ActionType::Decode => {
|
||||||
// for decode, input val may contains invalid new line character, which is ok to omitted them by default.
|
// for decode, input val may contains invalid new line character, which is ok to omitted them by default.
|
||||||
@ -135,46 +126,51 @@ fn action(
|
|||||||
match decode_config(&val, base64_config_enum) {
|
match decode_config(&val, base64_config_enum) {
|
||||||
Ok(decoded_value) => {
|
Ok(decoded_value) => {
|
||||||
if output_binary {
|
if output_binary {
|
||||||
Ok(Value::binary(decoded_value, *command_span))
|
Value::binary(decoded_value, command_span)
|
||||||
} else {
|
} else {
|
||||||
match String::from_utf8(decoded_value) {
|
match String::from_utf8(decoded_value) {
|
||||||
Ok(string_value) => {
|
Ok(string_value) => Value::string(string_value, command_span),
|
||||||
Ok(Value::string(string_value, *command_span))
|
Err(e) => Value::Error {
|
||||||
}
|
error: ShellError::GenericError(
|
||||||
Err(e) => Err(ShellError::GenericError(
|
"base64 payload isn't a valid utf-8 sequence"
|
||||||
"base64 payload isn't a valid utf-8 sequence".to_owned(),
|
.to_owned(),
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
Some(*value_span),
|
Some(*value_span),
|
||||||
Some("consider using the `--binary` flag".to_owned()),
|
Some("consider using the `--binary` flag".to_owned()),
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
)),
|
),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_) => Err(ShellError::GenericError(
|
Err(_) => Value::Error {
|
||||||
"value could not be base64 decoded".to_string(),
|
error: ShellError::GenericError(
|
||||||
format!(
|
"value could not be base64 decoded".to_string(),
|
||||||
"invalid base64 input for character set {}",
|
format!(
|
||||||
&config_character_set.item
|
"invalid base64 input for character set {}",
|
||||||
|
&config_character_set.item
|
||||||
|
),
|
||||||
|
Some(command_span),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
),
|
),
|
||||||
Some(*command_span),
|
},
|
||||||
None,
|
|
||||||
Vec::new(),
|
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
other => Err(ShellError::TypeMismatch(
|
other => Value::Error {
|
||||||
format!("value is {}, not string", other.get_type()),
|
error: ShellError::TypeMismatch(
|
||||||
other.span()?,
|
format!("value is {}, not string", other.get_type()),
|
||||||
)),
|
other.span().unwrap_or(command_span),
|
||||||
|
),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{action, ActionType, Base64Config};
|
use super::{action, ActionType, Arguments, Base64Config};
|
||||||
use nu_protocol::{Span, Spanned, Value};
|
use nu_protocol::{Span, Spanned, Value};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -184,17 +180,19 @@ mod tests {
|
|||||||
|
|
||||||
let actual = action(
|
let actual = action(
|
||||||
&word,
|
&word,
|
||||||
true,
|
&Arguments {
|
||||||
&Base64Config {
|
encoding_config: Base64Config {
|
||||||
character_set: Spanned {
|
character_set: Spanned {
|
||||||
item: "standard".to_string(),
|
item: "standard".to_string(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
action_type: ActionType::Encode,
|
||||||
},
|
},
|
||||||
action_type: ActionType::Encode,
|
binary: true,
|
||||||
|
cell_paths: None,
|
||||||
},
|
},
|
||||||
&Span::test_data(),
|
Span::test_data(),
|
||||||
)
|
);
|
||||||
.unwrap();
|
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,17 +203,19 @@ mod tests {
|
|||||||
|
|
||||||
let actual = action(
|
let actual = action(
|
||||||
&word,
|
&word,
|
||||||
true,
|
&Arguments {
|
||||||
&Base64Config {
|
encoding_config: Base64Config {
|
||||||
character_set: Spanned {
|
character_set: Spanned {
|
||||||
item: "standard-no-padding".to_string(),
|
item: "standard-no-padding".to_string(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
action_type: ActionType::Encode,
|
||||||
},
|
},
|
||||||
action_type: ActionType::Encode,
|
binary: true,
|
||||||
|
cell_paths: None,
|
||||||
},
|
},
|
||||||
&Span::test_data(),
|
Span::test_data(),
|
||||||
)
|
);
|
||||||
.unwrap();
|
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,17 +226,19 @@ mod tests {
|
|||||||
|
|
||||||
let actual = action(
|
let actual = action(
|
||||||
&word,
|
&word,
|
||||||
true,
|
&Arguments {
|
||||||
&Base64Config {
|
encoding_config: Base64Config {
|
||||||
character_set: Spanned {
|
character_set: Spanned {
|
||||||
item: "url-safe".to_string(),
|
item: "url-safe".to_string(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
action_type: ActionType::Encode,
|
||||||
},
|
},
|
||||||
action_type: ActionType::Encode,
|
binary: true,
|
||||||
|
cell_paths: None,
|
||||||
},
|
},
|
||||||
&Span::test_data(),
|
Span::test_data(),
|
||||||
)
|
);
|
||||||
.unwrap();
|
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,17 +249,19 @@ mod tests {
|
|||||||
|
|
||||||
let actual = action(
|
let actual = action(
|
||||||
&word,
|
&word,
|
||||||
true,
|
&Arguments {
|
||||||
&Base64Config {
|
encoding_config: Base64Config {
|
||||||
character_set: Spanned {
|
character_set: Spanned {
|
||||||
item: "binhex".to_string(),
|
item: "binhex".to_string(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
action_type: ActionType::Decode,
|
||||||
},
|
},
|
||||||
action_type: ActionType::Decode,
|
binary: true,
|
||||||
|
cell_paths: None,
|
||||||
},
|
},
|
||||||
&Span::test_data(),
|
Span::test_data(),
|
||||||
)
|
);
|
||||||
.unwrap();
|
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,17 +272,19 @@ mod tests {
|
|||||||
|
|
||||||
let actual = action(
|
let actual = action(
|
||||||
&word,
|
&word,
|
||||||
true,
|
&Arguments {
|
||||||
&Base64Config {
|
encoding_config: Base64Config {
|
||||||
character_set: Spanned {
|
character_set: Spanned {
|
||||||
item: "binhex".to_string(),
|
item: "binhex".to_string(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
action_type: ActionType::Decode,
|
||||||
},
|
},
|
||||||
action_type: ActionType::Decode,
|
binary: true,
|
||||||
|
cell_paths: None,
|
||||||
},
|
},
|
||||||
&Span::test_data(),
|
Span::test_data(),
|
||||||
)
|
);
|
||||||
.unwrap();
|
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,17 +298,19 @@ mod tests {
|
|||||||
|
|
||||||
let actual = action(
|
let actual = action(
|
||||||
&word,
|
&word,
|
||||||
true,
|
&Arguments {
|
||||||
&Base64Config {
|
encoding_config: Base64Config {
|
||||||
character_set: Spanned {
|
character_set: Spanned {
|
||||||
item: "standard".to_string(),
|
item: "standard".to_string(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
action_type: ActionType::Encode,
|
||||||
},
|
},
|
||||||
action_type: ActionType::Encode,
|
binary: true,
|
||||||
|
cell_paths: None,
|
||||||
},
|
},
|
||||||
&Span::test_data(),
|
Span::test_data(),
|
||||||
)
|
);
|
||||||
.unwrap();
|
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,16 +323,23 @@ mod tests {
|
|||||||
|
|
||||||
let actual = action(
|
let actual = action(
|
||||||
&word,
|
&word,
|
||||||
true,
|
&Arguments {
|
||||||
&Base64Config {
|
encoding_config: Base64Config {
|
||||||
character_set: Spanned {
|
character_set: Spanned {
|
||||||
item: "standard".to_string(),
|
item: "standard".to_string(),
|
||||||
span: Span::test_data(),
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
action_type: ActionType::Decode,
|
||||||
},
|
},
|
||||||
action_type: ActionType::Decode,
|
binary: true,
|
||||||
|
cell_paths: None,
|
||||||
},
|
},
|
||||||
&Span::test_data(),
|
Span::test_data(),
|
||||||
);
|
);
|
||||||
assert!(actual.is_err())
|
|
||||||
|
match actual {
|
||||||
|
Value::Error { .. } => {}
|
||||||
|
_ => panic!("the result should be Value::Error"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::input_handler::{operate, CmdArgument};
|
use crate::input_handler::{operate, CellPathOnlyArgs};
|
||||||
use nu_engine::CallExt;
|
use nu_engine::CallExt;
|
||||||
use nu_protocol::ast::Call;
|
use nu_protocol::ast::Call;
|
||||||
use nu_protocol::ast::CellPath;
|
use nu_protocol::ast::CellPath;
|
||||||
@ -8,16 +8,6 @@ use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShap
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
|
|
||||||
struct Arguments {
|
|
||||||
cell_paths: Option<Vec<CellPath>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CmdArgument for Arguments {
|
|
||||||
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
|
|
||||||
self.cell_paths.take()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Command for SubCommand {
|
impl Command for SubCommand {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"str length"
|
"str length"
|
||||||
@ -49,8 +39,7 @@ impl Command for SubCommand {
|
|||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||||
let cell_paths = (!cell_paths.is_empty()).then(|| cell_paths);
|
let args = CellPathOnlyArgs::from(cell_paths);
|
||||||
let args = Arguments { cell_paths };
|
|
||||||
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +62,7 @@ impl Command for SubCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn action(input: &Value, _arg: &Arguments, head: Span) -> Value {
|
fn action(input: &Value, _arg: &CellPathOnlyArgs, head: Span) -> Value {
|
||||||
match input {
|
match input {
|
||||||
Value::String { val, .. } => Value::Int {
|
Value::String { val, .. } => Value::Int {
|
||||||
val: val.len() as i64,
|
val: val.len() as i64,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::input_handler::{operate, CmdArgument};
|
use crate::input_handler::{operate, CellPathOnlyArgs};
|
||||||
use nu_engine::CallExt;
|
use nu_engine::CallExt;
|
||||||
use nu_protocol::ast::Call;
|
use nu_protocol::ast::Call;
|
||||||
use nu_protocol::ast::CellPath;
|
use nu_protocol::ast::CellPath;
|
||||||
@ -9,16 +9,6 @@ use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShap
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
|
|
||||||
struct Arguments {
|
|
||||||
cell_paths: Option<Vec<CellPath>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CmdArgument for Arguments {
|
|
||||||
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
|
|
||||||
self.cell_paths.take()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Command for SubCommand {
|
impl Command for SubCommand {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"str reverse"
|
"str reverse"
|
||||||
@ -50,8 +40,7 @@ impl Command for SubCommand {
|
|||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||||
let cell_paths = (!cell_paths.is_empty()).then(|| cell_paths);
|
let args = CellPathOnlyArgs::from(cell_paths);
|
||||||
let args = Arguments { cell_paths };
|
|
||||||
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +79,7 @@ impl Command for SubCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn action(input: &Value, _arg: &Arguments, head: Span) -> Value {
|
fn action(input: &Value, _arg: &CellPathOnlyArgs, head: Span) -> Value {
|
||||||
match input {
|
match input {
|
||||||
Value::String { val, .. } => Value::String {
|
Value::String { val, .. } => Value::String {
|
||||||
val: val.chars().rev().collect::<String>(),
|
val: val.chars().rev().collect::<String>(),
|
||||||
|
Loading…
Reference in New Issue
Block a user