forked from extern/nushell
move out call info deserializing from str
(#3294)
This commit is contained in:
parent
b19a7aa8a6
commit
a131eddf54
@ -8,9 +8,8 @@ use nu_protocol::{
|
|||||||
use nu_source::Tag;
|
use nu_source::Tag;
|
||||||
use nu_value_ext::ValueExt;
|
use nu_value_ext::ValueExt;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
rest: Vec<ColumnPath>,
|
column_paths: Vec<ColumnPath>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
@ -45,18 +44,20 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let (Arguments { rest }, input) = args.process()?;
|
let (options, input) = args.extract(|params| {
|
||||||
|
Ok(Arguments {
|
||||||
let column_paths: Vec<_> = rest;
|
column_paths: params.rest_args()?,
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.map(move |v| {
|
.map(move |v| {
|
||||||
if column_paths.is_empty() {
|
if options.column_paths.is_empty() {
|
||||||
ReturnSuccess::value(action(&v, v.tag())?)
|
ReturnSuccess::value(action(&v, v.tag())?)
|
||||||
} else {
|
} else {
|
||||||
let mut ret = v;
|
let mut ret = v;
|
||||||
|
|
||||||
for path in &column_paths {
|
for path in &options.column_paths {
|
||||||
ret = ret.swap_data_by_column_path(
|
ret = ret.swap_data_by_column_path(
|
||||||
path,
|
path,
|
||||||
Box::new(move |old| action(old, old.tag())),
|
Box::new(move |old| action(old, old.tag())),
|
||||||
|
@ -16,26 +16,28 @@ pub use pascal_case::SubCommand as PascalCase;
|
|||||||
pub use screaming_snake_case::SubCommand as ScreamingSnakeCase;
|
pub use screaming_snake_case::SubCommand as ScreamingSnakeCase;
|
||||||
pub use snake_case::SubCommand as SnakeCase;
|
pub use snake_case::SubCommand as SnakeCase;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
rest: Vec<ColumnPath>,
|
column_paths: Vec<ColumnPath>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn operate<F>(args: CommandArgs, case_operation: &'static F) -> Result<OutputStream, ShellError>
|
pub fn operate<F>(args: CommandArgs, case_operation: &'static F) -> Result<OutputStream, ShellError>
|
||||||
where
|
where
|
||||||
F: Fn(&str) -> String + Send + Sync + 'static,
|
F: Fn(&str) -> String + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
let (Arguments { rest }, input) = args.process()?;
|
let (options, input) = args.extract(|params| {
|
||||||
|
Ok(Arguments {
|
||||||
|
column_paths: params.rest_args()?,
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
let column_paths: Vec<_> = rest;
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.map(move |v| {
|
.map(move |v| {
|
||||||
if column_paths.is_empty() {
|
if options.column_paths.is_empty() {
|
||||||
ReturnSuccess::value(action(&v, v.tag(), &case_operation)?)
|
ReturnSuccess::value(action(&v, v.tag(), &case_operation)?)
|
||||||
} else {
|
} else {
|
||||||
let mut ret = v;
|
let mut ret = v;
|
||||||
|
|
||||||
for path in &column_paths {
|
for path in &options.column_paths {
|
||||||
ret = ret.swap_data_by_column_path(
|
ret = ret.swap_data_by_column_path(
|
||||||
path,
|
path,
|
||||||
Box::new(move |old| action(old, old.tag(), &case_operation)),
|
Box::new(move |old| action(old, old.tag(), &case_operation)),
|
||||||
|
@ -6,6 +6,16 @@ use nu_source::Tagged;
|
|||||||
|
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
|
|
||||||
|
struct Arguments {
|
||||||
|
separator: Option<Tagged<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Arguments {
|
||||||
|
pub fn separator(&self) -> &str {
|
||||||
|
self.separator.as_ref().map_or("", |sep| &sep.item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl WholeStreamCommand for SubCommand {
|
impl WholeStreamCommand for SubCommand {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"str collect"
|
"str collect"
|
||||||
@ -38,15 +48,18 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
|
|
||||||
pub fn collect(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn collect(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let tag = args.call_info.name_tag.clone();
|
let tag = args.call_info.name_tag.clone();
|
||||||
//let (SubCommandArgs { separator }, input) = args.process()?;
|
|
||||||
let args = args.evaluate_once()?;
|
let (options, input) = args.extract(|params| {
|
||||||
let separator: Option<Result<Tagged<String>, ShellError>> = args.opt(0);
|
Ok(Arguments {
|
||||||
let input = args.input;
|
separator: if let Some(arg) = params.opt(0) {
|
||||||
let separator = if let Some(separator) = separator {
|
Some(arg?)
|
||||||
separator?.item
|
} else {
|
||||||
} else {
|
None
|
||||||
"".into()
|
},
|
||||||
};
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let separator = options.separator();
|
||||||
|
|
||||||
let strings: Vec<Result<String, ShellError>> = input.map(|value| value.as_string()).collect();
|
let strings: Vec<Result<String, ShellError>> = input.map(|value| value.as_string()).collect();
|
||||||
let strings: Result<Vec<_>, _> = strings.into_iter().collect::<Result<_, _>>();
|
let strings: Result<Vec<_>, _> = strings.into_iter().collect::<Result<_, _>>();
|
||||||
|
@ -8,11 +8,10 @@ use nu_protocol::{
|
|||||||
use nu_source::{Tag, Tagged};
|
use nu_source::{Tag, Tagged};
|
||||||
use nu_value_ext::ValueExt;
|
use nu_value_ext::ValueExt;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
pattern: Tagged<String>,
|
pattern: Tagged<String>,
|
||||||
rest: Vec<ColumnPath>,
|
|
||||||
insensitive: bool,
|
insensitive: bool,
|
||||||
|
column_paths: Vec<ColumnPath>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
@ -57,28 +56,27 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let (
|
let (options, input) = args.extract(|params| {
|
||||||
Arguments {
|
Ok(Arc::new(Arguments {
|
||||||
pattern,
|
pattern: params.req(0)?,
|
||||||
rest,
|
insensitive: params.has_flag("insensitive"),
|
||||||
insensitive,
|
column_paths: params.rest(1)?,
|
||||||
},
|
}))
|
||||||
input,
|
})?;
|
||||||
) = args.process()?;
|
|
||||||
let column_paths: Vec<_> = rest;
|
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.map(move |v| {
|
.map(move |v| {
|
||||||
if column_paths.is_empty() {
|
if options.column_paths.is_empty() {
|
||||||
ReturnSuccess::value(action(&v, &pattern, insensitive, v.tag())?)
|
ReturnSuccess::value(action(&v, &options, v.tag())?)
|
||||||
} else {
|
} else {
|
||||||
let mut ret = v;
|
let mut ret = v;
|
||||||
|
|
||||||
for path in &column_paths {
|
for path in &options.column_paths {
|
||||||
let pattern = pattern.clone();
|
let options = options.clone();
|
||||||
|
|
||||||
ret = ret.swap_data_by_column_path(
|
ret = ret.swap_data_by_column_path(
|
||||||
path,
|
path,
|
||||||
Box::new(move |old| action(old, &pattern, insensitive, old.tag())),
|
Box::new(move |old| action(old, &options, old.tag())),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,16 +88,19 @@ fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
|
|
||||||
fn action(
|
fn action(
|
||||||
input: &Value,
|
input: &Value,
|
||||||
pattern: &str,
|
Arguments {
|
||||||
insensitive: bool,
|
ref pattern,
|
||||||
|
insensitive,
|
||||||
|
..
|
||||||
|
}: &Arguments,
|
||||||
tag: impl Into<Tag>,
|
tag: impl Into<Tag>,
|
||||||
) -> Result<Value, ShellError> {
|
) -> Result<Value, ShellError> {
|
||||||
match &input.value {
|
match &input.value {
|
||||||
UntaggedValue::Primitive(Primitive::String(s)) => {
|
UntaggedValue::Primitive(Primitive::String(s)) => {
|
||||||
let contains = if insensitive {
|
let contains = if *insensitive {
|
||||||
s.to_lowercase().contains(&pattern.to_lowercase())
|
s.to_lowercase().contains(&pattern.to_lowercase())
|
||||||
} else {
|
} else {
|
||||||
s.contains(pattern)
|
s.contains(&pattern.item)
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(UntaggedValue::boolean(contains).into_value(tag))
|
Ok(UntaggedValue::boolean(contains).into_value(tag))
|
||||||
@ -118,9 +119,9 @@ fn action(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::ShellError;
|
use super::ShellError;
|
||||||
use super::{action, SubCommand};
|
use super::{action, Arguments, SubCommand};
|
||||||
use nu_protocol::UntaggedValue;
|
use nu_protocol::UntaggedValue;
|
||||||
use nu_source::Tag;
|
use nu_source::{Tag, TaggedItem};
|
||||||
use nu_test_support::value::string;
|
use nu_test_support::value::string;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -133,44 +134,64 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn string_contains_other_string_case_sensitive() {
|
fn string_contains_other_string_case_sensitive() {
|
||||||
let word = string("Cargo.tomL");
|
let word = string("Cargo.tomL");
|
||||||
let pattern = ".tomL";
|
|
||||||
let insensitive = false;
|
|
||||||
let expected = UntaggedValue::boolean(true).into_untagged_value();
|
|
||||||
|
|
||||||
let actual = action(&word, &pattern, insensitive, Tag::unknown()).unwrap();
|
let options = Arguments {
|
||||||
|
pattern: String::from(".tomL").tagged_unknown(),
|
||||||
|
insensitive: false,
|
||||||
|
column_paths: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected = UntaggedValue::boolean(true).into_untagged_value();
|
||||||
|
let actual = action(&word, &options, Tag::unknown()).unwrap();
|
||||||
|
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn string_does_not_contain_other_string_case_sensitive() {
|
fn string_does_not_contain_other_string_case_sensitive() {
|
||||||
let word = string("Cargo.tomL");
|
let word = string("Cargo.tomL");
|
||||||
let pattern = "Lomt.";
|
|
||||||
let insensitive = false;
|
|
||||||
let expected = UntaggedValue::boolean(false).into_untagged_value();
|
|
||||||
|
|
||||||
let actual = action(&word, &pattern, insensitive, Tag::unknown()).unwrap();
|
let options = Arguments {
|
||||||
|
pattern: String::from("Lomt.").tagged_unknown(),
|
||||||
|
insensitive: false,
|
||||||
|
column_paths: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected = UntaggedValue::boolean(false).into_untagged_value();
|
||||||
|
let actual = action(&word, &options, Tag::unknown()).unwrap();
|
||||||
|
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn string_contains_other_string_case_insensitive() {
|
fn string_contains_other_string_case_insensitive() {
|
||||||
let word = string("Cargo.ToMl");
|
let word = string("Cargo.ToMl");
|
||||||
let pattern = ".TOML";
|
|
||||||
let insensitive = true;
|
|
||||||
let expected = UntaggedValue::boolean(true).into_untagged_value();
|
|
||||||
|
|
||||||
let actual = action(&word, &pattern, insensitive, Tag::unknown()).unwrap();
|
let options = Arguments {
|
||||||
|
pattern: String::from(".TOML").tagged_unknown(),
|
||||||
|
insensitive: true,
|
||||||
|
column_paths: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected = UntaggedValue::boolean(true).into_untagged_value();
|
||||||
|
let actual = action(&word, &options, Tag::unknown()).unwrap();
|
||||||
|
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn string_does_not_contain_other_string_case_insensitive() {
|
fn string_does_not_contain_other_string_case_insensitive() {
|
||||||
let word = string("Cargo.tOml");
|
let word = string("Cargo.tOml");
|
||||||
let pattern = "lomt.";
|
|
||||||
let insensitive = true;
|
|
||||||
let expected = UntaggedValue::boolean(false).into_untagged_value();
|
|
||||||
|
|
||||||
let actual = action(&word, &pattern, insensitive, Tag::unknown()).unwrap();
|
let options = Arguments {
|
||||||
|
pattern: String::from("lomt.").tagged_unknown(),
|
||||||
|
insensitive: true,
|
||||||
|
column_paths: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected = UntaggedValue::boolean(false).into_untagged_value();
|
||||||
|
let actual = action(&word, &options, Tag::unknown()).unwrap();
|
||||||
|
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,8 @@ use nu_protocol::{
|
|||||||
use nu_source::Tag;
|
use nu_source::Tag;
|
||||||
use nu_value_ext::ValueExt;
|
use nu_value_ext::ValueExt;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
rest: Vec<ColumnPath>,
|
column_paths: Vec<ColumnPath>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
@ -45,18 +44,20 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let (Arguments { rest }, input) = args.process()?;
|
let (options, input) = args.extract(|params| {
|
||||||
|
Ok(Arguments {
|
||||||
let column_paths: Vec<_> = rest;
|
column_paths: params.rest_args()?,
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.map(move |v| {
|
.map(move |v| {
|
||||||
if column_paths.is_empty() {
|
if options.column_paths.is_empty() {
|
||||||
ReturnSuccess::value(action(&v, v.tag())?)
|
ReturnSuccess::value(action(&v, v.tag())?)
|
||||||
} else {
|
} else {
|
||||||
let mut ret = v;
|
let mut ret = v;
|
||||||
|
|
||||||
for path in &column_paths {
|
for path in &options.column_paths {
|
||||||
ret = ret.swap_data_by_column_path(
|
ret = ret.swap_data_by_column_path(
|
||||||
path,
|
path,
|
||||||
Box::new(move |old| action(old, old.tag())),
|
Box::new(move |old| action(old, old.tag())),
|
||||||
@ -102,9 +103,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn downcases() {
|
fn downcases() {
|
||||||
let word = string("ANDRES");
|
let word = string("ANDRES");
|
||||||
let expected = string("andres");
|
|
||||||
|
|
||||||
let actual = action(&word, Tag::unknown()).unwrap();
|
let actual = action(&word, Tag::unknown()).unwrap();
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, string("andres"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,12 @@ use nu_protocol::{
|
|||||||
use nu_source::{Tag, Tagged};
|
use nu_source::{Tag, Tagged};
|
||||||
use nu_value_ext::ValueExt;
|
use nu_value_ext::ValueExt;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
pub struct SubCommand;
|
||||||
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
pattern: Tagged<String>,
|
pattern: Tagged<String>,
|
||||||
rest: Vec<ColumnPath>,
|
column_paths: Vec<ColumnPath>,
|
||||||
}
|
}
|
||||||
pub struct SubCommand;
|
|
||||||
|
|
||||||
impl WholeStreamCommand for SubCommand {
|
impl WholeStreamCommand for SubCommand {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
@ -47,22 +47,26 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let (Arguments { pattern, rest }, input) = args.process()?;
|
let (options, input) = args.extract(|params| {
|
||||||
|
Ok(Arc::new(Arguments {
|
||||||
let column_paths: Vec<_> = rest;
|
pattern: params.req(0)?,
|
||||||
|
column_paths: params.rest(1)?,
|
||||||
|
}))
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.map(move |v| {
|
.map(move |v| {
|
||||||
if column_paths.is_empty() {
|
if options.column_paths.is_empty() {
|
||||||
ReturnSuccess::value(action(&v, &pattern, v.tag())?)
|
ReturnSuccess::value(action(&v, &options.pattern, v.tag())?)
|
||||||
} else {
|
} else {
|
||||||
let mut ret = v;
|
let mut ret = v;
|
||||||
|
|
||||||
for path in &column_paths {
|
for path in &options.column_paths {
|
||||||
let pattern = pattern.clone();
|
let options = options.clone();
|
||||||
|
|
||||||
ret = ret.swap_data_by_column_path(
|
ret = ret.swap_data_by_column_path(
|
||||||
path,
|
path,
|
||||||
Box::new(move |old| action(old, &pattern, old.tag())),
|
Box::new(move |old| action(old, &options.pattern, old.tag())),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,12 +9,11 @@ use nu_source::{Tag, Tagged};
|
|||||||
use nu_value_ext::ValueExt;
|
use nu_value_ext::ValueExt;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
|
all: bool,
|
||||||
find: Tagged<String>,
|
find: Tagged<String>,
|
||||||
replace: Tagged<String>,
|
replace: Tagged<String>,
|
||||||
rest: Vec<ColumnPath>,
|
column_paths: Vec<ColumnPath>,
|
||||||
all: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
@ -59,35 +58,31 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
struct FindReplace<'a>(&'a str, &'a str);
|
||||||
struct FindReplace(String, String);
|
|
||||||
|
|
||||||
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let (
|
let (options, input) = args.extract(|params| {
|
||||||
Arguments {
|
Ok(Arc::new(Arguments {
|
||||||
find,
|
all: params.has_flag("all"),
|
||||||
replace,
|
find: params.req(0)?,
|
||||||
rest,
|
replace: params.req(1)?,
|
||||||
all,
|
column_paths: params.rest(2)?,
|
||||||
},
|
}))
|
||||||
input,
|
})?;
|
||||||
) = args.process()?;
|
|
||||||
let options = FindReplace(find.item, replace.item);
|
|
||||||
let column_paths: Vec<_> = rest;
|
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.map(move |v| {
|
.map(move |v| {
|
||||||
if column_paths.is_empty() {
|
if options.column_paths.is_empty() {
|
||||||
ReturnSuccess::value(action(&v, &options, v.tag(), all)?)
|
ReturnSuccess::value(action(&v, &options, v.tag())?)
|
||||||
} else {
|
} else {
|
||||||
let mut ret = v;
|
let mut ret = v;
|
||||||
|
|
||||||
for path in &column_paths {
|
for path in &options.column_paths {
|
||||||
let options = options.clone();
|
let options = options.clone();
|
||||||
|
|
||||||
ret = ret.swap_data_by_column_path(
|
ret = ret.swap_data_by_column_path(
|
||||||
path,
|
path,
|
||||||
Box::new(move |old| action(old, &options, old.tag(), all)),
|
Box::new(move |old| action(old, &options, old.tag())),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,29 +94,27 @@ fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
|
|
||||||
fn action(
|
fn action(
|
||||||
input: &Value,
|
input: &Value,
|
||||||
options: &FindReplace,
|
Arguments {
|
||||||
|
find, replace, all, ..
|
||||||
|
}: &Arguments,
|
||||||
tag: impl Into<Tag>,
|
tag: impl Into<Tag>,
|
||||||
all: bool,
|
|
||||||
) -> Result<Value, ShellError> {
|
) -> Result<Value, ShellError> {
|
||||||
match &input.value {
|
match &input.value {
|
||||||
UntaggedValue::Primitive(Primitive::String(s)) => {
|
UntaggedValue::Primitive(Primitive::String(s)) => {
|
||||||
let find = &options.0;
|
let FindReplace(find, replacement) = FindReplace(&find, &replace);
|
||||||
let replacement = &options.1;
|
let regex = Regex::new(find);
|
||||||
|
|
||||||
let regex = Regex::new(find.as_str());
|
Ok(match regex {
|
||||||
|
|
||||||
let out = match regex {
|
|
||||||
Ok(re) => {
|
Ok(re) => {
|
||||||
if all {
|
if *all {
|
||||||
UntaggedValue::string(re.replace_all(s, replacement.as_str()).to_owned())
|
UntaggedValue::string(re.replace_all(s, replacement).to_owned())
|
||||||
} else {
|
} else {
|
||||||
UntaggedValue::string(re.replace(s, replacement.as_str()).to_owned())
|
UntaggedValue::string(re.replace(s, replacement).to_owned())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_) => UntaggedValue::string(s),
|
Err(_) => UntaggedValue::string(s),
|
||||||
};
|
}
|
||||||
|
.into_value(tag))
|
||||||
Ok(out.into_value(tag))
|
|
||||||
}
|
}
|
||||||
other => {
|
other => {
|
||||||
let got = format!("got {}", other.type_name());
|
let got = format!("got {}", other.type_name());
|
||||||
@ -137,8 +130,8 @@ fn action(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::ShellError;
|
use super::ShellError;
|
||||||
use super::{action, FindReplace, SubCommand};
|
use super::{action, Arguments, SubCommand};
|
||||||
use nu_source::Tag;
|
use nu_source::{Tag, TaggedItem};
|
||||||
use nu_test_support::value::string;
|
use nu_test_support::value::string;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -151,11 +144,15 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn can_have_capture_groups() {
|
fn can_have_capture_groups() {
|
||||||
let word = string("Cargo.toml");
|
let word = string("Cargo.toml");
|
||||||
let expected = string("Carga.toml");
|
|
||||||
let all = false;
|
|
||||||
let find_replace_options = FindReplace("Cargo.(.+)".to_string(), "Carga.$1".to_string());
|
|
||||||
|
|
||||||
let actual = action(&word, &find_replace_options, Tag::unknown(), all).unwrap();
|
let options = Arguments {
|
||||||
assert_eq!(actual, expected);
|
find: String::from("Cargo.(.+)").tagged_unknown(),
|
||||||
|
replace: String::from("Carga.$1").tagged_unknown(),
|
||||||
|
column_paths: vec![],
|
||||||
|
all: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let actual = action(&word, &options, Tag::unknown()).unwrap();
|
||||||
|
assert_eq!(actual, string("Carga.toml"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,12 +14,10 @@ use std::iter;
|
|||||||
|
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
rest: Vec<ColumnPath>,
|
|
||||||
decimals: Option<Tagged<u64>>,
|
decimals: Option<Tagged<u64>>,
|
||||||
#[serde(rename(deserialize = "group-digits"))]
|
|
||||||
group_digits: bool,
|
group_digits: bool,
|
||||||
|
column_paths: Vec<ColumnPath>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WholeStreamCommand for SubCommand {
|
impl WholeStreamCommand for SubCommand {
|
||||||
@ -39,15 +37,6 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
"decimal digits to which to round",
|
"decimal digits to which to round",
|
||||||
Some('d'),
|
Some('d'),
|
||||||
)
|
)
|
||||||
/*
|
|
||||||
FIXME: this isn't currently supported because of num_format being out of date. Once it's updated, re-enable this
|
|
||||||
.switch(
|
|
||||||
"group-digits",
|
|
||||||
// TODO according to system localization
|
|
||||||
"group digits, currently by thousand with commas",
|
|
||||||
Some('g'),
|
|
||||||
)
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
@ -80,23 +69,28 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let (
|
let (options, input) = args.extract(|params| {
|
||||||
Arguments {
|
Ok(Arguments {
|
||||||
decimals,
|
decimals: if let Some(arg) = params.get_flag("decimals") {
|
||||||
group_digits,
|
Some(arg?)
|
||||||
rest: column_paths,
|
} else {
|
||||||
},
|
None
|
||||||
input,
|
},
|
||||||
) = args.process()?;
|
group_digits: false,
|
||||||
let digits = decimals.map(|tagged| tagged.item);
|
column_paths: params.rest_args()?,
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let digits = options.decimals.as_ref().map(|tagged| tagged.item);
|
||||||
|
let group_digits = options.group_digits;
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.map(move |v| {
|
.map(move |v| {
|
||||||
if column_paths.is_empty() {
|
if options.column_paths.is_empty() {
|
||||||
ReturnSuccess::value(action(&v, v.tag(), digits, group_digits)?)
|
ReturnSuccess::value(action(&v, v.tag(), digits, group_digits)?)
|
||||||
} else {
|
} else {
|
||||||
let mut ret = v;
|
let mut ret = v;
|
||||||
for path in &column_paths {
|
for path in &options.column_paths {
|
||||||
ret = ret.swap_data_by_column_path(
|
ret = ret.swap_data_by_column_path(
|
||||||
path,
|
path,
|
||||||
Box::new(move |old| action(old, old.tag(), digits, group_digits)),
|
Box::new(move |old| action(old, old.tag(), digits, group_digits)),
|
||||||
|
@ -8,12 +8,11 @@ use nu_protocol::{
|
|||||||
use nu_source::{Tag, Tagged};
|
use nu_source::{Tag, Tagged};
|
||||||
use nu_value_ext::{as_string, ValueExt};
|
use nu_value_ext::{as_string, ValueExt};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
pattern: Tagged<String>,
|
|
||||||
rest: Vec<ColumnPath>,
|
|
||||||
range: Option<Value>,
|
|
||||||
end: bool,
|
end: bool,
|
||||||
|
pattern: Tagged<String>,
|
||||||
|
range: Option<Value>,
|
||||||
|
column_paths: Vec<ColumnPath>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
@ -91,33 +90,32 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let (
|
let (options, input) = args.extract(|params| {
|
||||||
Arguments {
|
Ok(Arc::new(Arguments {
|
||||||
pattern,
|
pattern: params.req(0)?,
|
||||||
rest,
|
range: if let Some(arg) = params.get_flag("range") {
|
||||||
range,
|
Some(arg?)
|
||||||
end,
|
} else {
|
||||||
},
|
None
|
||||||
input,
|
},
|
||||||
) = args.process()?;
|
end: params.has_flag("end"),
|
||||||
let range = range.unwrap_or_else(|| {
|
column_paths: params.rest(1)?,
|
||||||
UntaggedValue::Primitive(Primitive::String("".to_string())).into_untagged_value()
|
}))
|
||||||
});
|
})?;
|
||||||
let column_paths: Vec<_> = rest;
|
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.map(move |v| {
|
.map(move |v| {
|
||||||
if column_paths.is_empty() {
|
if options.column_paths.is_empty() {
|
||||||
ReturnSuccess::value(action(&v, &pattern, &range, end, v.tag())?)
|
ReturnSuccess::value(action(&v, &options, v.tag())?)
|
||||||
} else {
|
} else {
|
||||||
let mut ret = v;
|
let mut ret = v;
|
||||||
|
|
||||||
for path in &column_paths {
|
for path in &options.column_paths {
|
||||||
let range = range.clone();
|
let options = options.clone();
|
||||||
let pattern = pattern.clone();
|
|
||||||
ret = ret.swap_data_by_column_path(
|
ret = ret.swap_data_by_column_path(
|
||||||
path,
|
path,
|
||||||
Box::new(move |old| action(old, &pattern, &range, end, old.tag())),
|
Box::new(move |old| action(old, &options, old.tag())),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,29 +127,38 @@ fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
|
|
||||||
fn action(
|
fn action(
|
||||||
input: &Value,
|
input: &Value,
|
||||||
pattern: &str,
|
Arguments {
|
||||||
range: &Value,
|
ref pattern,
|
||||||
end: bool,
|
range,
|
||||||
|
end,
|
||||||
|
..
|
||||||
|
}: &Arguments,
|
||||||
tag: impl Into<Tag>,
|
tag: impl Into<Tag>,
|
||||||
) -> Result<Value, ShellError> {
|
) -> Result<Value, ShellError> {
|
||||||
|
let tag = tag.into();
|
||||||
|
|
||||||
|
let range = match range {
|
||||||
|
Some(range) => range.clone(),
|
||||||
|
None => UntaggedValue::string("").into_value(&tag),
|
||||||
|
};
|
||||||
|
|
||||||
let r = process_range(&input, &range)?;
|
let r = process_range(&input, &range)?;
|
||||||
|
|
||||||
match &input.value {
|
match &input.value {
|
||||||
UntaggedValue::Primitive(Primitive::String(s)) => {
|
UntaggedValue::Primitive(Primitive::String(s)) => {
|
||||||
let start_index = r.0 as usize;
|
let start_index = r.0 as usize;
|
||||||
let end_index = r.1 as usize;
|
let end_index = r.1 as usize;
|
||||||
|
|
||||||
if end {
|
if *end {
|
||||||
if let Some(result) = s[start_index..end_index].rfind(pattern) {
|
if let Some(result) = s[start_index..end_index].rfind(&**pattern) {
|
||||||
Ok(UntaggedValue::int(result + start_index).into_value(tag))
|
Ok(UntaggedValue::int(result + start_index).into_value(tag))
|
||||||
} else {
|
} else {
|
||||||
let not_found = -1;
|
Ok(UntaggedValue::int(-1).into_value(tag))
|
||||||
Ok(UntaggedValue::int(not_found).into_value(tag))
|
|
||||||
}
|
}
|
||||||
} else if let Some(result) = s[start_index..end_index].find(pattern) {
|
} else if let Some(result) = s[start_index..end_index].find(&**pattern) {
|
||||||
Ok(UntaggedValue::int(result + start_index).into_value(tag))
|
Ok(UntaggedValue::int(result + start_index).into_value(tag))
|
||||||
} else {
|
} else {
|
||||||
let not_found = -1;
|
Ok(UntaggedValue::int(-1).into_value(tag))
|
||||||
Ok(UntaggedValue::int(not_found).into_value(tag))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
other => {
|
other => {
|
||||||
@ -159,7 +166,7 @@ fn action(
|
|||||||
Err(ShellError::labeled_error(
|
Err(ShellError::labeled_error(
|
||||||
"value is not string",
|
"value is not string",
|
||||||
got,
|
got,
|
||||||
tag.into().span,
|
tag.span,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -234,10 +241,9 @@ fn process_range(input: &Value, range: &Value) -> Result<IndexOfOptionalBounds,
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::ShellError;
|
use super::ShellError;
|
||||||
use super::{action, SubCommand};
|
use super::{action, Arguments, SubCommand};
|
||||||
use nu_protocol::{Primitive, UntaggedValue};
|
use nu_source::{Tag, TaggedItem};
|
||||||
use nu_source::Tag;
|
use nu_test_support::value::{int, string};
|
||||||
use nu_test_support::value::string;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||||
@ -249,76 +255,90 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn returns_index_of_substring() {
|
fn returns_index_of_substring() {
|
||||||
let word = string("Cargo.tomL");
|
let word = string("Cargo.tomL");
|
||||||
let pattern = ".tomL";
|
|
||||||
let end = false;
|
|
||||||
let index_of_bounds =
|
|
||||||
UntaggedValue::Primitive(Primitive::String("".to_string())).into_untagged_value();
|
|
||||||
let expected = UntaggedValue::Primitive(Primitive::Int(5.into())).into_untagged_value();
|
|
||||||
|
|
||||||
let actual = action(&word, &pattern, &index_of_bounds, end, Tag::unknown()).unwrap();
|
let options = Arguments {
|
||||||
assert_eq!(actual, expected);
|
pattern: String::from(".tomL").tagged_unknown(),
|
||||||
|
range: Some(string("")),
|
||||||
|
column_paths: vec![],
|
||||||
|
end: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let actual = action(&word, &options, Tag::unknown()).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(actual, int(5));
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn index_of_does_not_exist_in_string() {
|
fn index_of_does_not_exist_in_string() {
|
||||||
let word = string("Cargo.tomL");
|
let word = string("Cargo.tomL");
|
||||||
let pattern = "Lm";
|
|
||||||
let end = false;
|
|
||||||
let index_of_bounds =
|
|
||||||
UntaggedValue::Primitive(Primitive::String("".to_string())).into_untagged_value();
|
|
||||||
let expected = UntaggedValue::Primitive(Primitive::Int((-1).into())).into_untagged_value();
|
|
||||||
|
|
||||||
let actual = action(&word, &pattern, &index_of_bounds, end, Tag::unknown()).unwrap();
|
let options = Arguments {
|
||||||
assert_eq!(actual, expected);
|
pattern: String::from("Lm").tagged_unknown(),
|
||||||
|
range: Some(string("")),
|
||||||
|
column_paths: vec![],
|
||||||
|
end: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let actual = action(&word, &options, Tag::unknown()).unwrap();
|
||||||
|
assert_eq!(actual, int(-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn returns_index_of_next_substring() {
|
fn returns_index_of_next_substring() {
|
||||||
let word = string("Cargo.Cargo");
|
let word = string("Cargo.Cargo");
|
||||||
let pattern = "Cargo";
|
|
||||||
let end = false;
|
|
||||||
let index_of_bounds =
|
|
||||||
UntaggedValue::Primitive(Primitive::String("1,".to_string())).into_untagged_value();
|
|
||||||
let expected = UntaggedValue::Primitive(Primitive::Int(6.into())).into_untagged_value();
|
|
||||||
|
|
||||||
let actual = action(&word, &pattern, &index_of_bounds, end, Tag::unknown()).unwrap();
|
let options = Arguments {
|
||||||
assert_eq!(actual, expected);
|
pattern: String::from("Cargo").tagged_unknown(),
|
||||||
|
range: Some(string("1,")),
|
||||||
|
column_paths: vec![],
|
||||||
|
end: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let actual = action(&word, &options, Tag::unknown()).unwrap();
|
||||||
|
assert_eq!(actual, int(6));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn index_does_not_exist_due_to_end_index() {
|
fn index_does_not_exist_due_to_end_index() {
|
||||||
let word = string("Cargo.Banana");
|
let word = string("Cargo.Banana");
|
||||||
let pattern = "Banana";
|
|
||||||
let end = false;
|
|
||||||
let index_of_bounds =
|
|
||||||
UntaggedValue::Primitive(Primitive::String(",5".to_string())).into_untagged_value();
|
|
||||||
let expected = UntaggedValue::Primitive(Primitive::Int((-1).into())).into_untagged_value();
|
|
||||||
|
|
||||||
let actual = action(&word, &pattern, &index_of_bounds, end, Tag::unknown()).unwrap();
|
let options = Arguments {
|
||||||
assert_eq!(actual, expected);
|
pattern: String::from("Banana").tagged_unknown(),
|
||||||
|
range: Some(string(",5")),
|
||||||
|
column_paths: vec![],
|
||||||
|
end: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let actual = action(&word, &options, Tag::unknown()).unwrap();
|
||||||
|
assert_eq!(actual, int(-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn returns_index_of_nums_in_middle_due_to_index_limit_from_both_ends() {
|
fn returns_index_of_nums_in_middle_due_to_index_limit_from_both_ends() {
|
||||||
let word = string("123123123");
|
let word = string("123123123");
|
||||||
let pattern = "123";
|
|
||||||
let end = false;
|
|
||||||
let index_of_bounds =
|
|
||||||
UntaggedValue::Primitive(Primitive::String("2,6".to_string())).into_untagged_value();
|
|
||||||
let expected = UntaggedValue::Primitive(Primitive::Int(3.into())).into_untagged_value();
|
|
||||||
|
|
||||||
let actual = action(&word, &pattern, &index_of_bounds, end, Tag::unknown()).unwrap();
|
let options = Arguments {
|
||||||
assert_eq!(actual, expected);
|
pattern: String::from("123").tagged_unknown(),
|
||||||
|
range: Some(string("2,6")),
|
||||||
|
column_paths: vec![],
|
||||||
|
end: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let actual = action(&word, &options, Tag::unknown()).unwrap();
|
||||||
|
assert_eq!(actual, int(3));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn index_does_not_exists_due_to_strict_bounds() {
|
fn index_does_not_exists_due_to_strict_bounds() {
|
||||||
let word = string("123456");
|
let word = string("123456");
|
||||||
let pattern = "1";
|
|
||||||
let end = false;
|
|
||||||
let index_of_bounds =
|
|
||||||
UntaggedValue::Primitive(Primitive::String("2,4".to_string())).into_untagged_value();
|
|
||||||
let expected = UntaggedValue::Primitive(Primitive::Int((-1).into())).into_untagged_value();
|
|
||||||
|
|
||||||
let actual = action(&word, &pattern, &index_of_bounds, end, Tag::unknown()).unwrap();
|
let options = Arguments {
|
||||||
assert_eq!(actual, expected);
|
pattern: String::from("1").tagged_unknown(),
|
||||||
|
range: Some(string("2,4")),
|
||||||
|
column_paths: vec![],
|
||||||
|
end: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let actual = action(&word, &options, Tag::unknown()).unwrap();
|
||||||
|
assert_eq!(actual, int(-1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,8 @@ use nu_protocol::{
|
|||||||
|
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
rest: Vec<ColumnPath>,
|
column_paths: Vec<ColumnPath>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WholeStreamCommand for SubCommand {
|
impl WholeStreamCommand for SubCommand {
|
||||||
@ -53,17 +52,20 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let (Arguments { rest }, input) = args.process()?;
|
let (options, input) = args.extract(|params| {
|
||||||
let column_paths: Vec<_> = rest;
|
Ok(Arguments {
|
||||||
|
column_paths: params.rest_args()?,
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.map(move |v| {
|
.map(move |v| {
|
||||||
if column_paths.is_empty() {
|
if options.column_paths.is_empty() {
|
||||||
ReturnSuccess::value(action(&v, v.tag())?)
|
ReturnSuccess::value(action(&v, v.tag())?)
|
||||||
} else {
|
} else {
|
||||||
let mut ret = v;
|
let mut ret = v;
|
||||||
|
|
||||||
for path in &column_paths {
|
for path in &options.column_paths {
|
||||||
ret = ret.swap_data_by_column_path(
|
ret = ret.swap_data_by_column_path(
|
||||||
path,
|
path,
|
||||||
Box::new(move |old| action(old, old.tag())),
|
Box::new(move |old| action(old, old.tag())),
|
||||||
|
@ -8,11 +8,10 @@ use nu_protocol::{
|
|||||||
use nu_source::{Tag, Tagged};
|
use nu_source::{Tag, Tagged};
|
||||||
use nu_value_ext::ValueExt;
|
use nu_value_ext::ValueExt;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
length: Tagged<usize>,
|
length: Tagged<usize>,
|
||||||
character: Tagged<String>,
|
character: Tagged<String>,
|
||||||
rest: Vec<ColumnPath>,
|
column_paths: Vec<ColumnPath>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
@ -78,30 +77,27 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let (
|
let (options, input) = args.extract(|params| {
|
||||||
Arguments {
|
Ok(Arc::new(Arguments {
|
||||||
length,
|
length: params.req_named("length")?,
|
||||||
character,
|
character: params.req_named("character")?,
|
||||||
rest,
|
column_paths: params.rest_args()?,
|
||||||
},
|
}))
|
||||||
input,
|
})?;
|
||||||
) = args.process()?;
|
|
||||||
let column_paths: Vec<_> = rest;
|
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.map(move |v| {
|
.map(move |v| {
|
||||||
let len = length.item;
|
if options.column_paths.is_empty() {
|
||||||
let character = character.item.clone();
|
ReturnSuccess::value(action(&v, &options, v.tag())?)
|
||||||
if column_paths.is_empty() {
|
|
||||||
ReturnSuccess::value(action(&v, len, character, v.tag())?)
|
|
||||||
} else {
|
} else {
|
||||||
let mut ret = v;
|
let mut ret = v;
|
||||||
|
|
||||||
for path in &column_paths {
|
for path in &options.column_paths {
|
||||||
let str_clone = character.clone();
|
let options = options.clone();
|
||||||
|
|
||||||
ret = ret.swap_data_by_column_path(
|
ret = ret.swap_data_by_column_path(
|
||||||
path,
|
path,
|
||||||
Box::new(move |old| action(old, len, str_clone, old.tag())),
|
Box::new(move |old| action(old, &options, old.tag())),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,19 +109,20 @@ fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
|
|
||||||
fn action(
|
fn action(
|
||||||
input: &Value,
|
input: &Value,
|
||||||
length: usize,
|
Arguments {
|
||||||
character: String,
|
character, length, ..
|
||||||
|
}: &Arguments,
|
||||||
tag: impl Into<Tag>,
|
tag: impl Into<Tag>,
|
||||||
) -> Result<Value, ShellError> {
|
) -> Result<Value, ShellError> {
|
||||||
match &input.value {
|
match &input.value {
|
||||||
UntaggedValue::Primitive(Primitive::String(s)) => {
|
UntaggedValue::Primitive(Primitive::String(s)) => {
|
||||||
if length < s.len() {
|
if **length < s.len() {
|
||||||
Ok(
|
Ok(
|
||||||
UntaggedValue::string(s.chars().take(length).collect::<String>())
|
UntaggedValue::string(s.chars().take(**length).collect::<String>())
|
||||||
.into_value(tag),
|
.into_value(tag),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let mut res = character.repeat(length - s.chars().count());
|
let mut res = character.repeat(**length - s.chars().count());
|
||||||
res += s.as_ref();
|
res += s.as_ref();
|
||||||
Ok(UntaggedValue::string(res).into_value(tag))
|
Ok(UntaggedValue::string(res).into_value(tag))
|
||||||
}
|
}
|
||||||
@ -143,10 +140,10 @@ fn action(
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{action, SubCommand};
|
use super::{action, Arguments, SubCommand};
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::UntaggedValue;
|
use nu_protocol::UntaggedValue;
|
||||||
use nu_source::Tag;
|
use nu_source::{Tag, TaggedItem};
|
||||||
use nu_test_support::value::string;
|
use nu_test_support::value::string;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -159,22 +156,32 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn left_pad_with_zeros() {
|
fn left_pad_with_zeros() {
|
||||||
let word = string("123");
|
let word = string("123");
|
||||||
let pad_char = '0'.to_string();
|
|
||||||
let pad_len = 10;
|
|
||||||
let expected = UntaggedValue::string("0000000123").into_untagged_value();
|
|
||||||
|
|
||||||
let actual = action(&word, pad_len, pad_char, Tag::unknown()).unwrap();
|
let options = Arguments {
|
||||||
|
character: String::from("0").tagged_unknown(),
|
||||||
|
length: 10_usize.tagged_unknown(),
|
||||||
|
column_paths: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected = UntaggedValue::string("0000000123").into_untagged_value();
|
||||||
|
let actual = action(&word, &options, Tag::unknown()).unwrap();
|
||||||
|
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn left_pad_but_truncate() {
|
fn left_pad_but_truncate() {
|
||||||
let word = string("123456789");
|
let word = string("123456789");
|
||||||
let pad_char = '0'.to_string();
|
|
||||||
let pad_len = 3;
|
|
||||||
let expected = UntaggedValue::string("123").into_untagged_value();
|
|
||||||
|
|
||||||
let actual = action(&word, pad_len, pad_char, Tag::unknown()).unwrap();
|
let options = Arguments {
|
||||||
|
character: String::from("0").tagged_unknown(),
|
||||||
|
length: 3_usize.tagged_unknown(),
|
||||||
|
column_paths: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected = UntaggedValue::string("123").into_untagged_value();
|
||||||
|
let actual = action(&word, &options, Tag::unknown()).unwrap();
|
||||||
|
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,8 @@ use nu_protocol::{
|
|||||||
|
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
rest: Vec<ColumnPath>,
|
column_paths: Vec<ColumnPath>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WholeStreamCommand for SubCommand {
|
impl WholeStreamCommand for SubCommand {
|
||||||
@ -43,17 +42,20 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let (Arguments { rest }, input) = args.process()?;
|
let (options, input) = args.extract(|params| {
|
||||||
let column_paths: Vec<_> = rest;
|
Ok(Arguments {
|
||||||
|
column_paths: params.rest_args()?,
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.map(move |v| {
|
.map(move |v| {
|
||||||
if column_paths.is_empty() {
|
if options.column_paths.is_empty() {
|
||||||
ReturnSuccess::value(action(&v, v.tag())?)
|
ReturnSuccess::value(action(&v, v.tag())?)
|
||||||
} else {
|
} else {
|
||||||
let mut ret = v;
|
let mut ret = v;
|
||||||
|
|
||||||
for path in &column_paths {
|
for path in &options.column_paths {
|
||||||
ret = ret.swap_data_by_column_path(
|
ret = ret.swap_data_by_column_path(
|
||||||
path,
|
path,
|
||||||
Box::new(move |old| action(old, old.tag())),
|
Box::new(move |old| action(old, old.tag())),
|
||||||
|
@ -8,11 +8,10 @@ use nu_protocol::{
|
|||||||
use nu_source::{Tag, Tagged};
|
use nu_source::{Tag, Tagged};
|
||||||
use nu_value_ext::ValueExt;
|
use nu_value_ext::ValueExt;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
length: Tagged<usize>,
|
length: Tagged<usize>,
|
||||||
character: Tagged<String>,
|
character: Tagged<String>,
|
||||||
rest: Vec<ColumnPath>,
|
column_paths: Vec<ColumnPath>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
@ -78,30 +77,27 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let (
|
let (options, input) = args.extract(|params| {
|
||||||
Arguments {
|
Ok(Arc::new(Arguments {
|
||||||
length,
|
length: params.req_named("length")?,
|
||||||
character,
|
character: params.req_named("character")?,
|
||||||
rest,
|
column_paths: params.rest_args()?,
|
||||||
},
|
}))
|
||||||
input,
|
})?;
|
||||||
) = args.process()?;
|
|
||||||
let column_paths: Vec<_> = rest;
|
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.map(move |v| {
|
.map(move |v| {
|
||||||
let len = length.item;
|
if options.column_paths.is_empty() {
|
||||||
let character = character.item.clone();
|
ReturnSuccess::value(action(&v, &options, v.tag())?)
|
||||||
if column_paths.is_empty() {
|
|
||||||
ReturnSuccess::value(action(&v, len, character, v.tag())?)
|
|
||||||
} else {
|
} else {
|
||||||
let mut ret = v;
|
let mut ret = v;
|
||||||
|
|
||||||
for path in &column_paths {
|
for path in &options.column_paths {
|
||||||
let str_clone = character.clone();
|
let options = options.clone();
|
||||||
|
|
||||||
ret = ret.swap_data_by_column_path(
|
ret = ret.swap_data_by_column_path(
|
||||||
path,
|
path,
|
||||||
Box::new(move |old| action(old, len, str_clone, old.tag())),
|
Box::new(move |old| action(old, &options, old.tag())),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,20 +109,21 @@ fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||||||
|
|
||||||
fn action(
|
fn action(
|
||||||
input: &Value,
|
input: &Value,
|
||||||
length: usize,
|
Arguments {
|
||||||
character: String,
|
length, character, ..
|
||||||
|
}: &Arguments,
|
||||||
tag: impl Into<Tag>,
|
tag: impl Into<Tag>,
|
||||||
) -> Result<Value, ShellError> {
|
) -> Result<Value, ShellError> {
|
||||||
match &input.value {
|
match &input.value {
|
||||||
UntaggedValue::Primitive(Primitive::String(s)) => {
|
UntaggedValue::Primitive(Primitive::String(s)) => {
|
||||||
if length < s.len() {
|
if **length < s.len() {
|
||||||
Ok(
|
Ok(
|
||||||
UntaggedValue::string(s.chars().take(length).collect::<String>())
|
UntaggedValue::string(s.chars().take(**length).collect::<String>())
|
||||||
.into_value(tag),
|
.into_value(tag),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let mut res = s.to_string();
|
let mut res = s.to_string();
|
||||||
res += character.repeat(length - s.chars().count()).as_str();
|
res += character.repeat(**length - s.chars().count()).as_str();
|
||||||
Ok(UntaggedValue::string(res).into_value(tag))
|
Ok(UntaggedValue::string(res).into_value(tag))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -143,10 +140,10 @@ fn action(
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{action, SubCommand};
|
use super::{action, Arguments, SubCommand};
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::UntaggedValue;
|
use nu_protocol::UntaggedValue;
|
||||||
use nu_source::Tag;
|
use nu_source::{Tag, TaggedItem};
|
||||||
use nu_test_support::value::string;
|
use nu_test_support::value::string;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -159,22 +156,32 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn right_pad_with_zeros() {
|
fn right_pad_with_zeros() {
|
||||||
let word = string("123");
|
let word = string("123");
|
||||||
let pad_char = '0'.to_string();
|
|
||||||
let pad_len = 10;
|
|
||||||
let expected = UntaggedValue::string("1230000000").into_untagged_value();
|
|
||||||
|
|
||||||
let actual = action(&word, pad_len, pad_char, Tag::unknown()).unwrap();
|
let options = Arguments {
|
||||||
|
character: String::from("0").tagged_unknown(),
|
||||||
|
length: 10_usize.tagged_unknown(),
|
||||||
|
column_paths: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected = UntaggedValue::string("1230000000").into_untagged_value();
|
||||||
|
let actual = action(&word, &options, Tag::unknown()).unwrap();
|
||||||
|
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn right_pad_but_truncate() {
|
fn right_pad_but_truncate() {
|
||||||
let word = string("123456789");
|
let word = string("123456789");
|
||||||
let pad_char = '0'.to_string();
|
|
||||||
let pad_len = 3;
|
|
||||||
let expected = UntaggedValue::string("123").into_untagged_value();
|
|
||||||
|
|
||||||
let actual = action(&word, pad_len, pad_char, Tag::unknown()).unwrap();
|
let options = Arguments {
|
||||||
|
character: String::from("0").tagged_unknown(),
|
||||||
|
length: 3_usize.tagged_unknown(),
|
||||||
|
column_paths: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected = UntaggedValue::string("123").into_untagged_value();
|
||||||
|
let actual = action(&word, &options, Tag::unknown()).unwrap();
|
||||||
|
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,12 @@ use nu_protocol::{
|
|||||||
use nu_source::{Tag, Tagged};
|
use nu_source::{Tag, Tagged};
|
||||||
use nu_value_ext::ValueExt;
|
use nu_value_ext::ValueExt;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
pub struct SubCommand;
|
||||||
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
pattern: Tagged<String>,
|
pattern: Tagged<String>,
|
||||||
rest: Vec<ColumnPath>,
|
column_paths: Vec<ColumnPath>,
|
||||||
}
|
}
|
||||||
pub struct SubCommand;
|
|
||||||
|
|
||||||
impl WholeStreamCommand for SubCommand {
|
impl WholeStreamCommand for SubCommand {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
@ -47,22 +47,26 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let (Arguments { pattern, rest }, input) = args.process()?;
|
let (options, input) = args.extract(|params| {
|
||||||
|
Ok(Arc::new(Arguments {
|
||||||
let column_paths: Vec<_> = rest;
|
pattern: params.req(0)?,
|
||||||
|
column_paths: params.rest(1)?,
|
||||||
|
}))
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.map(move |v| {
|
.map(move |v| {
|
||||||
if column_paths.is_empty() {
|
if options.column_paths.is_empty() {
|
||||||
ReturnSuccess::value(action(&v, &pattern, v.tag())?)
|
ReturnSuccess::value(action(&v, &options.pattern, v.tag())?)
|
||||||
} else {
|
} else {
|
||||||
let mut ret = v;
|
let mut ret = v;
|
||||||
|
|
||||||
for path in &column_paths {
|
for path in &options.column_paths {
|
||||||
let pattern = pattern.clone();
|
let options = options.clone();
|
||||||
|
|
||||||
ret = ret.swap_data_by_column_path(
|
ret = ret.swap_data_by_column_path(
|
||||||
path,
|
path,
|
||||||
Box::new(move |old| action(old, &pattern, old.tag())),
|
Box::new(move |old| action(old, &options.pattern, old.tag())),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,10 +11,9 @@ use nu_value_ext::{as_string, ValueExt};
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
range: Value,
|
range: Value,
|
||||||
rest: Vec<ColumnPath>,
|
column_paths: Vec<ColumnPath>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
@ -90,24 +89,28 @@ struct SubstringText(String, String);
|
|||||||
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let name = args.call_info.name_tag.clone();
|
let name = args.call_info.name_tag.clone();
|
||||||
|
|
||||||
let (Arguments { range, rest }, input) = args.process()?;
|
let (options, input) = args.extract(|params| {
|
||||||
|
Ok(Arguments {
|
||||||
|
range: params.req(0)?,
|
||||||
|
column_paths: params.rest(1)?,
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
let column_paths: Vec<_> = rest;
|
let indexes = Arc::new(process_arguments(&options, name)?.into());
|
||||||
let options = process_arguments(range, name)?.into();
|
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.map(move |v| {
|
.map(move |v| {
|
||||||
if column_paths.is_empty() {
|
if options.column_paths.is_empty() {
|
||||||
ReturnSuccess::value(action(&v, &options, v.tag())?)
|
ReturnSuccess::value(action(&v, &indexes, v.tag())?)
|
||||||
} else {
|
} else {
|
||||||
let mut ret = v;
|
let mut ret = v;
|
||||||
|
|
||||||
for path in &column_paths {
|
for path in &options.column_paths {
|
||||||
let options = options.clone();
|
let indexes = indexes.clone();
|
||||||
|
|
||||||
ret = ret.swap_data_by_column_path(
|
ret = ret.swap_data_by_column_path(
|
||||||
path,
|
path,
|
||||||
Box::new(move |old| action(old, &options, old.tag())),
|
Box::new(move |old| action(old, &indexes, old.tag())),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,10 +177,13 @@ fn action(input: &Value, options: &Substring, tag: impl Into<Tag>) -> Result<Val
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_arguments(range: Value, name: impl Into<Tag>) -> Result<(isize, isize), ShellError> {
|
fn process_arguments(
|
||||||
|
options: &Arguments,
|
||||||
|
name: impl Into<Tag>,
|
||||||
|
) -> Result<(isize, isize), ShellError> {
|
||||||
let name = name.into();
|
let name = name.into();
|
||||||
|
|
||||||
let search = match &range.value {
|
let search = match &options.range.value {
|
||||||
UntaggedValue::Table(indexes) => {
|
UntaggedValue::Table(indexes) => {
|
||||||
if indexes.len() > 2 {
|
if indexes.len() > 2 {
|
||||||
Err(ShellError::labeled_error(
|
Err(ShellError::labeled_error(
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use crate::utils::arguments::arguments;
|
||||||
use nu_engine::WholeStreamCommand;
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
@ -10,12 +11,11 @@ use nu_value_ext::ValueExt;
|
|||||||
|
|
||||||
use chrono::{DateTime, FixedOffset, Local, LocalResult, Offset, TimeZone, Utc};
|
use chrono::{DateTime, FixedOffset, Local, LocalResult, Offset, TimeZone, Utc};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
timezone: Option<Tagged<String>>,
|
timezone: Option<Tagged<String>>,
|
||||||
offset: Option<Tagged<i16>>,
|
offset: Option<Tagged<i16>>,
|
||||||
format: Option<Tagged<String>>,
|
format: Option<Tagged<String>>,
|
||||||
rest: Vec<ColumnPath>,
|
column_paths: Vec<ColumnPath>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// In case it may be confused with chrono::TimeZone
|
// In case it may be confused with chrono::TimeZone
|
||||||
@ -78,7 +78,7 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
Some('f'),
|
Some('f'),
|
||||||
)
|
)
|
||||||
.rest(
|
.rest(
|
||||||
SyntaxShape::ColumnPath,
|
SyntaxShape::Any,
|
||||||
"optionally convert text into datetime by column paths",
|
"optionally convert text into datetime by column paths",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -127,55 +127,62 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
struct DatetimeFormat(String);
|
struct DatetimeFormat(String);
|
||||||
|
|
||||||
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let (
|
let (options, input) = args.extract(|params| {
|
||||||
Arguments {
|
let (column_paths, _) = arguments(&mut params.rest_args()?)?;
|
||||||
timezone,
|
|
||||||
offset,
|
|
||||||
format,
|
|
||||||
rest,
|
|
||||||
},
|
|
||||||
input,
|
|
||||||
) = args.process()?;
|
|
||||||
|
|
||||||
let column_paths: Vec<_> = rest;
|
Ok(Arguments {
|
||||||
|
timezone: if let Some(arg) = params.get_flag("timezone") {
|
||||||
|
Some(arg?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
offset: if let Some(arg) = params.get_flag("offset") {
|
||||||
|
Some(arg?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
format: if let Some(arg) = params.get_flag("format") {
|
||||||
|
Some(arg?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
column_paths,
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
// if zone-offset is specified, then zone will be neglected
|
// if zone-offset is specified, then zone will be neglected
|
||||||
let zone_options = if let Some(Tagged {
|
let zone_options = if let Some(Tagged {
|
||||||
item: zone_offset,
|
item: zone_offset,
|
||||||
tag: _tag,
|
tag,
|
||||||
}) = offset
|
}) = &options.offset
|
||||||
{
|
{
|
||||||
Some(Tagged {
|
Some(Tagged {
|
||||||
item: Zone::new(zone_offset),
|
item: Zone::new(*zone_offset),
|
||||||
tag: _tag,
|
tag: tag.into(),
|
||||||
})
|
})
|
||||||
} else if let Some(Tagged {
|
} else if let Some(Tagged { item: zone, tag }) = &options.timezone {
|
||||||
item: zone,
|
|
||||||
tag: _tag,
|
|
||||||
}) = timezone
|
|
||||||
{
|
|
||||||
Some(Tagged {
|
Some(Tagged {
|
||||||
item: Zone::from_string(zone),
|
item: Zone::from_string(zone.clone()),
|
||||||
tag: _tag,
|
tag: tag.into(),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let format_options = if let Some(Tagged { item: fmt, .. }) = format {
|
let format_options = if let Some(Tagged { item: fmt, .. }) = &options.format {
|
||||||
Some(DatetimeFormat(fmt))
|
Some(DatetimeFormat(fmt.to_string()))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.map(move |v| {
|
.map(move |v| {
|
||||||
if column_paths.is_empty() {
|
if options.column_paths.is_empty() {
|
||||||
ReturnSuccess::value(action(&v, &zone_options, &format_options, v.tag())?)
|
ReturnSuccess::value(action(&v, &zone_options, &format_options, v.tag())?)
|
||||||
} else {
|
} else {
|
||||||
let mut ret = v;
|
let mut ret = v;
|
||||||
|
|
||||||
for path in &column_paths {
|
for path in &options.column_paths {
|
||||||
let zone_options = zone_options.clone();
|
let zone_options = zone_options.clone();
|
||||||
let format_options = format_options.clone();
|
let format_options = format_options.clone();
|
||||||
|
|
||||||
|
@ -11,9 +11,8 @@ use nu_value_ext::ValueExt;
|
|||||||
use bigdecimal::BigDecimal;
|
use bigdecimal::BigDecimal;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
rest: Vec<ColumnPath>,
|
column_paths: Vec<ColumnPath>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
@ -48,18 +47,20 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let (Arguments { rest }, input) = args.process()?;
|
let (options, input) = args.extract(|params| {
|
||||||
|
Ok(Arguments {
|
||||||
let column_paths: Vec<_> = rest;
|
column_paths: params.rest_args()?,
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.map(move |v| {
|
.map(move |v| {
|
||||||
if column_paths.is_empty() {
|
if options.column_paths.is_empty() {
|
||||||
ReturnSuccess::value(action(&v, v.tag())?)
|
ReturnSuccess::value(action(&v, v.tag())?)
|
||||||
} else {
|
} else {
|
||||||
let mut ret = v;
|
let mut ret = v;
|
||||||
|
|
||||||
for path in &column_paths {
|
for path in &options.column_paths {
|
||||||
ret = ret.swap_data_by_column_path(
|
ret = ret.swap_data_by_column_path(
|
||||||
path,
|
path,
|
||||||
Box::new(move |old| action(old, old.tag())),
|
Box::new(move |old| action(old, old.tag())),
|
||||||
|
@ -3,17 +3,18 @@ use crate::utils::arguments::arguments;
|
|||||||
use nu_engine::WholeStreamCommand;
|
use nu_engine::WholeStreamCommand;
|
||||||
use nu_errors::ShellError;
|
use nu_errors::ShellError;
|
||||||
use nu_protocol::ShellTypeName;
|
use nu_protocol::ShellTypeName;
|
||||||
use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
use nu_protocol::{
|
||||||
|
ColumnPath, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,
|
||||||
|
};
|
||||||
use nu_source::{Tag, Tagged};
|
use nu_source::{Tag, Tagged};
|
||||||
use nu_value_ext::ValueExt;
|
use nu_value_ext::ValueExt;
|
||||||
|
|
||||||
use num_bigint::BigInt;
|
use num_bigint::BigInt;
|
||||||
use num_traits::Num;
|
use num_traits::Num;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
rest: Vec<Value>,
|
|
||||||
radix: Option<Tagged<u32>>,
|
radix: Option<Tagged<u32>>,
|
||||||
|
column_paths: Vec<ColumnPath>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
@ -67,19 +68,29 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let (Arguments { mut rest, radix }, input) = args.process()?;
|
let (options, input) = args.extract(|params| {
|
||||||
let (column_paths, _) = arguments(&mut rest)?;
|
let (column_paths, _) = arguments(&mut params.rest_args()?)?;
|
||||||
|
|
||||||
let radix = radix.map(|r| r.item).unwrap_or(10);
|
Ok(Arguments {
|
||||||
|
radix: if let Some(arg) = params.get_flag("radix") {
|
||||||
|
Some(arg?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
column_paths,
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let radix = options.radix.as_ref().map(|r| r.item).unwrap_or(10);
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.map(move |v| {
|
.map(move |v| {
|
||||||
if column_paths.is_empty() {
|
if options.column_paths.is_empty() {
|
||||||
ReturnSuccess::value(action(&v, v.tag(), radix)?)
|
ReturnSuccess::value(action(&v, v.tag(), radix)?)
|
||||||
} else {
|
} else {
|
||||||
let mut ret = v;
|
let mut ret = v;
|
||||||
|
|
||||||
for path in &column_paths {
|
for path in &options.column_paths {
|
||||||
ret = ret.swap_data_by_column_path(
|
ret = ret.swap_data_by_column_path(
|
||||||
path,
|
path,
|
||||||
Box::new(move |old| action(old, old.tag(), radix)),
|
Box::new(move |old| action(old, old.tag(), radix)),
|
||||||
|
@ -14,25 +14,31 @@ pub use trim_both_ends::SubCommand as Trim;
|
|||||||
pub use trim_left::SubCommand as TrimLeft;
|
pub use trim_left::SubCommand as TrimLeft;
|
||||||
pub use trim_right::SubCommand as TrimRight;
|
pub use trim_right::SubCommand as TrimRight;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
rest: Vec<ColumnPath>,
|
character: Option<Tagged<char>>,
|
||||||
#[serde(rename(deserialize = "char"))]
|
column_paths: Vec<ColumnPath>,
|
||||||
char_: Option<Tagged<char>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn operate<F>(args: CommandArgs, trim_operation: &'static F) -> Result<OutputStream, ShellError>
|
pub fn operate<F>(args: CommandArgs, trim_operation: &'static F) -> Result<OutputStream, ShellError>
|
||||||
where
|
where
|
||||||
F: Fn(&str, Option<char>) -> String + Send + Sync + 'static,
|
F: Fn(&str, Option<char>) -> String + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
let (Arguments { rest, char_ }, input) = args.process()?;
|
let (options, input) = args.extract(|params| {
|
||||||
|
Ok(Arc::new(Arguments {
|
||||||
|
character: if let Some(arg) = params.get_flag("char") {
|
||||||
|
Some(arg?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
column_paths: params.rest_args()?,
|
||||||
|
}))
|
||||||
|
})?;
|
||||||
|
|
||||||
let column_paths: Vec<_> = rest;
|
let to_trim = options.character.as_ref().map(|tagged| tagged.item);
|
||||||
let to_trim = char_.map(|tagged| tagged.item);
|
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.map(move |v| {
|
.map(move |v| {
|
||||||
if column_paths.is_empty() {
|
if options.column_paths.is_empty() {
|
||||||
ReturnSuccess::value(action(
|
ReturnSuccess::value(action(
|
||||||
&v,
|
&v,
|
||||||
v.tag(),
|
v.tag(),
|
||||||
@ -43,7 +49,7 @@ where
|
|||||||
} else {
|
} else {
|
||||||
let mut ret = v;
|
let mut ret = v;
|
||||||
|
|
||||||
for path in &column_paths {
|
for path in &options.column_paths {
|
||||||
ret = ret.swap_data_by_column_path(
|
ret = ret.swap_data_by_column_path(
|
||||||
path,
|
path,
|
||||||
Box::new(move |old| {
|
Box::new(move |old| {
|
||||||
|
@ -8,9 +8,8 @@ use nu_protocol::{
|
|||||||
use nu_source::Tag;
|
use nu_source::Tag;
|
||||||
use nu_value_ext::ValueExt;
|
use nu_value_ext::ValueExt;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
rest: Vec<ColumnPath>,
|
column_paths: Vec<ColumnPath>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
@ -45,18 +44,20 @@ impl WholeStreamCommand for SubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let (Arguments { rest }, input) = args.process()?;
|
let (options, input) = args.extract(|params| {
|
||||||
|
Ok(Arguments {
|
||||||
let column_paths: Vec<_> = rest;
|
column_paths: params.rest_args()?,
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.map(move |v| {
|
.map(move |v| {
|
||||||
if column_paths.is_empty() {
|
if options.column_paths.is_empty() {
|
||||||
ReturnSuccess::value(action(&v, v.tag())?)
|
ReturnSuccess::value(action(&v, v.tag())?)
|
||||||
} else {
|
} else {
|
||||||
let mut ret = v;
|
let mut ret = v;
|
||||||
|
|
||||||
for path in &column_paths {
|
for path in &options.column_paths {
|
||||||
ret = ret.swap_data_by_column_path(
|
ret = ret.swap_data_by_column_path(
|
||||||
path,
|
path,
|
||||||
Box::new(move |old| action(old, old.tag())),
|
Box::new(move |old| action(old, old.tag())),
|
||||||
@ -102,9 +103,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn upcases() {
|
fn upcases() {
|
||||||
let word = string("andres");
|
let word = string("andres");
|
||||||
let expected = string("ANDRES");
|
|
||||||
|
|
||||||
let actual = action(&word, Tag::unknown()).unwrap();
|
let actual = action(&word, Tag::unknown()).unwrap();
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, string("ANDRES"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,23 +78,27 @@ impl std::fmt::Debug for CommandArgs {
|
|||||||
|
|
||||||
impl CommandArgs {
|
impl CommandArgs {
|
||||||
pub fn evaluate_once(self) -> Result<EvaluatedWholeStreamCommandArgs, ShellError> {
|
pub fn evaluate_once(self) -> Result<EvaluatedWholeStreamCommandArgs, ShellError> {
|
||||||
let ctx = EvaluationContext::from_args(&self);
|
let ctx = EvaluationContext::new(
|
||||||
let host = self.host.clone();
|
self.scope,
|
||||||
let ctrl_c = self.ctrl_c.clone();
|
self.host,
|
||||||
let configs = self.configs.clone();
|
self.current_errors,
|
||||||
let shell_manager = self.shell_manager.clone();
|
self.ctrl_c,
|
||||||
|
self.configs,
|
||||||
|
self.shell_manager,
|
||||||
|
Arc::new(Mutex::new(std::collections::HashMap::new())),
|
||||||
|
);
|
||||||
|
|
||||||
let input = self.input;
|
let input = self.input;
|
||||||
let call_info = self.call_info.evaluate(&ctx)?;
|
let call_info = self.call_info.evaluate(&ctx)?;
|
||||||
let scope = self.scope.clone();
|
|
||||||
|
|
||||||
Ok(EvaluatedWholeStreamCommandArgs::new(
|
Ok(EvaluatedWholeStreamCommandArgs::new(
|
||||||
host,
|
ctx.host,
|
||||||
ctrl_c,
|
ctx.ctrl_c,
|
||||||
configs,
|
ctx.configs,
|
||||||
shell_manager,
|
ctx.shell_manager,
|
||||||
call_info,
|
call_info,
|
||||||
input,
|
input,
|
||||||
scope,
|
ctx.scope,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,6 +116,15 @@ impl CommandArgs {
|
|||||||
(self.input, new_context)
|
(self.input, new_context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn extract<T>(
|
||||||
|
self,
|
||||||
|
f: impl FnOnce(&EvaluatedCommandArgs) -> Result<T, ShellError>,
|
||||||
|
) -> Result<(T, InputStream), ShellError> {
|
||||||
|
let evaluated_args = self.evaluate_once()?;
|
||||||
|
|
||||||
|
Ok((f(&evaluated_args.args)?, evaluated_args.input))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn process<'de, T: Deserialize<'de>>(self) -> Result<(T, InputStream), ShellError> {
|
pub fn process<'de, T: Deserialize<'de>>(self) -> Result<(T, InputStream), ShellError> {
|
||||||
let args = self.evaluate_once()?;
|
let args = self.evaluate_once()?;
|
||||||
let call_info = args.call_info.clone();
|
let call_info = args.call_info.clone();
|
||||||
@ -205,6 +218,13 @@ impl EvaluatedCommandArgs {
|
|||||||
.map(|x| FromValue::from_value(x))
|
.map(|x| FromValue::from_value(x))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn req_named<T: FromValue>(&self, name: &str) -> Result<T, ShellError> {
|
||||||
|
self.call_info
|
||||||
|
.args
|
||||||
|
.expect_get(name)
|
||||||
|
.and_then(|x| FromValue::from_value(x))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn has_flag(&self, name: &str) -> bool {
|
pub fn has_flag(&self, name: &str) -> bool {
|
||||||
self.call_info.args.has(name)
|
self.call_info.args.has(name)
|
||||||
}
|
}
|
||||||
@ -229,6 +249,10 @@ impl EvaluatedCommandArgs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rest_args<T: FromValue>(&self) -> Result<Vec<T>, ShellError> {
|
||||||
|
self.rest(0)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn rest<T: FromValue>(&self, starting_pos: usize) -> Result<Vec<T>, ShellError> {
|
pub fn rest<T: FromValue>(&self, starting_pos: usize) -> Result<Vec<T>, ShellError> {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
|
|
||||||
|
6
crates/nu-engine/src/env/host.rs
vendored
6
crates/nu-engine/src/env/host.rs
vendored
@ -22,6 +22,12 @@ pub trait Host: Debug + Send {
|
|||||||
fn is_external_cmd(&self, cmd_name: &str) -> bool;
|
fn is_external_cmd(&self, cmd_name: &str) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Box<dyn Host> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Box::new(BasicHost)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Host for Box<dyn Host> {
|
impl Host for Box<dyn Host> {
|
||||||
fn stdout(&mut self, out: &str) {
|
fn stdout(&mut self, out: &str) {
|
||||||
(**self).stdout(out)
|
(**self).stdout(out)
|
||||||
|
@ -14,7 +14,7 @@ use parking_lot::Mutex;
|
|||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
use std::{path::Path, sync::Arc};
|
use std::{path::Path, sync::Arc};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Default)]
|
||||||
pub struct EvaluationContext {
|
pub struct EvaluationContext {
|
||||||
pub scope: Scope,
|
pub scope: Scope,
|
||||||
pub host: Arc<parking_lot::Mutex<Box<dyn Host>>>,
|
pub host: Arc<parking_lot::Mutex<Box<dyn Host>>>,
|
||||||
@ -28,6 +28,26 @@ pub struct EvaluationContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl EvaluationContext {
|
impl EvaluationContext {
|
||||||
|
pub fn new(
|
||||||
|
scope: Scope,
|
||||||
|
host: Arc<parking_lot::Mutex<Box<dyn Host>>>,
|
||||||
|
current_errors: Arc<Mutex<Vec<ShellError>>>,
|
||||||
|
ctrl_c: Arc<AtomicBool>,
|
||||||
|
configs: Arc<Mutex<ConfigHolder>>,
|
||||||
|
shell_manager: ShellManager,
|
||||||
|
windows_drives_previous_cwd: Arc<Mutex<std::collections::HashMap<String, String>>>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
scope,
|
||||||
|
host,
|
||||||
|
current_errors,
|
||||||
|
ctrl_c,
|
||||||
|
configs,
|
||||||
|
shell_manager,
|
||||||
|
windows_drives_previous_cwd,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn from_args(args: &CommandArgs) -> EvaluationContext {
|
pub fn from_args(args: &CommandArgs) -> EvaluationContext {
|
||||||
EvaluationContext {
|
EvaluationContext {
|
||||||
scope: args.scope.clone(),
|
scope: args.scope.clone(),
|
||||||
|
@ -40,6 +40,12 @@ impl FromValue for num_bigint::BigInt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl FromValue for Tagged<u64> {
|
||||||
|
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
||||||
|
let tag = v.tag.clone();
|
||||||
|
v.as_u64().map(|s| s.tagged(tag))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl FromValue for u64 {
|
impl FromValue for u64 {
|
||||||
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
||||||
@ -47,6 +53,34 @@ impl FromValue for u64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FromValue for Tagged<u32> {
|
||||||
|
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
||||||
|
let tag = v.tag.clone();
|
||||||
|
v.as_u32().map(|s| s.tagged(tag))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromValue for Tagged<i16> {
|
||||||
|
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
||||||
|
let tag = v.tag.clone();
|
||||||
|
v.as_i16().map(|s| s.tagged(tag))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromValue for Tagged<usize> {
|
||||||
|
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
||||||
|
let tag = v.tag.clone();
|
||||||
|
v.as_usize().map(|s| s.tagged(tag))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromValue for Tagged<char> {
|
||||||
|
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
||||||
|
let tag = v.tag.clone();
|
||||||
|
v.as_char().map(|c| c.tagged(tag))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl FromValue for usize {
|
impl FromValue for usize {
|
||||||
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
fn from_value(v: &Value) -> Result<Self, ShellError> {
|
||||||
v.as_usize()
|
v.as_usize()
|
||||||
|
@ -12,7 +12,7 @@ use std::path::{Path, PathBuf};
|
|||||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Default, Debug)]
|
||||||
pub struct ShellManager {
|
pub struct ShellManager {
|
||||||
pub current_shell: Arc<AtomicUsize>,
|
pub current_shell: Arc<AtomicUsize>,
|
||||||
pub shells: Arc<Mutex<Vec<Box<dyn Shell + Send>>>>,
|
pub shells: Arc<Mutex<Vec<Box<dyn Shell + Send>>>>,
|
||||||
|
@ -80,6 +80,16 @@ impl EvaluatedArgs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the corresponding Value for the named argument given, error if not possible
|
||||||
|
pub fn expect_get(&self, name: &str) -> Result<&Value, ShellError> {
|
||||||
|
match &self.named {
|
||||||
|
None => Err(ShellError::unimplemented("Better error: expect_get")),
|
||||||
|
Some(named) => named
|
||||||
|
.get(name)
|
||||||
|
.ok_or_else(|| ShellError::unimplemented("Better error: expect_get")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Iterates over the positional arguments
|
/// Iterates over the positional arguments
|
||||||
pub fn positional_iter(&self) -> PositionalIter<'_> {
|
pub fn positional_iter(&self) -> PositionalIter<'_> {
|
||||||
match &self.positional {
|
match &self.positional {
|
||||||
|
@ -429,6 +429,14 @@ impl Value {
|
|||||||
matches!(&self.value, UntaggedValue::Primitive(_))
|
matches!(&self.value, UntaggedValue::Primitive(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// View the Value as char, if possible
|
||||||
|
pub fn as_char(&self) -> Result<char, ShellError> {
|
||||||
|
match &self.value {
|
||||||
|
UntaggedValue::Primitive(primitive) => primitive.as_char(self.tag.span),
|
||||||
|
_ => Err(ShellError::type_error("char", self.spanned_type_name())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// View the Value as unsigned size, if possible
|
/// View the Value as unsigned size, if possible
|
||||||
pub fn as_usize(&self) -> Result<usize, ShellError> {
|
pub fn as_usize(&self) -> Result<usize, ShellError> {
|
||||||
match &self.value {
|
match &self.value {
|
||||||
@ -453,7 +461,15 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// View the Value as signed 64-bit, if possible
|
/// View the Value as unsigned 32-bit, if possible
|
||||||
|
pub fn as_u32(&self) -> Result<u32, ShellError> {
|
||||||
|
match &self.value {
|
||||||
|
UntaggedValue::Primitive(primitive) => primitive.as_u32(self.tag.span),
|
||||||
|
_ => Err(ShellError::type_error("integer", self.spanned_type_name())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// View the Value as signed 32-bit, if possible
|
||||||
pub fn as_i32(&self) -> Result<i32, ShellError> {
|
pub fn as_i32(&self) -> Result<i32, ShellError> {
|
||||||
match &self.value {
|
match &self.value {
|
||||||
UntaggedValue::Primitive(primitive) => primitive.as_i32(self.tag.span),
|
UntaggedValue::Primitive(primitive) => primitive.as_i32(self.tag.span),
|
||||||
@ -461,6 +477,14 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// View the Value as signed 16-bit, if possible
|
||||||
|
pub fn as_i16(&self) -> Result<i16, ShellError> {
|
||||||
|
match &self.value {
|
||||||
|
UntaggedValue::Primitive(primitive) => primitive.as_i16(self.tag.span),
|
||||||
|
_ => Err(ShellError::type_error("integer", self.spanned_type_name())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// View the Value as boolean, if possible
|
/// View the Value as boolean, if possible
|
||||||
pub fn as_bool(&self) -> Result<bool, ShellError> {
|
pub fn as_bool(&self) -> Result<bool, ShellError> {
|
||||||
match &self.value {
|
match &self.value {
|
||||||
|
@ -60,6 +60,27 @@ pub enum Primitive {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Primitive {
|
impl Primitive {
|
||||||
|
/// Converts a primitive value to a char, if possible. Uses a span to build an error if the conversion isn't possible.
|
||||||
|
pub fn as_char(&self, span: Span) -> Result<char, ShellError> {
|
||||||
|
match self {
|
||||||
|
Primitive::String(s) => {
|
||||||
|
if s.len() > 1 {
|
||||||
|
return Err(ShellError::type_error(
|
||||||
|
"char",
|
||||||
|
self.type_name().spanned(span),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
s.chars()
|
||||||
|
.next()
|
||||||
|
.ok_or_else(|| ShellError::type_error("char", self.type_name().spanned(span)))
|
||||||
|
}
|
||||||
|
other => Err(ShellError::type_error(
|
||||||
|
"char",
|
||||||
|
other.type_name().spanned(span),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Converts a primitive value to a u64, if possible. Uses a span to build an error if the conversion isn't possible.
|
/// Converts a primitive value to a u64, if possible. Uses a span to build an error if the conversion isn't possible.
|
||||||
pub fn as_usize(&self, span: Span) -> Result<usize, ShellError> {
|
pub fn as_usize(&self, span: Span) -> Result<usize, ShellError> {
|
||||||
match self {
|
match self {
|
||||||
@ -108,6 +129,7 @@ impl Primitive {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts a primitive value to a i64, if possible. Uses a span to build an error if the conversion isn't possible.
|
||||||
pub fn as_i64(&self, span: Span) -> Result<i64, ShellError> {
|
pub fn as_i64(&self, span: Span) -> Result<i64, ShellError> {
|
||||||
match self {
|
match self {
|
||||||
Primitive::Int(int) => int.to_i64().ok_or_else(|| {
|
Primitive::Int(int) => int.to_i64().ok_or_else(|| {
|
||||||
@ -131,6 +153,30 @@ impl Primitive {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts a primitive value to a u32, if possible. Uses a span to build an error if the conversion isn't possible.
|
||||||
|
pub fn as_u32(&self, span: Span) -> Result<u32, ShellError> {
|
||||||
|
match self {
|
||||||
|
Primitive::Int(int) => int.to_u32().ok_or_else(|| {
|
||||||
|
ShellError::range_error(
|
||||||
|
ExpectedRange::U32,
|
||||||
|
&format!("{}", int).spanned(span),
|
||||||
|
"converting an integer into a unsigned 32-bit integer",
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
Primitive::Decimal(decimal) => decimal.to_u32().ok_or_else(|| {
|
||||||
|
ShellError::range_error(
|
||||||
|
ExpectedRange::U32,
|
||||||
|
&format!("{}", decimal).spanned(span),
|
||||||
|
"converting a decimal into a unsigned 32-bit integer",
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
other => Err(ShellError::type_error(
|
||||||
|
"number",
|
||||||
|
other.type_name().spanned(span),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn as_i32(&self, span: Span) -> Result<i32, ShellError> {
|
pub fn as_i32(&self, span: Span) -> Result<i32, ShellError> {
|
||||||
match self {
|
match self {
|
||||||
Primitive::Int(int) => int.to_i32().ok_or_else(|| {
|
Primitive::Int(int) => int.to_i32().ok_or_else(|| {
|
||||||
@ -154,6 +200,29 @@ impl Primitive {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_i16(&self, span: Span) -> Result<i16, ShellError> {
|
||||||
|
match self {
|
||||||
|
Primitive::Int(int) => int.to_i16().ok_or_else(|| {
|
||||||
|
ShellError::range_error(
|
||||||
|
ExpectedRange::I16,
|
||||||
|
&format!("{}", int).spanned(span),
|
||||||
|
"converting an integer into a signed 16-bit integer",
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
Primitive::Decimal(decimal) => decimal.to_i16().ok_or_else(|| {
|
||||||
|
ShellError::range_error(
|
||||||
|
ExpectedRange::I16,
|
||||||
|
&format!("{}", decimal).spanned(span),
|
||||||
|
"converting a decimal into a signed 16-bit integer",
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
other => Err(ShellError::type_error(
|
||||||
|
"number",
|
||||||
|
other.type_name().spanned(span),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: This is a bad name, but no other way to differentiate with our own Duration.
|
// FIXME: This is a bad name, but no other way to differentiate with our own Duration.
|
||||||
pub fn into_chrono_duration(self, span: Span) -> Result<chrono::Duration, ShellError> {
|
pub fn into_chrono_duration(self, span: Span) -> Result<chrono::Duration, ShellError> {
|
||||||
match self {
|
match self {
|
||||||
|
Loading…
Reference in New Issue
Block a user