forked from extern/nushell
Commands to engine (#3448)
* commands to engine * Correction of error in parser * Added detailed regex error to parse * better regex error parsing * clippy corrections * parse example with test * secondary error for regex * removed clone in error parser * Secondary error message
This commit is contained in:
parent
94a26abf21
commit
f075e2459d
@ -2,18 +2,11 @@ use crate::prelude::*;
|
||||
use nu_data::base::select_fields;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, Value};
|
||||
use nu_protocol::{ColumnPath, Signature, SyntaxShape, Value};
|
||||
use nu_source::HasFallibleSpan;
|
||||
|
||||
pub struct Command;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Arguments {
|
||||
rest: Vec<ColumnPath>,
|
||||
after: Option<ColumnPath>,
|
||||
before: Option<ColumnPath>,
|
||||
}
|
||||
|
||||
impl WholeStreamCommand for Command {
|
||||
fn name(&self) -> &str {
|
||||
"move"
|
||||
@ -40,7 +33,7 @@ impl WholeStreamCommand for Command {
|
||||
"Move columns."
|
||||
}
|
||||
|
||||
fn run_with_actions(&self, args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
operate(args)
|
||||
}
|
||||
|
||||
@ -82,16 +75,13 @@ impl WholeStreamCommand for Command {
|
||||
}
|
||||
}
|
||||
|
||||
fn operate(raw_args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
fn operate(raw_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name = raw_args.call_info.name_tag.clone();
|
||||
let (
|
||||
Arguments {
|
||||
rest: mut columns,
|
||||
before,
|
||||
after,
|
||||
},
|
||||
input,
|
||||
) = raw_args.process()?;
|
||||
let args = raw_args.evaluate_once()?;
|
||||
|
||||
let mut columns: Vec<ColumnPath> = args.rest(0)?;
|
||||
let before: Option<ColumnPath> = args.get_flag("before")?;
|
||||
let after: Option<ColumnPath> = args.get_flag("after")?;
|
||||
|
||||
if columns.is_empty() {
|
||||
return Err(ShellError::labeled_error(
|
||||
@ -125,7 +115,8 @@ fn operate(raw_args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
if let Some(after) = after {
|
||||
let member = columns.remove(0);
|
||||
|
||||
Ok(input
|
||||
Ok(args
|
||||
.input
|
||||
.map(move |item| {
|
||||
let member = vec![member.clone()];
|
||||
let column_paths = vec![&member, &columns]
|
||||
@ -144,7 +135,7 @@ fn operate(raw_args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
|
||||
if let Some(column) = after.last() {
|
||||
if !keys.contains(&column.as_string()) {
|
||||
ReturnSuccess::value(move_after(&item, &keys, &after)?)
|
||||
move_after(&item, &keys, &after)
|
||||
} else {
|
||||
let msg =
|
||||
format!("can't move column {} after itself", column.as_string());
|
||||
@ -169,11 +160,12 @@ fn operate(raw_args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
))
|
||||
}
|
||||
})
|
||||
.to_action_stream())
|
||||
.to_input_stream())
|
||||
} else if let Some(before) = before {
|
||||
let member = columns.remove(0);
|
||||
|
||||
Ok(input
|
||||
Ok(args
|
||||
.input
|
||||
.map(move |item| {
|
||||
let member = vec![member.clone()];
|
||||
let column_paths = vec![&member, &columns]
|
||||
@ -192,7 +184,7 @@ fn operate(raw_args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
|
||||
if let Some(column) = before.last() {
|
||||
if !keys.contains(&column.as_string()) {
|
||||
ReturnSuccess::value(move_before(&item, &keys, &before)?)
|
||||
move_before(&item, &keys, &before)
|
||||
} else {
|
||||
let msg =
|
||||
format!("can't move column {} before itself", column.as_string());
|
||||
@ -217,7 +209,7 @@ fn operate(raw_args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
))
|
||||
}
|
||||
})
|
||||
.to_action_stream())
|
||||
.to_input_stream())
|
||||
} else {
|
||||
Err(ShellError::labeled_error(
|
||||
"no columns given",
|
||||
|
@ -4,13 +4,7 @@ use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, SyntaxShape, TaggedDictBuilder, UntaggedValue, Value};
|
||||
use nu_source::Tagged;
|
||||
|
||||
use regex::Regex;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Arguments {
|
||||
pattern: Tagged<String>,
|
||||
regex: Tagged<bool>,
|
||||
}
|
||||
use regex::{self, Regex};
|
||||
|
||||
pub struct Command;
|
||||
|
||||
@ -33,7 +27,7 @@ impl WholeStreamCommand for Command {
|
||||
"Parse columns from string data using a simple pattern."
|
||||
}
|
||||
|
||||
fn run_with_actions(&self, args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
operate(args)
|
||||
}
|
||||
|
||||
@ -41,33 +35,41 @@ impl WholeStreamCommand for Command {
|
||||
let mut row = IndexMap::new();
|
||||
row.insert("foo".to_string(), Value::from("hi"));
|
||||
row.insert("bar".to_string(), Value::from("there"));
|
||||
vec![Example {
|
||||
description: "Parse a string into two named columns",
|
||||
example: "echo \"hi there\" | parse \"{foo} {bar}\"",
|
||||
result: Some(vec![UntaggedValue::row(row).into()]),
|
||||
}]
|
||||
vec![
|
||||
Example {
|
||||
description: "Parse a string into two named columns",
|
||||
example: "echo \"hi there\" | parse \"{foo} {bar}\"",
|
||||
result: Some(vec![UntaggedValue::row(row.clone()).into()]),
|
||||
},
|
||||
Example {
|
||||
description: "Parse a string using regex pattern",
|
||||
example: "echo \"hi there\" | parse -r \"(?P<foo>\\w+) (?P<bar>\\w+)\"",
|
||||
result: Some(vec![UntaggedValue::row(row).into()]),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn operate(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
pub fn operate(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name_tag = args.call_info.name_tag.clone();
|
||||
let (Arguments { regex, pattern }, input) = args.process()?;
|
||||
let args = args.evaluate_once()?;
|
||||
|
||||
let regex_pattern = if let Tagged { item: true, tag } = regex {
|
||||
Regex::new(&pattern.item)
|
||||
.map_err(|_| ShellError::labeled_error("Invalid regex", "invalid regex", tag.span))?
|
||||
let pattern: Tagged<String> = args.req(0)?;
|
||||
let regex: bool = args.has_flag("regex");
|
||||
|
||||
let item_to_parse = if regex {
|
||||
pattern.item.clone()
|
||||
} else {
|
||||
let parse_regex = build_regex(&pattern.item, name_tag.clone())?;
|
||||
|
||||
Regex::new(&parse_regex).map_err(|_| {
|
||||
ShellError::labeled_error("Invalid pattern", "invalid pattern", name_tag.span)
|
||||
})?
|
||||
build_regex(&pattern.item, pattern.tag.clone())?
|
||||
};
|
||||
|
||||
let regex_pattern =
|
||||
Regex::new(&item_to_parse).map_err(|e| parse_regex_error(e, pattern.span()))?;
|
||||
|
||||
let columns = column_names(®ex_pattern);
|
||||
let mut parsed: VecDeque<Value> = VecDeque::new();
|
||||
|
||||
for v in input {
|
||||
for v in args.input {
|
||||
match v.as_string() {
|
||||
Ok(s) => {
|
||||
let results = regex_pattern.captures_iter(&s);
|
||||
@ -95,7 +97,7 @@ pub fn operate(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(parsed.into_iter().to_action_stream())
|
||||
Ok(parsed.into_iter().to_output_stream())
|
||||
}
|
||||
|
||||
fn build_regex(input: &str, tag: Tag) -> Result<String, ShellError> {
|
||||
@ -165,6 +167,38 @@ fn column_names(regex: &Regex) -> Vec<String> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn parse_regex_error(e: regex::Error, base_span: Span) -> ShellError {
|
||||
match e {
|
||||
regex::Error::Syntax(msg) => {
|
||||
let mut lines = msg.lines();
|
||||
|
||||
let main_msg = lines
|
||||
.next()
|
||||
.map(|l| l.replace(':', ""))
|
||||
.expect("invalid regex pattern");
|
||||
|
||||
let span = lines.nth(1).map(|l| l.find('^')).flatten().map(|space| {
|
||||
let start = base_span.start() + space - 3;
|
||||
Span::for_char(start)
|
||||
});
|
||||
|
||||
let msg = lines
|
||||
.next()
|
||||
.map(|l| l.split(':').nth(1))
|
||||
.flatten()
|
||||
.map(|s| s.trim().to_string());
|
||||
|
||||
match (msg, span) {
|
||||
(Some(msg), Some(span)) => {
|
||||
ShellError::labeled_error_with_secondary(&msg, &msg, span, main_msg, span)
|
||||
}
|
||||
_ => ShellError::labeled_error("Invalid regex", "invalid regex", base_span),
|
||||
}
|
||||
}
|
||||
_ => ShellError::labeled_error("Invalid regex", "invalid regex", base_span),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Command;
|
||||
|
@ -2,18 +2,16 @@ use crate::prelude::*;
|
||||
use nu_data::base::select_fields;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, TaggedDictBuilder, UntaggedValue, Value};
|
||||
use nu_protocol::{Signature, SyntaxShape, TaggedDictBuilder, UntaggedValue, Value};
|
||||
use nu_source::Tagged;
|
||||
|
||||
use super::support::{rotate, Direction};
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Arguments {
|
||||
by: Option<Tagged<u64>>,
|
||||
opposite: bool,
|
||||
#[serde(rename(deserialize = "cells-only"))]
|
||||
cells_only: bool,
|
||||
}
|
||||
|
||||
@ -47,25 +45,31 @@ impl WholeStreamCommand for SubCommand {
|
||||
"Rolls the table columns"
|
||||
}
|
||||
|
||||
fn run_with_actions(&self, args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
roll(args)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn roll(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
let (args, input) = args.process()?;
|
||||
pub fn roll(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once()?;
|
||||
|
||||
Ok(input
|
||||
let options = Arguments {
|
||||
by: args.opt(0)?,
|
||||
opposite: args.has_flag("opposite"),
|
||||
cells_only: args.has_flag("cells-only"),
|
||||
};
|
||||
|
||||
Ok(args
|
||||
.input
|
||||
.map(move |value| {
|
||||
let tag = value.tag();
|
||||
|
||||
roll_by(value, &args)
|
||||
roll_by(value, &options)
|
||||
.unwrap_or_else(|| vec![UntaggedValue::nothing().into_value(tag)])
|
||||
.into_iter()
|
||||
.map(ReturnSuccess::value)
|
||||
})
|
||||
.flatten()
|
||||
.to_action_stream())
|
||||
.to_output_stream())
|
||||
}
|
||||
|
||||
fn roll_by(value: Value, options: &Arguments) -> Option<Vec<Value>> {
|
||||
|
@ -1,14 +1,13 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_protocol::{Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_source::Tagged;
|
||||
|
||||
use super::support::{rotate, Direction};
|
||||
|
||||
pub struct Command;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Arguments {
|
||||
by: Option<Tagged<u64>>,
|
||||
}
|
||||
@ -26,22 +25,23 @@ impl WholeStreamCommand for Command {
|
||||
"Rolls the table rows."
|
||||
}
|
||||
|
||||
fn run_with_actions(&self, args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
roll(args)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn roll(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
pub fn roll(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name = args.call_info.name_tag.clone();
|
||||
let (args, mut input) = args.process()?;
|
||||
let mut args = args.evaluate_once()?;
|
||||
|
||||
let values = input.drain_vec();
|
||||
let options = Arguments { by: args.opt(0)? };
|
||||
|
||||
Ok((roll_down(values, &args)
|
||||
let values = args.input.drain_vec();
|
||||
|
||||
Ok(roll_down(values, &options)
|
||||
.unwrap_or_else(|| vec![UntaggedValue::nothing().into_value(&name)])
|
||||
.into_iter()
|
||||
.map(ReturnSuccess::value))
|
||||
.to_action_stream())
|
||||
.to_output_stream())
|
||||
}
|
||||
|
||||
fn roll_down(values: Vec<Value>, Arguments { by: ref n }: &Arguments) -> Option<Vec<Value>> {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_protocol::{Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_source::Tagged;
|
||||
|
||||
use super::support::{rotate, Direction};
|
||||
@ -26,22 +26,23 @@ impl WholeStreamCommand for SubCommand {
|
||||
"Rolls the table rows"
|
||||
}
|
||||
|
||||
fn run_with_actions(&self, args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
roll(args)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn roll(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
pub fn roll(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name = args.call_info.name_tag.clone();
|
||||
let (args, mut input) = args.process()?;
|
||||
let mut args = args.evaluate_once()?;
|
||||
|
||||
let values = input.drain_vec();
|
||||
let options = Arguments { by: args.opt(0)? };
|
||||
|
||||
Ok((roll_up(values, &args)
|
||||
let values = args.input.drain_vec();
|
||||
|
||||
Ok(roll_up(values, &options)
|
||||
.unwrap_or_else(|| vec![UntaggedValue::nothing().into_value(&name)])
|
||||
.into_iter()
|
||||
.map(ReturnSuccess::value))
|
||||
.to_action_stream())
|
||||
.to_output_stream())
|
||||
}
|
||||
|
||||
fn roll_up(values: Vec<Value>, Arguments { by: ref n }: &Arguments) -> Option<Vec<Value>> {
|
||||
|
@ -181,7 +181,7 @@ mod regex {
|
||||
"#
|
||||
));
|
||||
|
||||
assert!(actual.err.contains("invalid regex"));
|
||||
assert!(actual.err.contains("unclosed group"));
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user