forked from extern/nushell
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_protocol::ast::Call;
|
||||
use nu_protocol::ast::CellPath;
|
||||
@ -9,16 +9,6 @@ use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShap
|
||||
#[derive(Clone)]
|
||||
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 {
|
||||
fn name(&self) -> &str {
|
||||
"bytes length"
|
||||
@ -50,8 +40,7 @@ impl Command for BytesLen {
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
|
||||
let cell_paths = (!cell_paths.is_empty()).then(|| cell_paths);
|
||||
let arg = Arguments { cell_paths };
|
||||
let arg = CellPathOnlyArgs::from(cell_paths);
|
||||
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 {
|
||||
Value::Binary {
|
||||
val,
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::input_handler::{operate, CmdArgument};
|
||||
use crate::input_handler::{operate, CellPathOnlyArgs};
|
||||
use nu_engine::CallExt;
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::ast::CellPath;
|
||||
@ -6,16 +6,6 @@ use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
use nu_protocol::Category;
|
||||
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)]
|
||||
|
||||
pub struct BytesReverse;
|
||||
@ -51,8 +41,7 @@ impl Command for BytesReverse {
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||
let cell_paths = (!cell_paths.is_empty()).then(|| cell_paths);
|
||||
let arg = Arguments { cell_paths };
|
||||
let arg = CellPathOnlyArgs::from(cell_paths);
|
||||
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 {
|
||||
Value::Binary {
|
||||
val,
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::input_handler::{operate, CellPathOnlyArgs};
|
||||
use nu_engine::CallExt;
|
||||
use nu_protocol::{
|
||||
ast::{Call, CellPath},
|
||||
@ -96,31 +97,12 @@ fn fmt(
|
||||
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(),
|
||||
)
|
||||
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())
|
||||
}
|
||||
|
||||
pub fn action(input: &Value, span: Span) -> Value {
|
||||
fn action(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
|
||||
match input {
|
||||
Value::Int { 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_protocol::{
|
||||
ast::{Call, CellPath},
|
||||
@ -100,7 +101,7 @@ fn into_binary(
|
||||
input: PipelineData,
|
||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||
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 {
|
||||
PipelineData::ExternalStream { stdout: None, .. } => Ok(Value::Binary {
|
||||
@ -120,27 +121,10 @@ fn into_binary(
|
||||
}
|
||||
.into_pipeline_data())
|
||||
}
|
||||
_ => 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(),
|
||||
),
|
||||
_ => {
|
||||
let arg = CellPathOnlyArgs::from(cell_paths);
|
||||
operate(action, arg, input, call.head, 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 {
|
||||
Value::Binary { .. } => input.clone(),
|
||||
Value::Int { val, .. } => Value::Binary {
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::input_handler::{operate, CellPathOnlyArgs};
|
||||
use nu_engine::CallExt;
|
||||
use nu_protocol::{
|
||||
ast::{Call, CellPath},
|
||||
@ -108,28 +109,9 @@ fn into_bool(
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, 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(),
|
||||
)
|
||||
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 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 {
|
||||
Value::Bool { .. } => input.clone(),
|
||||
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 chrono::{DateTime, FixedOffset, Local, TimeZone, Utc};
|
||||
use nu_engine::CallExt;
|
||||
@ -5,14 +6,20 @@ use nu_protocol::ast::Call;
|
||||
use nu_protocol::ast::CellPath;
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value,
|
||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Spanned,
|
||||
SyntaxShape, Value,
|
||||
};
|
||||
|
||||
struct Arguments {
|
||||
timezone: Option<Spanned<String>>,
|
||||
offset: Option<Spanned<i64>>,
|
||||
format: Option<String>,
|
||||
column_paths: Vec<CellPath>,
|
||||
zone_options: Option<Spanned<Zone>>,
|
||||
format_options: Option<DatetimeFormat>,
|
||||
cell_paths: Option<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
|
||||
@ -95,7 +102,36 @@ impl Command for SubCommand {
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> 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 {
|
||||
@ -162,72 +198,9 @@ impl Command for SubCommand {
|
||||
#[derive(Clone)]
|
||||
struct DatetimeFormat(String);
|
||||
|
||||
fn operate(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
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 {
|
||||
fn action(input: &Value, args: &Arguments, head: Span) -> Value {
|
||||
let timezone = &args.zone_options;
|
||||
let dateformat = &args.format_options;
|
||||
// Check to see if input looks like a Unix timestamp (i.e. can it be parsed to an int?)
|
||||
let timestamp = match input {
|
||||
Value::Int { val, .. } => Ok(*val),
|
||||
@ -359,7 +332,12 @@ mod tests {
|
||||
fn takes_a_date_format() {
|
||||
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 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 {
|
||||
val: DateTime::parse_from_str("16.11.1984 8:00 am +0000", "%d.%m.%Y %H:%M %P %z")
|
||||
.unwrap(),
|
||||
@ -371,7 +349,12 @@ mod tests {
|
||||
#[test]
|
||||
fn takes_iso8601_date_format() {
|
||||
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 {
|
||||
val: DateTime::parse_from_str("2020-08-04T16:39:18+00:00", "%Y-%m-%dT%H:%M:%S%z")
|
||||
.unwrap(),
|
||||
@ -387,7 +370,12 @@ mod tests {
|
||||
item: Zone::East(8),
|
||||
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 {
|
||||
val: DateTime::parse_from_str("2021-02-27 21:55:40 +08:00", "%Y-%m-%d %H:%M:%S %z")
|
||||
.unwrap(),
|
||||
@ -404,7 +392,12 @@ mod tests {
|
||||
item: Zone::East(8),
|
||||
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 {
|
||||
val: DateTime::parse_from_str("2021-02-27 21:55:40 +08:00", "%Y-%m-%d %H:%M:%S %z")
|
||||
.unwrap(),
|
||||
@ -421,7 +414,12 @@ mod tests {
|
||||
item: Zone::Local,
|
||||
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 {
|
||||
val: Local.timestamp(1614434140, 0).into(),
|
||||
span: Span::test_data(),
|
||||
@ -433,8 +431,12 @@ mod tests {
|
||||
#[test]
|
||||
fn takes_timestamp_without_timezone() {
|
||||
let date_str = Value::test_string("1614434140");
|
||||
let timezone_option = None;
|
||||
let actual = action(&date_str, &timezone_option, &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 {
|
||||
val: Utc.timestamp(1614434140, 0).into(),
|
||||
@ -451,7 +453,12 @@ mod tests {
|
||||
item: Zone::Utc,
|
||||
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);
|
||||
}
|
||||
@ -460,7 +467,12 @@ mod tests {
|
||||
fn communicates_parsing_error_given_an_invalid_datetimelike_string() {
|
||||
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 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);
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::input_handler::{operate, CellPathOnlyArgs};
|
||||
use nu_engine::CallExt;
|
||||
use nu_protocol::{
|
||||
ast::{Call, CellPath},
|
||||
@ -36,7 +37,9 @@ impl Command for SubCommand {
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> 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> {
|
||||
@ -72,37 +75,7 @@ impl Command for SubCommand {
|
||||
}
|
||||
}
|
||||
|
||||
fn operate(
|
||||
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 {
|
||||
fn action(input: &Value, _args: &CellPathOnlyArgs, head: Span) -> Value {
|
||||
match input {
|
||||
Value::String { val: s, span } => {
|
||||
let other = s.trim();
|
||||
@ -163,7 +136,7 @@ mod tests {
|
||||
let word = Value::test_string("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);
|
||||
}
|
||||
|
||||
@ -171,7 +144,11 @@ mod tests {
|
||||
fn communicates_parsing_error_given_an_invalid_decimallike_string() {
|
||||
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);
|
||||
}
|
||||
@ -180,7 +157,11 @@ mod tests {
|
||||
fn int_to_decimal() {
|
||||
let decimal_str = Value::test_int(10);
|
||||
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);
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::input_handler::{operate, CellPathOnlyArgs};
|
||||
use nu_engine::CallExt;
|
||||
use nu_protocol::{
|
||||
ast::{Call, CellPath},
|
||||
@ -38,7 +39,9 @@ impl Command for SubCommand {
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> 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> {
|
||||
@ -84,37 +87,7 @@ impl Command for SubCommand {
|
||||
}
|
||||
}
|
||||
|
||||
fn into_filesize(
|
||||
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 {
|
||||
pub fn action(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
|
||||
if let Ok(value_span) = input.span() {
|
||||
match input {
|
||||
Value::Filesize { .. } => input.clone(),
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::input_handler::{operate, CmdArgument};
|
||||
use nu_engine::CallExt;
|
||||
use nu_protocol::{
|
||||
ast::{Call, CellPath},
|
||||
@ -6,11 +7,17 @@ use nu_protocol::{
|
||||
};
|
||||
|
||||
struct Arguments {
|
||||
radix: Option<Value>,
|
||||
column_paths: Vec<CellPath>,
|
||||
radix: u32,
|
||||
cell_paths: Option<Vec<CellPath>>,
|
||||
little_endian: bool,
|
||||
}
|
||||
|
||||
impl CmdArgument for Arguments {
|
||||
fn take_cell_paths(&mut self) -> Option<Vec<CellPath>> {
|
||||
self.cell_paths.take()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SubCommand;
|
||||
|
||||
@ -46,7 +53,29 @@ impl Command for SubCommand {
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> 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> {
|
||||
@ -121,59 +150,9 @@ impl Command for SubCommand {
|
||||
}
|
||||
}
|
||||
|
||||
fn into_int(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
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 {
|
||||
fn action(input: &Value, args: &Arguments, span: Span) -> Value {
|
||||
let radix = args.radix;
|
||||
let little_endian = args.little_endian;
|
||||
match input {
|
||||
Value::Int { val: _, .. } => {
|
||||
if radix == 10 {
|
||||
@ -401,21 +380,45 @@ mod test {
|
||||
let word = Value::test_string("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);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn turns_binary_to_integer() {
|
||||
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));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn turns_hex_to_integer() {
|
||||
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));
|
||||
}
|
||||
|
||||
@ -423,7 +426,15 @@ mod test {
|
||||
fn communicates_parsing_error_given_an_invalid_integerlike_string() {
|
||||
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)
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::input_handler::{operate, CmdArgument};
|
||||
use nu_engine::CallExt;
|
||||
use nu_protocol::{
|
||||
ast::{Call, CellPath},
|
||||
@ -8,6 +9,19 @@ use nu_protocol::{
|
||||
use nu_utils::get_system_locale;
|
||||
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)]
|
||||
pub struct SubCommand;
|
||||
|
||||
@ -149,9 +163,6 @@ fn string_helper(
|
||||
let decimals = call.has_flag("decimals");
|
||||
let head = call.head;
|
||||
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 decimals && decimal_val.is_negative() {
|
||||
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 {
|
||||
PipelineData::ExternalStream { stdout: None, .. } => Ok(Value::String {
|
||||
@ -179,45 +199,18 @@ fn string_helper(
|
||||
}
|
||||
.into_pipeline_data())
|
||||
}
|
||||
_ => input.map(
|
||||
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(),
|
||||
),
|
||||
_ => operate(action, args, input, head, engine_state.ctrlc.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn action(
|
||||
input: &Value,
|
||||
span: Span,
|
||||
decimals: bool,
|
||||
digits: Option<i64>,
|
||||
group_digits: bool,
|
||||
config: &Config,
|
||||
) -> Value {
|
||||
fn action(input: &Value, args: &Arguments, span: Span) -> Value {
|
||||
let decimals = args.decimals;
|
||||
let digits = args.decimals_value;
|
||||
let config = &args.config;
|
||||
match input {
|
||||
Value::Int { val, .. } => {
|
||||
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::Float { val, .. } => {
|
||||
|
@ -1,6 +1,8 @@
|
||||
use crate::input_handler::{operate, CmdArgument};
|
||||
use nu_engine::CallExt;
|
||||
use nu_protocol::ast::{Call, CellPath};
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
use nu_protocol::Span;
|
||||
use nu_protocol::{Example, PipelineData, ShellError, Signature, SyntaxShape, Value};
|
||||
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>
|
||||
where
|
||||
D: HashDigest + Send + Sync + 'static,
|
||||
@ -66,31 +79,19 @@ where
|
||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||
let binary = call.has_flag("binary");
|
||||
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||
|
||||
input.map(
|
||||
move |v| {
|
||||
if cell_paths.is_empty() {
|
||||
action::<D>(binary, &v)
|
||||
} else {
|
||||
let mut v = v;
|
||||
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
|
||||
}
|
||||
},
|
||||
let cell_paths = (!cell_paths.is_empty()).then(|| cell_paths);
|
||||
let args = Arguments { binary, cell_paths };
|
||||
operate(
|
||||
action::<D>,
|
||||
args,
|
||||
input,
|
||||
call.head,
|
||||
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
|
||||
D: HashDigest,
|
||||
digest::Output<D>: core::fmt::LowerHex,
|
||||
@ -119,7 +120,7 @@ where
|
||||
|
||||
let digest = D::digest(bytes);
|
||||
|
||||
if binary {
|
||||
if args.binary {
|
||||
Value::Binary {
|
||||
val: digest.to_vec(),
|
||||
span,
|
||||
|
@ -42,7 +42,7 @@ impl HashDigest for Md5 {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::hash::generic_digest;
|
||||
use crate::hash::generic_digest::{self, Arguments};
|
||||
|
||||
#[test]
|
||||
fn test_examples() {
|
||||
@ -59,7 +59,14 @@ mod tests {
|
||||
val: "c3fcd3d76192e4007dfb496cca67e13b".to_owned(),
|
||||
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);
|
||||
}
|
||||
|
||||
@ -73,7 +80,14 @@ mod tests {
|
||||
val: "5f80e231382769b0102b1164cf722d83".to_owned(),
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ impl HashDigest for Sha256 {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::hash::generic_digest;
|
||||
use crate::hash::generic_digest::{self, Arguments};
|
||||
|
||||
#[test]
|
||||
fn test_examples() {
|
||||
@ -61,7 +61,14 @@ mod tests {
|
||||
val: "71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73".to_owned(),
|
||||
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);
|
||||
}
|
||||
|
||||
@ -75,7 +82,14 @@ mod tests {
|
||||
val: "c47a10dc272b1221f0380a2ae0f7d7fa830b3e378f2f5309bbf13f61ad211913".to_owned(),
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,28 @@ pub trait CmdArgument {
|
||||
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.
|
||||
///
|
||||
/// 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 nu_engine::CallExt;
|
||||
use nu_protocol::ast::{Call, CellPath};
|
||||
@ -20,6 +21,18 @@ pub enum ActionType {
|
||||
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(
|
||||
action_type: ActionType,
|
||||
engine_state: &EngineState,
|
||||
@ -31,7 +44,8 @@ pub fn operate(
|
||||
let character_set: Option<Spanned<String>> =
|
||||
call.get_flag(engine_state, stack, "character-set")?;
|
||||
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.
|
||||
let character_set = match character_set {
|
||||
@ -42,50 +56,27 @@ pub fn operate(
|
||||
},
|
||||
};
|
||||
|
||||
let encoding_config = Base64Config {
|
||||
character_set,
|
||||
action_type,
|
||||
let args = Arguments {
|
||||
encoding_config: Base64Config {
|
||||
character_set,
|
||||
action_type,
|
||||
},
|
||||
binary,
|
||||
cell_paths,
|
||||
};
|
||||
|
||||
input.map(
|
||||
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(),
|
||||
)
|
||||
general_operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||
}
|
||||
|
||||
fn action(
|
||||
input: &Value,
|
||||
// only used for `decode` action
|
||||
output_binary: bool,
|
||||
base64_config: &Base64Config,
|
||||
command_span: &Span,
|
||||
) -> Result<Value, ShellError> {
|
||||
args: &Arguments,
|
||||
command_span: Span,
|
||||
) -> Value {
|
||||
let base64_config = &args.encoding_config;
|
||||
let output_binary = args.binary;
|
||||
|
||||
let config_character_set = &base64_config.character_set;
|
||||
let base64_config_enum: base64::Config = match config_character_set.item.as_str() {
|
||||
"standard" => base64::STANDARD,
|
||||
@ -95,7 +86,7 @@ fn action(
|
||||
"binhex" => base64::BINHEX,
|
||||
"bcrypt" => base64::BCRYPT,
|
||||
"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(),
|
||||
format!(
|
||||
"{} 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),
|
||||
None,
|
||||
Vec::new(),
|
||||
))
|
||||
)}
|
||||
};
|
||||
match input {
|
||||
Value::Binary { val, .. } => match base64_config.action_type {
|
||||
ActionType::Encode => Ok(Value::string(
|
||||
encode_config(&val, base64_config_enum),
|
||||
*command_span,
|
||||
)),
|
||||
ActionType::Decode => Err(ShellError::UnsupportedInput(
|
||||
"Binary data can only support encoding".to_string(),
|
||||
*command_span,
|
||||
)),
|
||||
ActionType::Encode => {
|
||||
Value::string(encode_config(&val, base64_config_enum), command_span)
|
||||
}
|
||||
ActionType::Decode => Value::Error {
|
||||
error: ShellError::UnsupportedInput(
|
||||
"Binary data can only support encoding".to_string(),
|
||||
command_span,
|
||||
),
|
||||
},
|
||||
},
|
||||
Value::String {
|
||||
val,
|
||||
span: value_span,
|
||||
} => {
|
||||
match base64_config.action_type {
|
||||
ActionType::Encode => Ok(Value::string(
|
||||
encode_config(&val, base64_config_enum),
|
||||
*command_span,
|
||||
)),
|
||||
ActionType::Encode => {
|
||||
Value::string(encode_config(&val, base64_config_enum), command_span)
|
||||
}
|
||||
|
||||
ActionType::Decode => {
|
||||
// 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) {
|
||||
Ok(decoded_value) => {
|
||||
if output_binary {
|
||||
Ok(Value::binary(decoded_value, *command_span))
|
||||
Value::binary(decoded_value, command_span)
|
||||
} else {
|
||||
match String::from_utf8(decoded_value) {
|
||||
Ok(string_value) => {
|
||||
Ok(Value::string(string_value, *command_span))
|
||||
}
|
||||
Err(e) => Err(ShellError::GenericError(
|
||||
"base64 payload isn't a valid utf-8 sequence".to_owned(),
|
||||
e.to_string(),
|
||||
Some(*value_span),
|
||||
Some("consider using the `--binary` flag".to_owned()),
|
||||
Vec::new(),
|
||||
)),
|
||||
Ok(string_value) => Value::string(string_value, command_span),
|
||||
Err(e) => Value::Error {
|
||||
error: ShellError::GenericError(
|
||||
"base64 payload isn't a valid utf-8 sequence"
|
||||
.to_owned(),
|
||||
e.to_string(),
|
||||
Some(*value_span),
|
||||
Some("consider using the `--binary` flag".to_owned()),
|
||||
Vec::new(),
|
||||
),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => Err(ShellError::GenericError(
|
||||
"value could not be base64 decoded".to_string(),
|
||||
format!(
|
||||
"invalid base64 input for character set {}",
|
||||
&config_character_set.item
|
||||
Err(_) => Value::Error {
|
||||
error: ShellError::GenericError(
|
||||
"value could not be base64 decoded".to_string(),
|
||||
format!(
|
||||
"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(
|
||||
format!("value is {}, not string", other.get_type()),
|
||||
other.span()?,
|
||||
)),
|
||||
other => Value::Error {
|
||||
error: ShellError::TypeMismatch(
|
||||
format!("value is {}, not string", other.get_type()),
|
||||
other.span().unwrap_or(command_span),
|
||||
),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{action, ActionType, Base64Config};
|
||||
use super::{action, ActionType, Arguments, Base64Config};
|
||||
use nu_protocol::{Span, Spanned, Value};
|
||||
|
||||
#[test]
|
||||
@ -184,17 +180,19 @@ mod tests {
|
||||
|
||||
let actual = action(
|
||||
&word,
|
||||
true,
|
||||
&Base64Config {
|
||||
character_set: Spanned {
|
||||
item: "standard".to_string(),
|
||||
span: Span::test_data(),
|
||||
&Arguments {
|
||||
encoding_config: Base64Config {
|
||||
character_set: Spanned {
|
||||
item: "standard".to_string(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
action_type: ActionType::Encode,
|
||||
},
|
||||
action_type: ActionType::Encode,
|
||||
binary: true,
|
||||
cell_paths: None,
|
||||
},
|
||||
&Span::test_data(),
|
||||
)
|
||||
.unwrap();
|
||||
Span::test_data(),
|
||||
);
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
@ -205,17 +203,19 @@ mod tests {
|
||||
|
||||
let actual = action(
|
||||
&word,
|
||||
true,
|
||||
&Base64Config {
|
||||
character_set: Spanned {
|
||||
item: "standard-no-padding".to_string(),
|
||||
span: Span::test_data(),
|
||||
&Arguments {
|
||||
encoding_config: Base64Config {
|
||||
character_set: Spanned {
|
||||
item: "standard-no-padding".to_string(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
action_type: ActionType::Encode,
|
||||
},
|
||||
action_type: ActionType::Encode,
|
||||
binary: true,
|
||||
cell_paths: None,
|
||||
},
|
||||
&Span::test_data(),
|
||||
)
|
||||
.unwrap();
|
||||
Span::test_data(),
|
||||
);
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
@ -226,17 +226,19 @@ mod tests {
|
||||
|
||||
let actual = action(
|
||||
&word,
|
||||
true,
|
||||
&Base64Config {
|
||||
character_set: Spanned {
|
||||
item: "url-safe".to_string(),
|
||||
span: Span::test_data(),
|
||||
&Arguments {
|
||||
encoding_config: Base64Config {
|
||||
character_set: Spanned {
|
||||
item: "url-safe".to_string(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
action_type: ActionType::Encode,
|
||||
},
|
||||
action_type: ActionType::Encode,
|
||||
binary: true,
|
||||
cell_paths: None,
|
||||
},
|
||||
&Span::test_data(),
|
||||
)
|
||||
.unwrap();
|
||||
Span::test_data(),
|
||||
);
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
@ -247,17 +249,19 @@ mod tests {
|
||||
|
||||
let actual = action(
|
||||
&word,
|
||||
true,
|
||||
&Base64Config {
|
||||
character_set: Spanned {
|
||||
item: "binhex".to_string(),
|
||||
span: Span::test_data(),
|
||||
&Arguments {
|
||||
encoding_config: Base64Config {
|
||||
character_set: Spanned {
|
||||
item: "binhex".to_string(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
action_type: ActionType::Decode,
|
||||
},
|
||||
action_type: ActionType::Decode,
|
||||
binary: true,
|
||||
cell_paths: None,
|
||||
},
|
||||
&Span::test_data(),
|
||||
)
|
||||
.unwrap();
|
||||
Span::test_data(),
|
||||
);
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
@ -268,17 +272,19 @@ mod tests {
|
||||
|
||||
let actual = action(
|
||||
&word,
|
||||
true,
|
||||
&Base64Config {
|
||||
character_set: Spanned {
|
||||
item: "binhex".to_string(),
|
||||
span: Span::test_data(),
|
||||
&Arguments {
|
||||
encoding_config: Base64Config {
|
||||
character_set: Spanned {
|
||||
item: "binhex".to_string(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
action_type: ActionType::Decode,
|
||||
},
|
||||
action_type: ActionType::Decode,
|
||||
binary: true,
|
||||
cell_paths: None,
|
||||
},
|
||||
&Span::test_data(),
|
||||
)
|
||||
.unwrap();
|
||||
Span::test_data(),
|
||||
);
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
@ -292,17 +298,19 @@ mod tests {
|
||||
|
||||
let actual = action(
|
||||
&word,
|
||||
true,
|
||||
&Base64Config {
|
||||
character_set: Spanned {
|
||||
item: "standard".to_string(),
|
||||
span: Span::test_data(),
|
||||
&Arguments {
|
||||
encoding_config: Base64Config {
|
||||
character_set: Spanned {
|
||||
item: "standard".to_string(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
action_type: ActionType::Encode,
|
||||
},
|
||||
action_type: ActionType::Encode,
|
||||
binary: true,
|
||||
cell_paths: None,
|
||||
},
|
||||
&Span::test_data(),
|
||||
)
|
||||
.unwrap();
|
||||
Span::test_data(),
|
||||
);
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
@ -315,16 +323,23 @@ mod tests {
|
||||
|
||||
let actual = action(
|
||||
&word,
|
||||
true,
|
||||
&Base64Config {
|
||||
character_set: Spanned {
|
||||
item: "standard".to_string(),
|
||||
span: Span::test_data(),
|
||||
&Arguments {
|
||||
encoding_config: Base64Config {
|
||||
character_set: Spanned {
|
||||
item: "standard".to_string(),
|
||||
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_protocol::ast::Call;
|
||||
use nu_protocol::ast::CellPath;
|
||||
@ -8,16 +8,6 @@ use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShap
|
||||
#[derive(Clone)]
|
||||
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 {
|
||||
fn name(&self) -> &str {
|
||||
"str length"
|
||||
@ -49,8 +39,7 @@ impl Command for SubCommand {
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||
let cell_paths = (!cell_paths.is_empty()).then(|| cell_paths);
|
||||
let args = Arguments { cell_paths };
|
||||
let args = CellPathOnlyArgs::from(cell_paths);
|
||||
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 {
|
||||
Value::String { val, .. } => Value::Int {
|
||||
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_protocol::ast::Call;
|
||||
use nu_protocol::ast::CellPath;
|
||||
@ -9,16 +9,6 @@ use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShap
|
||||
#[derive(Clone)]
|
||||
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 {
|
||||
fn name(&self) -> &str {
|
||||
"str reverse"
|
||||
@ -50,8 +40,7 @@ impl Command for SubCommand {
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||
let cell_paths = (!cell_paths.is_empty()).then(|| cell_paths);
|
||||
let args = Arguments { cell_paths };
|
||||
let args = CellPathOnlyArgs::from(cell_paths);
|
||||
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 {
|
||||
Value::String { val, .. } => Value::String {
|
||||
val: val.chars().rev().collect::<String>(),
|
||||
|
Loading…
Reference in New Issue
Block a user