diff --git a/Cargo.lock b/Cargo.lock index 6b519f29a0..42749f2bb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1878,7 +1878,7 @@ dependencies = [ [[package]] name = "nu" -version = "0.6.1" +version = "0.6.2" dependencies = [ "ansi_term 0.12.1", "app_dirs", diff --git a/Cargo.toml b/Cargo.toml index 4b4d5c0330..63eca929ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nu" -version = "0.6.1" +version = "0.6.2" authors = ["Yehuda Katz ", "Jonathan Turner ", "Andrés N. Robalino "] description = "A shell for the GitHub era" license = "MIT" diff --git a/crates/nu-parser/src/hir/syntax_shape/expression/file_path.rs b/crates/nu-parser/src/hir/syntax_shape/expression/file_path.rs index 0fca4a6c2c..2c5cb7169d 100644 --- a/crates/nu-parser/src/hir/syntax_shape/expression/file_path.rs +++ b/crates/nu-parser/src/hir/syntax_shape/expression/file_path.rs @@ -102,10 +102,17 @@ impl ExpandExpression for FilePathShape { token_nodes: &mut TokensIterator<'_>, context: &ExpandContext, ) -> Result { - let atom = expand_atom(token_nodes, "file path", context, ExpansionRule::new())?; + let atom = expand_atom( + token_nodes, + "file path", + context, + ExpansionRule::new().allow_external_word(), + )?; match atom.unspanned { - UnspannedAtomicToken::Word { text: body } | UnspannedAtomicToken::String { body } => { + UnspannedAtomicToken::Word { text: body } + | UnspannedAtomicToken::ExternalWord { text: body } + | UnspannedAtomicToken::String { body } => { let path = expand_file_path(body.slice(context.source), context); return Ok(hir::Expression::file_path(path, atom.span)); } diff --git a/crates/nu-parser/src/hir/syntax_shape/expression/pattern.rs b/crates/nu-parser/src/hir/syntax_shape/expression/pattern.rs index 02fa0ed687..826d5d8286 100644 --- a/crates/nu-parser/src/hir/syntax_shape/expression/pattern.rs +++ b/crates/nu-parser/src/hir/syntax_shape/expression/pattern.rs @@ -84,11 +84,17 @@ impl ExpandExpression for PatternShape { token_nodes: &mut TokensIterator<'_>, context: &ExpandContext, ) -> Result { - let atom = expand_atom(token_nodes, "pattern", context, ExpansionRule::new())?; + let atom = expand_atom( + token_nodes, + "pattern", + context, + ExpansionRule::new().allow_external_word(), + )?; match atom.unspanned { UnspannedAtomicToken::Word { text: body } | UnspannedAtomicToken::String { body } + | UnspannedAtomicToken::ExternalWord { text: body } | UnspannedAtomicToken::GlobPattern { pattern: body } => { let path = expand_file_path(body.slice(context.source), context); return Ok(hir::Expression::pattern(path.to_string_lossy(), atom.span)); diff --git a/crates/nu-protocol/src/value.rs b/crates/nu-protocol/src/value.rs index 8e116315a7..fbbc10304d 100644 --- a/crates/nu-protocol/src/value.rs +++ b/crates/nu-protocol/src/value.rs @@ -132,9 +132,10 @@ impl Value { self.tag.clone() } - pub fn as_string(&self) -> Result<&str, ShellError> { + pub fn as_string(&self) -> Result { match &self.value { - UntaggedValue::Primitive(Primitive::String(string)) => Ok(&string[..]), + UntaggedValue::Primitive(Primitive::String(string)) => Ok(string.clone()), + UntaggedValue::Primitive(Primitive::Line(line)) => Ok(line.clone() + "\n"), _ => Err(ShellError::type_error("string", self.spanned_type_name())), } } diff --git a/crates/nu-protocol/src/value/debug.rs b/crates/nu-protocol/src/value/debug.rs index c24789340d..f71be77124 100644 --- a/crates/nu-protocol/src/value/debug.rs +++ b/crates/nu-protocol/src/value/debug.rs @@ -31,6 +31,7 @@ impl PrettyType for Primitive { Primitive::Decimal(_) => ty("decimal"), Primitive::Bytes(_) => ty("bytesize"), Primitive::String(_) => ty("string"), + Primitive::Line(_) => ty("line"), Primitive::ColumnPath(_) => ty("column-path"), Primitive::Pattern(_) => ty("pattern"), Primitive::Boolean(_) => ty("boolean"), @@ -52,6 +53,7 @@ impl PrettyDebug for Primitive { Primitive::Decimal(decimal) => prim(format_args!("{}", decimal)), Primitive::Bytes(bytes) => primitive_doc(bytes, "bytesize"), Primitive::String(string) => prim(string), + Primitive::Line(string) => prim(string), Primitive::ColumnPath(path) => path.pretty(), Primitive::Pattern(pattern) => primitive_doc(pattern, "pattern"), Primitive::Boolean(boolean) => match boolean { diff --git a/crates/nu-protocol/src/value/primitive.rs b/crates/nu-protocol/src/value/primitive.rs index 34bacb69ca..80092d3c48 100644 --- a/crates/nu-protocol/src/value/primitive.rs +++ b/crates/nu-protocol/src/value/primitive.rs @@ -17,6 +17,7 @@ pub enum Primitive { Decimal(BigDecimal), Bytes(u64), String(String), + Line(String), ColumnPath(ColumnPath), Pattern(String), Boolean(bool), @@ -51,6 +52,7 @@ impl ShellTypeName for Primitive { Primitive::Decimal(_) => "decimal", Primitive::Bytes(_) => "bytes", Primitive::String(_) => "string", + Primitive::Line(_) => "line", Primitive::ColumnPath(_) => "column path", Primitive::Pattern(_) => "pattern", Primitive::Boolean(_) => "boolean", diff --git a/src/commands/autoview.rs b/src/commands/autoview.rs index 5c8bf1c982..06f69f4ec1 100644 --- a/src/commands/autoview.rs +++ b/src/commands/autoview.rs @@ -152,6 +152,25 @@ pub fn autoview( } => { outln!("{}", s); } + Value { + value: UntaggedValue::Primitive(Primitive::Line(ref s)), + tag: Tag { anchor, span }, + } if anchor.is_some() => { + if let Some(text) = text { + let mut stream = VecDeque::new(); + stream.push_back(value::string(s).into_value(Tag { anchor, span })); + let result = text.run(raw.with_input(stream.into()), &context.commands); + result.collect::>().await; + } else { + outln!("{}\n", s); + } + } + Value { + value: UntaggedValue::Primitive(Primitive::Line(s)), + .. + } => { + outln!("{}\n", s); + } Value { value: UntaggedValue::Primitive(Primitive::Path(s)), .. diff --git a/src/commands/classified/external.rs b/src/commands/classified/external.rs index 3ddb7a3276..e56bfa7e1b 100644 --- a/src/commands/classified/external.rs +++ b/src/commands/classified/external.rs @@ -25,7 +25,7 @@ impl Encoder for LinesCodec { } impl Decoder for LinesCodec { - type Item = String; + type Item = nu_protocol::UntaggedValue; type Error = Error; fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { @@ -33,12 +33,14 @@ impl Decoder for LinesCodec { Some(pos) if !src.is_empty() => { let buf = src.split_to(pos + 1); String::from_utf8(buf.to_vec()) + .map(value::line) .map(Some) .map_err(|e| Error::new(ErrorKind::InvalidData, e)) } _ if !src.is_empty() => { let drained = src.take(); String::from_utf8(drained.to_vec()) + .map(value::string) .map(Some) .map_err(|e| Error::new(ErrorKind::InvalidData, e)) } @@ -192,8 +194,7 @@ pub(crate) async fn run_external_command( let stdout = popen.stdout.take().unwrap(); let file = futures::io::AllowStdIo::new(stdout); let stream = Framed::new(file, LinesCodec {}); - let stream = - stream.map(move |line| value::string(line.unwrap()).into_value(&name_tag)); + let stream = stream.map(move |line| line.unwrap().into_value(&name_tag)); Ok(ClassifiedInputStream::from_input_stream( stream.boxed() as BoxStream<'static, Value> )) diff --git a/src/commands/from_delimited_data.rs b/src/commands/from_delimited_data.rs index 99db232f80..970085ccac 100644 --- a/src/commands/from_delimited_data.rs +++ b/src/commands/from_delimited_data.rs @@ -56,19 +56,16 @@ pub fn from_delimited_data( for value in values { let value_tag = &value.tag; latest_tag = Some(value_tag.clone()); - match &value.value { - UntaggedValue::Primitive(Primitive::String(s)) => { - concat_string.push_str(&s); - concat_string.push_str("\n"); - } - _ => yield Err(ShellError::labeled_error_with_secondary( + if let Ok(s) = value.as_string() { + concat_string.push_str(&s); + } else { + yield Err(ShellError::labeled_error_with_secondary( "Expected a string from pipeline", "requires string input", name_tag.clone(), "value originates from here", value_tag.clone(), - )), - + )) } } diff --git a/src/commands/from_ini.rs b/src/commands/from_ini.rs index 63383ba18d..0be687e6d3 100644 --- a/src/commands/from_ini.rs +++ b/src/commands/from_ini.rs @@ -79,19 +79,16 @@ fn from_ini(args: CommandArgs, registry: &CommandRegistry) -> Result { - concat_string.push_str(&s); - concat_string.push_str("\n"); - } - _ => yield Err(ShellError::labeled_error_with_secondary( + if let Ok(s) = value.as_string() { + concat_string.push_str(&s); + } else { + yield Err(ShellError::labeled_error_with_secondary( "Expected a string from pipeline", "requires string input", span, "value originates from here", value_span, - )), - + )) } } diff --git a/src/commands/from_json.rs b/src/commands/from_json.rs index 9a9ea1ecbd..40ba10d2f6 100644 --- a/src/commands/from_json.rs +++ b/src/commands/from_json.rs @@ -83,19 +83,17 @@ fn from_json( for value in values { latest_tag = Some(value.tag.clone()); let value_span = value.tag.span; - match &value.value { - UntaggedValue::Primitive(Primitive::String(s)) => { - concat_string.push_str(&s); - concat_string.push_str("\n"); - } - _ => yield Err(ShellError::labeled_error_with_secondary( + + if let Ok(s) = value.as_string() { + concat_string.push_str(&s); + } else { + yield Err(ShellError::labeled_error_with_secondary( "Expected a string from pipeline", "requires string input", name_span, "value originates from here", value_span, - )), - + )) } } diff --git a/src/commands/from_ssv.rs b/src/commands/from_ssv.rs index 24caae107e..2752531111 100644 --- a/src/commands/from_ssv.rs +++ b/src/commands/from_ssv.rs @@ -266,17 +266,17 @@ fn from_ssv( for value in values { let value_tag = value.tag.clone(); latest_tag = Some(value_tag.clone()); - match &value.value { - UntaggedValue::Primitive(Primitive::String(s)) => { - concat_string.push_str(&s); - } - _ => yield Err(ShellError::labeled_error_with_secondary ( + if let Ok(s) = value.as_string() { + concat_string.push_str(&s); + } + else { + yield Err(ShellError::labeled_error_with_secondary ( "Expected a string from pipeline", "requires string input", &name, "value originates from here", &value_tag - )), + )) } } diff --git a/src/commands/from_toml.rs b/src/commands/from_toml.rs index eabaa2392c..9b488b7907 100644 --- a/src/commands/from_toml.rs +++ b/src/commands/from_toml.rs @@ -82,19 +82,17 @@ pub fn from_toml( for value in values { latest_tag = Some(value.tag.clone()); let value_span = value.tag.span; - match value.value { - UntaggedValue::Primitive(Primitive::String(s)) => { - concat_string.push_str(&s); - concat_string.push_str("\n"); - } - _ => yield Err(ShellError::labeled_error_with_secondary( + if let Ok(s) = value.as_string() { + concat_string.push_str(&s); + } + else { + yield Err(ShellError::labeled_error_with_secondary( "Expected a string from pipeline", "requires string input", name_span, "value originates from here", value_span, - )), - + )) } } diff --git a/src/commands/from_url.rs b/src/commands/from_url.rs index cafcb6cd1f..91ca18fef9 100644 --- a/src/commands/from_url.rs +++ b/src/commands/from_url.rs @@ -3,7 +3,7 @@ use crate::data::value; use crate::data::TaggedDictBuilder; use crate::prelude::*; use nu_errors::ShellError; -use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value}; +use nu_protocol::{ReturnSuccess, Signature, Value}; pub struct FromURL; @@ -44,18 +44,16 @@ fn from_url(args: CommandArgs, registry: &CommandRegistry) -> Result { - concat_string.push_str(&s); - } - _ => yield Err(ShellError::labeled_error_with_secondary( + if let Ok(s) = value.as_string() { + concat_string.push_str(&s); + } else { + yield Err(ShellError::labeled_error_with_secondary( "Expected a string from pipeline", "requires string input", name_span, "value originates from here", value_span, - )), - + )) } } diff --git a/src/commands/from_xml.rs b/src/commands/from_xml.rs index db2d173604..9d54f25684 100644 --- a/src/commands/from_xml.rs +++ b/src/commands/from_xml.rs @@ -96,19 +96,17 @@ fn from_xml(args: CommandArgs, registry: &CommandRegistry) -> Result { - concat_string.push_str(&s); - concat_string.push_str("\n"); - } - _ => yield Err(ShellError::labeled_error_with_secondary( + if let Ok(s) = value.as_string() { + concat_string.push_str(&s); + } + else { + yield Err(ShellError::labeled_error_with_secondary( "Expected a string from pipeline", "requires string input", name_span, "value originates from here", value_span, - )), - + )) } } diff --git a/src/commands/from_yaml.rs b/src/commands/from_yaml.rs index 3beea333c9..2b253c2e5f 100644 --- a/src/commands/from_yaml.rs +++ b/src/commands/from_yaml.rs @@ -110,19 +110,17 @@ fn from_yaml(args: CommandArgs, registry: &CommandRegistry) -> Result { - concat_string.push_str(&s); - concat_string.push_str("\n"); - } - _ => yield Err(ShellError::labeled_error_with_secondary( + if let Ok(s) = value.as_string() { + concat_string.push_str(&s); + } + else { + yield Err(ShellError::labeled_error_with_secondary( "Expected a string from pipeline", "requires string input", name_span, "value originates from here", value_span, - )), - + )) } } diff --git a/src/commands/lines.rs b/src/commands/lines.rs index 32f0523044..a78920e050 100644 --- a/src/commands/lines.rs +++ b/src/commands/lines.rs @@ -38,8 +38,8 @@ fn lines(args: CommandArgs, registry: &CommandRegistry) -> Result { + .map(move |v| { + if let Ok(s) = v.as_string() { let split_result: Vec<_> = s.lines().filter(|s| s.trim() != "").collect(); trace!("split result = {:?}", split_result); @@ -47,12 +47,11 @@ fn lines(args: CommandArgs, registry: &CommandRegistry) -> Result { + } else { let mut result = VecDeque::new(); let value_span = v.tag.span; diff --git a/src/commands/save.rs b/src/commands/save.rs index 3bb87029cd..d7c58f3d3a 100644 --- a/src/commands/save.rs +++ b/src/commands/save.rs @@ -146,7 +146,7 @@ fn save( } _ => { yield Err(ShellError::labeled_error( - "Save requires a filepath (1)", + "Save requires a filepath", "needs path", name_tag.clone(), )); @@ -154,7 +154,7 @@ fn save( }, None => { yield Err(ShellError::labeled_error( - "Save requires a filepath (2)", + "Save requires a filepath", "needs path", name_tag.clone(), )); @@ -162,7 +162,7 @@ fn save( } } else { yield Err(ShellError::labeled_error( - "Save requires a filepath (3)", + "Save requires a filepath", "needs path", name_tag.clone(), )); diff --git a/src/commands/size.rs b/src/commands/size.rs index 5a637ea94c..4687563b4a 100644 --- a/src/commands/size.rs +++ b/src/commands/size.rs @@ -2,7 +2,7 @@ use crate::commands::WholeStreamCommand; use crate::data::{value, TaggedDictBuilder}; use crate::prelude::*; use nu_errors::ShellError; -use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value}; +use nu_protocol::{ReturnSuccess, Signature, Value}; pub struct Size; @@ -35,17 +35,18 @@ fn size(args: CommandArgs, _registry: &CommandRegistry) -> Result { - ReturnSuccess::value(count(s, &v.tag)) + .map(move |v| { + if let Ok(s) = v.as_string() { + ReturnSuccess::value(count(&s, &v.tag)) + } else { + Err(ShellError::labeled_error_with_secondary( + "Expected a string from pipeline", + "requires string input", + name_span, + "value originates from here", + v.tag.span, + )) } - _ => Err(ShellError::labeled_error_with_secondary( - "Expected a string from pipeline", - "requires string input", - name_span, - "value originates from here", - v.tag.span, - )), }) .to_output_stream()) } diff --git a/src/commands/split_column.rs b/src/commands/split_column.rs index 8ed5a61d83..f856c109c0 100644 --- a/src/commands/split_column.rs +++ b/src/commands/split_column.rs @@ -57,8 +57,8 @@ fn split_column( Ok(input .values - .map(move |v| match v.value { - UntaggedValue::Primitive(Primitive::String(ref s)) => { + .map(move |v| { + if let Ok(s) = v.as_string() { let splitter = separator.replace("\\n", "\n"); trace!("splitting with {:?}", splitter); @@ -104,14 +104,15 @@ fn split_column( } ReturnSuccess::value(dict.into_value()) } + } else { + Err(ShellError::labeled_error_with_secondary( + "Expected a string from pipeline", + "requires string input", + name_span, + "value originates from here", + v.tag.span, + )) } - _ => Err(ShellError::labeled_error_with_secondary( - "Expected a string from pipeline", - "requires string input", - name_span, - "value originates from here", - v.tag.span, - )), }) .to_output_stream()) } diff --git a/src/commands/split_row.rs b/src/commands/split_row.rs index e0a803b713..5d8d712335 100644 --- a/src/commands/split_row.rs +++ b/src/commands/split_row.rs @@ -44,8 +44,8 @@ fn split_row( ) -> Result { let stream = input .values - .map(move |v| match v.value { - UntaggedValue::Primitive(Primitive::String(ref s)) => { + .map(move |v| { + if let Ok(s) = v.as_string() { let splitter = separator.item.replace("\\n", "\n"); trace!("splitting with {:?}", splitter); let split_result: Vec<_> = s.split(&splitter).filter(|s| s.trim() != "").collect(); @@ -59,8 +59,7 @@ fn split_row( )); } result - } - _ => { + } else { let mut result = VecDeque::new(); result.push_back(Err(ShellError::labeled_error_with_secondary( "Expected a string from pipeline", diff --git a/src/commands/to_bson.rs b/src/commands/to_bson.rs index 9fab91a9d1..8a21c796b3 100644 --- a/src/commands/to_bson.rs +++ b/src/commands/to_bson.rs @@ -56,6 +56,7 @@ pub fn value_to_bson_value(v: &Value) -> Result { } UntaggedValue::Primitive(Primitive::Nothing) => Bson::Null, UntaggedValue::Primitive(Primitive::String(s)) => Bson::String(s.clone()), + UntaggedValue::Primitive(Primitive::Line(s)) => Bson::String(s.clone()), UntaggedValue::Primitive(Primitive::ColumnPath(path)) => Bson::Array( path.iter() .map(|x| match &x.unspanned { diff --git a/src/commands/to_delimited_data.rs b/src/commands/to_delimited_data.rs index ceadfef803..0e74145577 100644 --- a/src/commands/to_delimited_data.rs +++ b/src/commands/to_delimited_data.rs @@ -137,6 +137,7 @@ fn to_string_tagged_value(v: &Value) -> Result { UntaggedValue::Primitive(Primitive::Path(_)) => Ok(v.as_string()?.to_string()), UntaggedValue::Table(_) => return Ok(String::from("[Table]")), UntaggedValue::Row(_) => return Ok(String::from("[Row]")), + UntaggedValue::Primitive(Primitive::Line(s)) => return Ok(s.to_string()), UntaggedValue::Primitive(Primitive::String(s)) => return Ok(s.to_string()), _ => { return Err(ShellError::labeled_error( diff --git a/src/commands/to_json.rs b/src/commands/to_json.rs index 10244a2260..8c460ce4d4 100644 --- a/src/commands/to_json.rs +++ b/src/commands/to_json.rs @@ -54,6 +54,7 @@ pub fn value_to_json_value(v: &Value) -> Result { UntaggedValue::Primitive(Primitive::Nothing) => serde_json::Value::Null, UntaggedValue::Primitive(Primitive::Pattern(s)) => serde_json::Value::String(s.clone()), UntaggedValue::Primitive(Primitive::String(s)) => serde_json::Value::String(s.clone()), + UntaggedValue::Primitive(Primitive::Line(s)) => serde_json::Value::String(s.clone()), UntaggedValue::Primitive(Primitive::ColumnPath(path)) => serde_json::Value::Array( path.iter() .map(|x| match &x.unspanned { diff --git a/src/commands/to_sqlite.rs b/src/commands/to_sqlite.rs index 0237b53e58..3a6a37012c 100644 --- a/src/commands/to_sqlite.rs +++ b/src/commands/to_sqlite.rs @@ -94,6 +94,7 @@ fn nu_value_to_sqlite_string(v: Value) -> String { Primitive::Bytes(u) => format!("{}", u), Primitive::Pattern(s) => format!("'{}'", s.replace("'", "''")), Primitive::String(s) => format!("'{}'", s.replace("'", "''")), + Primitive::Line(s) => format!("'{}'", s.replace("'", "''")), Primitive::Boolean(true) => "1".into(), Primitive::Boolean(_) => "0".into(), Primitive::Date(d) => format!("'{}'", d), diff --git a/src/commands/to_toml.rs b/src/commands/to_toml.rs index 7504d7def6..16091a2cf3 100644 --- a/src/commands/to_toml.rs +++ b/src/commands/to_toml.rs @@ -50,6 +50,7 @@ pub fn value_to_toml_value(v: &Value) -> Result { } UntaggedValue::Primitive(Primitive::Pattern(s)) => toml::Value::String(s.clone()), UntaggedValue::Primitive(Primitive::String(s)) => toml::Value::String(s.clone()), + UntaggedValue::Primitive(Primitive::Line(s)) => toml::Value::String(s.clone()), UntaggedValue::Primitive(Primitive::Path(s)) => { toml::Value::String(s.display().to_string()) } diff --git a/src/commands/to_yaml.rs b/src/commands/to_yaml.rs index 243ee80875..aa21108d99 100644 --- a/src/commands/to_yaml.rs +++ b/src/commands/to_yaml.rs @@ -51,6 +51,7 @@ pub fn value_to_yaml_value(v: &Value) -> Result { UntaggedValue::Primitive(Primitive::Nothing) => serde_yaml::Value::Null, UntaggedValue::Primitive(Primitive::Pattern(s)) => serde_yaml::Value::String(s.clone()), UntaggedValue::Primitive(Primitive::String(s)) => serde_yaml::Value::String(s.clone()), + UntaggedValue::Primitive(Primitive::Line(s)) => serde_yaml::Value::String(s.clone()), UntaggedValue::Primitive(Primitive::ColumnPath(path)) => { let mut out = vec![]; diff --git a/src/data/base.rs b/src/data/base.rs index 54341467f7..a73ea32940 100644 --- a/src/data/base.rs +++ b/src/data/base.rs @@ -186,6 +186,9 @@ fn coerce_compare_primitive( CompareValues::Decimals(BigDecimal::from(*left), right.clone()) } (String(left), String(right)) => CompareValues::String(left.clone(), right.clone()), + (Line(left), String(right)) => CompareValues::String(left.clone(), right.clone()), + (String(left), Line(right)) => CompareValues::String(left.clone(), right.clone()), + (Line(left), Line(right)) => CompareValues::String(left.clone(), right.clone()), (Date(left), Date(right)) => CompareValues::Date(left.clone(), right.clone()), (Date(left), Duration(right)) => CompareValues::DateDuration(left.clone(), right.clone()), _ => return Err((left.type_name(), right.type_name())), diff --git a/src/data/base/shape.rs b/src/data/base/shape.rs index 0cb086a434..324c1df37b 100644 --- a/src/data/base/shape.rs +++ b/src/data/base/shape.rs @@ -33,6 +33,7 @@ pub enum TypeShape { Decimal, Bytesize, String, + Line, ColumnPath, Pattern, Boolean, @@ -62,6 +63,7 @@ impl TypeShape { Primitive::Decimal(_) => TypeShape::Decimal, Primitive::Bytes(_) => TypeShape::Bytesize, Primitive::String(_) => TypeShape::String, + Primitive::Line(_) => TypeShape::Line, Primitive::ColumnPath(_) => TypeShape::ColumnPath, Primitive::Pattern(_) => TypeShape::Pattern, Primitive::Boolean(_) => TypeShape::Boolean, @@ -114,6 +116,7 @@ impl PrettyDebug for TypeShape { TypeShape::Decimal => ty("decimal"), TypeShape::Bytesize => ty("bytesize"), TypeShape::String => ty("string"), + TypeShape::Line => ty("line"), TypeShape::ColumnPath => ty("column-path"), TypeShape::Pattern => ty("pattern"), TypeShape::Boolean => ty("boolean"), @@ -208,6 +211,7 @@ pub enum InlineShape { Decimal(BigDecimal), Bytesize(u64), String(String), + Line(String), ColumnPath(ColumnPath), Pattern(String), Boolean(bool), @@ -242,6 +246,7 @@ impl InlineShape { Primitive::Decimal(decimal) => InlineShape::Decimal(decimal.clone()), Primitive::Bytes(bytesize) => InlineShape::Bytesize(*bytesize), Primitive::String(string) => InlineShape::String(string.clone()), + Primitive::Line(string) => InlineShape::Line(string.clone()), Primitive::ColumnPath(path) => InlineShape::ColumnPath(path.clone()), Primitive::Pattern(pattern) => InlineShape::Pattern(pattern.clone()), Primitive::Boolean(boolean) => InlineShape::Boolean(*boolean), @@ -327,6 +332,7 @@ impl PrettyDebug for FormatInlineShape { } } InlineShape::String(string) => b::primitive(format!("{}", string)), + InlineShape::Line(string) => b::primitive(format!("{}", string)), InlineShape::ColumnPath(path) => { b::intersperse(path.iter().map(|member| member.pretty()), b::keyword(".")) } diff --git a/src/data/primitive.rs b/src/data/primitive.rs index 2123e9e946..5bda3ccbfb 100644 --- a/src/data/primitive.rs +++ b/src/data/primitive.rs @@ -37,6 +37,7 @@ pub fn format_primitive(primitive: &Primitive, field_name: Option<&String>) -> S Primitive::Decimal(decimal) => format!("{}", decimal), Primitive::Pattern(s) => format!("{}", s), Primitive::String(s) => format!("{}", s), + Primitive::Line(s) => format!("{}", s), Primitive::ColumnPath(p) => { let mut members = p.iter(); let mut f = String::new(); diff --git a/src/data/types.rs b/src/data/types.rs index d140f31e22..b6b9c598e5 100644 --- a/src/data/types.rs +++ b/src/data/types.rs @@ -86,6 +86,10 @@ impl ExtractType for String { value: UntaggedValue::Primitive(Primitive::String(string)), .. } => Ok(string.clone()), + Value { + value: UntaggedValue::Primitive(Primitive::Line(string)), + .. + } => Ok(string.clone()), other => Err(ShellError::type_error("String", other.spanned_type_name())), } } diff --git a/src/data/value.rs b/src/data/value.rs index 5088c6621b..27670e7af9 100644 --- a/src/data/value.rs +++ b/src/data/value.rs @@ -27,6 +27,10 @@ pub fn string(s: impl Into) -> UntaggedValue { UntaggedValue::Primitive(Primitive::String(s.into())) } +pub fn line(s: impl Into) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::Line(s.into())) +} + pub fn column_path(s: Vec>) -> UntaggedValue { UntaggedValue::Primitive(Primitive::ColumnPath(ColumnPath::new( s.into_iter().map(|p| p.into()).collect(), diff --git a/src/plugins/match.rs b/src/plugins/match.rs index b513073eaf..830ec4af27 100644 --- a/src/plugins/match.rs +++ b/src/plugins/match.rs @@ -72,16 +72,14 @@ impl Plugin for Match { tag, } => { if let Some(val) = dict.entries.get(&self.column) { - match val { - Value { - value: UntaggedValue::Primitive(Primitive::String(s)), - .. - } => { - flag = self.regex.is_match(s); - } - Value { tag, .. } => { - return Err(ShellError::labeled_error("expected string", "value", tag)); - } + if let Ok(s) = val.as_string() { + flag = self.regex.is_match(&s); + } else { + return Err(ShellError::labeled_error( + "expected string", + "value", + val.tag(), + )); } } else { return Err(ShellError::labeled_error( diff --git a/src/plugins/parse.rs b/src/plugins/parse.rs index 8354cafb10..5dc9e34439 100644 --- a/src/plugins/parse.rs +++ b/src/plugins/parse.rs @@ -129,24 +129,16 @@ impl Plugin for Parse { fn filter(&mut self, input: Value) -> Result, ShellError> { let mut results = vec![]; - match &input { - Value { - tag, - value: UntaggedValue::Primitive(Primitive::String(s)), - } => { - //self.full_input.push_str(&s); + if let Ok(s) = input.as_string() { + for cap in self.regex.captures_iter(&s) { + let mut dict = TaggedDictBuilder::new(input.tag()); - for cap in self.regex.captures_iter(&s) { - let mut dict = TaggedDictBuilder::new(tag); - - for (idx, column_name) in self.column_names.iter().enumerate() { - dict.insert_untagged(column_name, value::string(&cap[idx + 1].to_string())); - } - - results.push(ReturnSuccess::value(dict.into_value())); + for (idx, column_name) in self.column_names.iter().enumerate() { + dict.insert_untagged(column_name, value::string(&cap[idx + 1].to_string())); } + + results.push(ReturnSuccess::value(dict.into_value())); } - _ => {} } Ok(results) } diff --git a/src/plugins/str.rs b/src/plugins/str.rs index dde12e72ee..566e9b9e44 100644 --- a/src/plugins/str.rs +++ b/src/plugins/str.rs @@ -155,6 +155,9 @@ impl Str { UntaggedValue::Primitive(Primitive::String(ref s)) => { Ok(self.apply(&s)?.into_value(value.tag())) } + UntaggedValue::Primitive(Primitive::Line(ref s)) => { + Ok(self.apply(&s)?.into_value(value.tag())) + } UntaggedValue::Row(_) => match self.field { Some(ref f) => { let fields = f.clone(); diff --git a/tests/filters_test.rs b/tests/filters_test.rs index 7f38b60477..e55a1289ad 100644 --- a/tests/filters_test.rs +++ b/tests/filters_test.rs @@ -30,6 +30,7 @@ fn converts_structured_table_to_csv_text() { r#" open csv_text_sample.txt | lines + | trim | split-column "," a b c d origin | last 1 | to-csv @@ -60,6 +61,7 @@ fn converts_structured_table_to_csv_text_skipping_headers_after_conversion() { r#" open csv_text_sample.txt | lines + | trim | split-column "," a b c d origin | last 1 | to-csv --headerless