diff --git a/Cargo.lock b/Cargo.lock index b4c5e79eae..6241e14498 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1704,6 +1704,7 @@ dependencies = [ "nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "nom-tracable 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "nom_locate 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "nu-source 0.1.0", "num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "onig_sys 69.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1746,6 +1747,20 @@ dependencies = [ "which 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "nu-source" +version = "0.1.0" +dependencies = [ + "derive-new 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", + "getset 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "language-reporting 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "nom-tracable 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "nom_locate 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pretty 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num-bigint" version = "0.2.3" diff --git a/Cargo.toml b/Cargo.toml index cbf34bd1f6..e81c4fdc40 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,9 +11,15 @@ repository = "https://github.com/nushell/nushell" homepage = "https://www.nushell.sh" documentation = "https://book.nushell.sh" +[workspace] + +members = ["crates/nu-source"] + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +nu-source = { path = "./crates/nu-source" } + rustyline = "5.0.4" chrono = { version = "0.4.9", features = ["serde"] } derive-new = "0.5.8" @@ -80,7 +86,7 @@ strip-ansi-escapes = "0.1.0" calamine = "0.16" umask = "0.1" futures-util = "0.3.0" -pretty = { version = "0.5.2" } +pretty = "0.5.2" termcolor = "1.0.5" console = "0.9.1" @@ -96,7 +102,6 @@ ptree = {version = "0.2" } image = { version = "0.22.2", default_features = false, features = ["png_codec", "jpeg"], optional = true } starship = { version = "0.26.4", optional = true} - [features] default = ["textview", "sys", "ps"] raw-key = ["rawkey", "neso"] diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000000..58456b5605 --- /dev/null +++ b/TODO.md @@ -0,0 +1,50 @@ +This pattern is extremely repetitive and can be abstracted: + +```rs + let args = args.evaluate_once(registry)?; + let tag = args.name_tag(); + let input = args.input; + + let stream = async_stream! { + let values: Vec = input.values.collect().await; + + let mut concat_string = String::new(); + let mut latest_tag: Option = None; + + 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( + "Expected a string from pipeline", + "requires string input", + name_span, + "value originates from here", + value_span, + )), + + } + } + +``` + +Do we need Display impls? + +Mandatory and Optional in parse_command + +trace_remaining? + +select_fields and select_fields take unnecessary Tag + +Value#value should be Value#untagged + +Unify dictionary building, probably around a macro + +sys plugin in own crate + +textview in own crate diff --git a/crates/nu-source/Cargo.toml b/crates/nu-source/Cargo.toml new file mode 100644 index 0000000000..d4338aff49 --- /dev/null +++ b/crates/nu-source/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "nu-source" +version = "0.1.0" +authors = ["Yehuda Katz "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +serde = { version = "1.0.102", features = ["derive"] } +derive-new = "0.5.8" +getset = "0.0.9" +nom_locate = "1.0.0" +nom-tracable = "0.4.1" +language-reporting = "0.4.0" +termcolor = "1.0.5" +pretty = "0.5.2" diff --git a/crates/nu-source/src/lib.rs b/crates/nu-source/src/lib.rs new file mode 100644 index 0000000000..840ba6a750 --- /dev/null +++ b/crates/nu-source/src/lib.rs @@ -0,0 +1,15 @@ +mod meta; +mod pretty; +mod term_colored; +mod text; +mod tracable; + +pub use self::meta::{ + span_for_spanned_list, tag_for_tagged_list, AnchorLocation, HasFallibleSpan, HasSpan, HasTag, + Span, Spanned, SpannedItem, Tag, Tagged, TaggedItem, +}; +pub use self::pretty::{ + b, DebugDoc, DebugDocBuilder, PrettyDebug, PrettyDebugWithSource, ShellAnnotation, +}; +pub use self::text::Text; +pub use self::tracable::{nom_input, NomSpan, TracableContext}; diff --git a/src/data/meta.rs b/crates/nu-source/src/meta.rs similarity index 85% rename from src/data/meta.rs rename to crates/nu-source/src/meta.rs index 5a12df2fe5..ea89b5df51 100644 --- a/src/data/meta.rs +++ b/crates/nu-source/src/meta.rs @@ -1,13 +1,24 @@ -use crate::context::AnchorLocation; -use crate::parser::parse::parser::TracableContext; -use crate::prelude::*; +use crate::pretty::{b, DebugDocBuilder, PrettyDebugWithSource}; +use crate::text::Text; +use crate::tracable::TracableContext; + use derive_new::new; use getset::Getters; use serde::Deserialize; use serde::Serialize; -use std::fmt; use std::path::{Path, PathBuf}; +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum AnchorLocation { + Url(String), + File(String), + Source(Text), +} + +pub trait HasTag { + fn tag(&self) -> Tag; +} + #[derive(new, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)] pub struct Spanned { pub span: Span, @@ -62,6 +73,7 @@ impl std::ops::Deref for Spanned { &self.item } } + #[derive(new, Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)] pub struct Tagged { pub tag: Tag, @@ -79,6 +91,12 @@ impl Tagged { } } +impl Tagged> { + pub fn items(&self) -> impl Iterator { + self.item.iter() + } +} + impl HasTag for Tagged { fn tag(&self) -> Tag { self.tag.clone() @@ -184,14 +202,8 @@ impl From<&Tag> for Tag { } } -impl From> for Span { - fn from(input: nom_locate::LocatedSpanEx<&str, TracableContext>) -> Span { - Span::new(input.offset, input.offset + input.fragment.len()) - } -} - -impl From> for Span { - fn from(input: nom_locate::LocatedSpanEx<&str, u64>) -> Span { +impl From> for Span { + fn from(input: nom_locate::LocatedSpanEx<&str, T>) -> Span { Span::new(input.offset, input.offset + input.fragment.len()) } } @@ -330,6 +342,10 @@ impl Tag { } } + pub fn anchor(&self) -> Option { + self.anchor.clone() + } + pub fn until(&self, other: impl Into) -> Tag { let other = other.into(); debug_assert!( @@ -376,6 +392,14 @@ impl Tag { pub fn tagged_string<'a>(&self, source: &'a str) -> Tagged { self.span.slice(source).to_string().tagged(self) } + + pub fn anchor_name(&self) -> Option { + match self.anchor { + Some(AnchorLocation::File(ref file)) => Some(file.clone()), + Some(AnchorLocation::Url(ref url)) => Some(url.clone()), + _ => None, + } + } } #[allow(unused)] @@ -418,6 +442,12 @@ pub struct Span { end: usize, } +impl From<&Span> for Span { + fn from(span: &Span) -> Span { + *span + } +} + impl From> for Span { fn from(input: Option) -> Span { match input { @@ -514,11 +544,11 @@ impl language_reporting::ReportingSpan for Span { } } -pub trait HasSpan: ToDebug { +pub trait HasSpan: PrettyDebugWithSource { fn span(&self) -> Span; } -pub trait HasFallibleSpan: ToDebug { +pub trait HasFallibleSpan: PrettyDebugWithSource { fn maybe_span(&self) -> Option; } @@ -530,31 +560,34 @@ impl HasFallibleSpan for T { impl HasSpan for Spanned where - Spanned: ToDebug, + Spanned: PrettyDebugWithSource, { fn span(&self) -> Span { self.span } } +impl PrettyDebugWithSource for Option { + fn pretty_debug(&self, source: &str) -> DebugDocBuilder { + match self { + None => b::description("no span"), + Some(span) => span.pretty_debug(source), + } + } +} + impl HasFallibleSpan for Option { fn maybe_span(&self) -> Option { *self } } -impl FormatDebug for Option { - fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result { - match self { - Option::None => write!(f, "no span"), - Option::Some(span) => FormatDebug::fmt_debug(span, f, source), - } - } -} - -impl FormatDebug for Span { - fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result { - write!(f, "{:?}", self.slice(source)) +impl PrettyDebugWithSource for Span { + fn pretty_debug(&self, source: &str) -> DebugDocBuilder { + b::typed( + "spanned", + b::keyword("for") + b::space() + b::description(format!("{:?}", source)), + ) } } @@ -564,21 +597,21 @@ impl HasSpan for Span { } } -impl FormatDebug for Option> +impl PrettyDebugWithSource for Option> where - Spanned: ToDebug, + Spanned: PrettyDebugWithSource, { - fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result { + fn pretty_debug(&self, source: &str) -> DebugDocBuilder { match self { - Option::None => write!(f, "nothing"), - Option::Some(spanned) => FormatDebug::fmt_debug(spanned, f, source), + None => b::description("nothing"), + Some(v) => v.pretty_debug(source), } } } impl HasFallibleSpan for Option> where - Spanned: ToDebug, + Spanned: PrettyDebugWithSource, { fn maybe_span(&self) -> Option { match self { @@ -588,21 +621,21 @@ where } } -impl FormatDebug for Option> +impl PrettyDebugWithSource for Option> where - Tagged: ToDebug, + Tagged: PrettyDebugWithSource, { - fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result { + fn pretty_debug(&self, source: &str) -> DebugDocBuilder { match self { - Option::None => write!(f, "nothing"), - Option::Some(item) => FormatDebug::fmt_debug(item, f, source), + None => b::description("nothing"), + Some(d) => d.pretty_debug(source), } } } impl HasFallibleSpan for Option> where - Tagged: ToDebug, + Tagged: PrettyDebugWithSource, { fn maybe_span(&self) -> Option { match self { @@ -614,33 +647,9 @@ where impl HasSpan for Tagged where - Tagged: ToDebug, + Tagged: PrettyDebugWithSource, { fn span(&self) -> Span { self.tag.span } } - -impl FormatDebug for Vec { - fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result { - write!(f, "[ ")?; - write!( - f, - "{}", - self.iter().map(|item| item.debug(source)).join(" ") - )?; - write!(f, " ]") - } -} - -impl FormatDebug for String { - fn fmt_debug(&self, f: &mut DebugFormatter, _source: &str) -> fmt::Result { - write!(f, "{}", self) - } -} - -impl FormatDebug for Spanned { - fn fmt_debug(&self, f: &mut DebugFormatter, _source: &str) -> fmt::Result { - write!(f, "{}", self.item) - } -} diff --git a/crates/nu-source/src/pretty.rs b/crates/nu-source/src/pretty.rs new file mode 100644 index 0000000000..12b201c848 --- /dev/null +++ b/crates/nu-source/src/pretty.rs @@ -0,0 +1,495 @@ +use crate::term_colored::TermColored; +use crate::text::Text; +use derive_new::new; +use pretty::{BoxAllocator, DocAllocator}; +use std::hash::Hash; +use termcolor::{Color, ColorSpec}; + +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)] +pub enum ShellStyle { + Delimiter, + Key, + Value, + Equals, + Kind, + Keyword, + Operator, + Variable, + Primitive, + Opaque, + Description, + Error, +} + +impl From for ColorSpec { + fn from(ann: ShellAnnotation) -> ColorSpec { + match ann.style { + ShellStyle::Delimiter => ColorSpec::new() + .set_fg(Some(Color::White)) + .set_intense(false) + .clone(), + ShellStyle::Key => ColorSpec::new() + .set_fg(Some(Color::Black)) + .set_intense(true) + .clone(), + ShellStyle::Value => ColorSpec::new() + .set_fg(Some(Color::White)) + .set_intense(true) + .clone(), + ShellStyle::Equals => ColorSpec::new() + .set_fg(Some(Color::Black)) + .set_intense(true) + .clone(), + ShellStyle::Kind => ColorSpec::new().set_fg(Some(Color::Cyan)).clone(), + ShellStyle::Variable => ColorSpec::new() + .set_fg(Some(Color::Green)) + .set_intense(true) + .clone(), + ShellStyle::Keyword => ColorSpec::new().set_fg(Some(Color::Magenta)).clone(), + ShellStyle::Operator => ColorSpec::new().set_fg(Some(Color::Yellow)).clone(), + ShellStyle::Primitive => ColorSpec::new() + .set_fg(Some(Color::Green)) + .set_intense(true) + .clone(), + ShellStyle::Opaque => ColorSpec::new() + .set_fg(Some(Color::Yellow)) + .set_intense(true) + .clone(), + ShellStyle::Description => ColorSpec::new() + .set_fg(Some(Color::Black)) + .set_intense(true) + .clone(), + ShellStyle::Error => ColorSpec::new() + .set_fg(Some(Color::Red)) + .set_intense(true) + .clone(), + } + } +} + +#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd, Hash, new)] +pub struct ShellAnnotation { + style: ShellStyle, +} + +impl std::fmt::Debug for ShellAnnotation { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.style) + } +} + +impl ShellAnnotation { + pub fn style(style: impl Into) -> ShellAnnotation { + ShellAnnotation { + style: style.into(), + } + } +} + +pub type PrettyDebugDoc = + pretty::Doc<'static, pretty::BoxDoc<'static, ShellAnnotation>, ShellAnnotation>; + +pub type PrettyDebugDocBuilder = pretty::DocBuilder<'static, pretty::BoxAllocator, ShellAnnotation>; + +pub use self::DebugDocBuilder as b; + +#[derive(Clone, new)] +pub struct DebugDocBuilder { + pub inner: PrettyDebugDocBuilder, +} + +impl PrettyDebug for DebugDocBuilder { + fn pretty(&self) -> DebugDocBuilder { + self.clone() + } +} + +impl std::ops::Add for DebugDocBuilder { + type Output = DebugDocBuilder; + + fn add(self, rhs: DebugDocBuilder) -> DebugDocBuilder { + DebugDocBuilder::new(self.inner.append(rhs.inner)) + } +} + +impl DebugDocBuilder { + pub fn from_doc(doc: DebugDoc) -> DebugDocBuilder { + DebugDocBuilder { + inner: BoxAllocator.nil().append(doc), + } + } + + pub fn blank() -> DebugDocBuilder { + BoxAllocator.nil().into() + } + + pub fn delimiter(string: impl std::fmt::Display) -> DebugDocBuilder { + DebugDocBuilder::styled(string, ShellStyle::Delimiter) + } + + pub fn key(string: impl std::fmt::Display) -> DebugDocBuilder { + DebugDocBuilder::styled(string, ShellStyle::Key) + } + + pub fn value(string: impl std::fmt::Display) -> DebugDocBuilder { + DebugDocBuilder::styled(string, ShellStyle::Value) + } + + pub fn as_value(self) -> DebugDocBuilder { + self.inner + .annotate(ShellAnnotation::style(ShellStyle::Value)) + .into() + } + + pub fn equals() -> DebugDocBuilder { + DebugDocBuilder::styled("=", ShellStyle::Equals) + } + + pub fn kind(string: impl std::fmt::Display) -> DebugDocBuilder { + DebugDocBuilder::styled(string, ShellStyle::Kind) + } + + pub fn as_kind(self) -> DebugDocBuilder { + self.inner + .annotate(ShellAnnotation::style(ShellStyle::Kind)) + .into() + } + + pub fn typed(kind: &str, value: DebugDocBuilder) -> DebugDocBuilder { + b::delimit("(", b::kind(kind) + b::space() + value.group(), ")").group() + } + + pub fn subtyped( + kind: &str, + subkind: impl std::fmt::Display, + value: DebugDocBuilder, + ) -> DebugDocBuilder { + b::delimit( + "(", + (b::kind(kind) + b::delimit("[", b::kind(format!("{}", subkind)), "]")).group() + + b::space() + + value.group(), + ")", + ) + .group() + } + + pub fn keyword(string: impl std::fmt::Display) -> DebugDocBuilder { + DebugDocBuilder::styled(string, ShellStyle::Keyword) + } + + pub fn var(string: impl std::fmt::Display) -> DebugDocBuilder { + DebugDocBuilder::styled(string, ShellStyle::Variable) + } + + pub fn operator(string: impl std::fmt::Display) -> DebugDocBuilder { + DebugDocBuilder::styled(string, ShellStyle::Operator) + } + + pub fn primitive(string: impl std::fmt::Display) -> DebugDocBuilder { + DebugDocBuilder::styled(format!("{}", string), ShellStyle::Primitive) + } + + pub fn opaque(string: impl std::fmt::Display) -> DebugDocBuilder { + DebugDocBuilder::styled(string, ShellStyle::Opaque) + } + + pub fn description(string: impl std::fmt::Display) -> DebugDocBuilder { + DebugDocBuilder::styled(string, ShellStyle::Description) + } + + pub fn error(string: impl std::fmt::Display) -> DebugDocBuilder { + DebugDocBuilder::styled(string, ShellStyle::Error) + } + + pub fn delimit(start: &str, doc: DebugDocBuilder, end: &str) -> DebugDocBuilder { + DebugDocBuilder::delimiter(start) + doc + DebugDocBuilder::delimiter(end) + } + + pub fn preceded(before: DebugDocBuilder, body: DebugDocBuilder) -> DebugDocBuilder { + if body.is_empty() { + body + } else { + before + body + } + } + + pub fn surrounded_option( + before: Option, + builder: Option, + after: Option, + ) -> DebugDocBuilder { + match builder { + None => DebugDocBuilder::blank(), + Some(b) => b::option(before) + b + b::option(after), + } + } + + pub fn preceded_option( + before: Option, + builder: Option, + ) -> DebugDocBuilder { + DebugDocBuilder::surrounded_option(before, builder, None) + } + + pub fn option(builder: Option) -> DebugDocBuilder { + match builder { + None => DebugDocBuilder::blank(), + Some(b) => b, + } + } + + pub fn space() -> DebugDocBuilder { + BoxAllocator.space().into() + } + + pub fn newline() -> DebugDocBuilder { + BoxAllocator.newline().into() + } + + pub fn is_empty(&self) -> bool { + match &self.inner.1 { + pretty::Doc::Nil => true, + _ => false, + } + } + + pub fn or(self, doc: DebugDocBuilder) -> DebugDocBuilder { + if self.is_empty() { + doc + } else { + self + } + } + + pub fn group(self) -> DebugDocBuilder { + self.inner.group().into() + } + + pub fn nest(self) -> DebugDocBuilder { + self.inner.nest(1).group().into() + } + + pub fn intersperse_with_source<'a, T: PrettyDebugWithSource + 'a>( + list: impl IntoIterator, + separator: DebugDocBuilder, + source: &str, + ) -> DebugDocBuilder { + BoxAllocator + .intersperse( + list.into_iter().filter_map(|item| { + let item = item.pretty_debug(source); + if item.is_empty() { + None + } else { + Some(item) + } + }), + separator, + ) + .into() + } + + pub fn intersperse( + list: impl IntoIterator, + separator: DebugDocBuilder, + ) -> DebugDocBuilder { + BoxAllocator + .intersperse( + list.into_iter().filter_map(|item| { + let item = item.pretty(); + if item.is_empty() { + None + } else { + Some(item) + } + }), + separator, + ) + .into() + } + + pub fn list(list: impl IntoIterator) -> DebugDocBuilder { + let mut result: DebugDocBuilder = BoxAllocator.nil().into(); + + for item in list { + result = result + item; + } + + result.into() + } + + fn styled(string: impl std::fmt::Display, style: ShellStyle) -> DebugDocBuilder { + BoxAllocator + .text(string.to_string()) + .annotate(ShellAnnotation::style(style)) + .into() + } +} + +impl std::ops::Deref for DebugDocBuilder { + type Target = PrettyDebugDocBuilder; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, new)] +pub struct DebugDoc { + pub inner: PrettyDebugDoc, +} + +pub trait PrettyDebugWithSource: Sized { + fn pretty_debug(&self, source: &str) -> DebugDocBuilder; + + // This is a transitional convenience method + fn debug(&self, source: impl Into) -> String + where + Self: Clone, + { + self.clone().debuggable(source).display() + } + + fn debuggable(self, source: impl Into) -> DebuggableWithSource { + DebuggableWithSource { + inner: self, + source: source.into(), + } + } +} + +impl PrettyDebugWithSource for T { + fn pretty_debug(&self, _source: &str) -> DebugDocBuilder { + self.pretty() + } +} + +pub struct DebuggableWithSource { + inner: T, + source: Text, +} + +impl PrettyDebug for DebuggableWithSource +where + T: PrettyDebugWithSource, +{ + fn pretty(&self) -> DebugDocBuilder { + self.inner.pretty_debug(&self.source) + } +} + +impl PrettyDebug for DebugDoc { + fn pretty(&self) -> DebugDocBuilder { + DebugDocBuilder::new(BoxAllocator.nil().append(self.inner.clone())) + } +} + +pub trait PrettyDebug { + fn pretty(&self) -> DebugDocBuilder; + + fn to_doc(&self) -> DebugDoc { + DebugDoc::new(self.pretty().into()) + } + + fn pretty_doc(&self) -> PrettyDebugDoc { + let builder = self.pretty(); + builder.inner.into() + } + + fn pretty_builder(&self) -> PrettyDebugDocBuilder { + let doc = self.pretty(); + doc.inner + } + + /// A convenience method that prints out the document without colors in + /// 70 columns. Generally, you should use plain_string or colored_string + /// if possible, but display() can be useful for trace lines and things + /// like that, where you don't have control over the terminal. + fn display(&self) -> String { + self.plain_string(70) + } + + fn plain_string(&self, width: usize) -> String { + let doc = self.pretty_doc(); + let mut buffer = termcolor::Buffer::no_color(); + + doc.render_raw(width, &mut TermColored::new(&mut buffer)) + .unwrap(); + + String::from_utf8_lossy(buffer.as_slice()).to_string() + } + + fn colored_string(&self, width: usize) -> String { + let doc = self.pretty_doc(); + let mut buffer = termcolor::Buffer::ansi(); + + doc.render_raw(width, &mut TermColored::new(&mut buffer)) + .unwrap(); + + String::from_utf8_lossy(buffer.as_slice()).to_string() + } +} + +impl Into for PrettyDebugDocBuilder { + fn into(self) -> DebugDocBuilder { + DebugDocBuilder { inner: self } + } +} + +impl std::ops::Deref for DebugDoc { + type Target = PrettyDebugDoc; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl From for PrettyDebugDoc { + fn from(input: DebugDoc) -> PrettyDebugDoc { + input.inner + } +} + +impl Into for DebugDocBuilder { + fn into(self) -> PrettyDebugDoc { + self.inner.into() + } +} + +fn hash_doc(doc: &PrettyDebugDoc, state: &mut H) { + match doc { + pretty::Doc::Nil => 0u8.hash(state), + pretty::Doc::Append(a, b) => { + 1u8.hash(state); + hash_doc(&*a, state); + hash_doc(&*b, state); + } + pretty::Doc::Group(a) => { + 2u8.hash(state); + hash_doc(&*a, state); + } + pretty::Doc::Nest(a, b) => { + 3u8.hash(state); + a.hash(state); + hash_doc(&*b, state); + } + pretty::Doc::Space => 4u8.hash(state), + pretty::Doc::Newline => 5u8.hash(state), + pretty::Doc::Text(t) => { + 6u8.hash(state); + t.hash(state); + } + pretty::Doc::Annotated(a, b) => { + 7u8.hash(state); + a.hash(state); + hash_doc(&*b, state); + } + } +} + +impl std::hash::Hash for DebugDoc { + fn hash(&self, state: &mut H) { + hash_doc(&self.inner, state); + } +} diff --git a/crates/nu-source/src/term_colored.rs b/crates/nu-source/src/term_colored.rs new file mode 100644 index 0000000000..050041dad3 --- /dev/null +++ b/crates/nu-source/src/term_colored.rs @@ -0,0 +1,51 @@ +use crate::pretty::ShellAnnotation; +use pretty::{Render, RenderAnnotated}; +use std::io; +use termcolor::WriteColor; + +pub struct TermColored<'a, W> { + color_stack: Vec, + upstream: &'a mut W, +} + +impl<'a, W> TermColored<'a, W> { + pub fn new(upstream: &'a mut W) -> TermColored<'a, W> { + TermColored { + color_stack: Vec::new(), + upstream, + } + } +} + +impl<'a, W> Render for TermColored<'a, W> +where + W: io::Write, +{ + type Error = io::Error; + + fn write_str(&mut self, s: &str) -> io::Result { + self.upstream.write(s.as_bytes()) + } + + fn write_str_all(&mut self, s: &str) -> io::Result<()> { + self.upstream.write_all(s.as_bytes()) + } +} + +impl<'a, W> RenderAnnotated for TermColored<'a, W> +where + W: WriteColor, +{ + fn push_annotation(&mut self, ann: &ShellAnnotation) -> Result<(), Self::Error> { + self.color_stack.push(*ann); + self.upstream.set_color(&(*ann).into()) + } + + fn pop_annotation(&mut self) -> Result<(), Self::Error> { + self.color_stack.pop(); + match self.color_stack.last() { + Some(previous) => self.upstream.set_color(&(*previous).into()), + None => self.upstream.reset(), + } + } +} diff --git a/src/parser/parse/text.rs b/crates/nu-source/src/text.rs similarity index 98% rename from src/parser/parse/text.rs rename to crates/nu-source/src/text.rs index a3a9924b7e..3448ac07a2 100644 --- a/src/parser/parse/text.rs +++ b/crates/nu-source/src/text.rs @@ -74,6 +74,12 @@ impl From<&str> for Text { } } +impl From<&Text> for Text { + fn from(text: &Text) -> Self { + text.clone() + } +} + impl std::borrow::Borrow for Text { fn borrow(&self) -> &str { &*self diff --git a/crates/nu-source/src/tracable.rs b/crates/nu-source/src/tracable.rs new file mode 100644 index 0000000000..34d260949d --- /dev/null +++ b/crates/nu-source/src/tracable.rs @@ -0,0 +1,32 @@ +use derive_new::new; +use nom_locate::LocatedSpanEx; +use nom_tracable::{HasTracableInfo, TracableInfo}; + +pub type NomSpan<'a> = LocatedSpanEx<&'a str, TracableContext>; + +#[derive(Debug, Clone, Copy, PartialEq, new)] +pub struct TracableContext { + pub(crate) info: TracableInfo, +} + +impl HasTracableInfo for TracableContext { + fn get_tracable_info(&self) -> TracableInfo { + self.info + } + + fn set_tracable_info(self, info: TracableInfo) -> Self { + TracableContext { info } + } +} + +impl std::ops::Deref for TracableContext { + type Target = TracableInfo; + + fn deref(&self) -> &TracableInfo { + &self.info + } +} + +pub fn nom_input(s: &str) -> NomSpan<'_> { + LocatedSpanEx::new_extra(s, TracableContext::new(TracableInfo::new())) +} diff --git a/src/cli.rs b/src/cli.rs index 64d562f97e..4554b6bdcd 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,13 +1,15 @@ use crate::commands::classified::{ - ClassifiedCommand, ClassifiedInputStream, ClassifiedPipeline, ExternalCommand, InternalCommand, - StreamNext, + ClassifiedCommand, ClassifiedInputStream, ClassifiedPipeline, ExternalArg, ExternalArgs, + ExternalCommand, InternalCommand, StreamNext, }; use crate::commands::plugin::JsonRpc; use crate::commands::plugin::{PluginCommand, PluginSink}; use crate::commands::whole_stream_command; use crate::context::Context; -use crate::data::config; -use crate::data::Value; +use crate::data::{ + base::{UntaggedValue, Value}, + config, +}; pub(crate) use crate::errors::ShellError; #[cfg(not(feature = "starship-prompt"))] use crate::git::current_branch; @@ -19,6 +21,7 @@ use crate::parser::{ TokenNode, }; use crate::prelude::*; +use nu_source::{Spanned, Tagged}; use log::{debug, log_enabled, trace}; use rustyline::error::ReadlineError; @@ -381,7 +384,7 @@ pub async fn cli() -> Result<(), Box> { let edit_mode = config::config(Tag::unknown())? .get("edit_mode") - .map(|s| match s.as_string().unwrap().as_ref() { + .map(|s| match s.value.expect_string() { "vi" => EditMode::Vi, "emacs" => EditMode::Emacs, _ => EditMode::Emacs, @@ -448,7 +451,7 @@ pub async fn cli() -> Result<(), Box> { LineResult::CtrlC => { let config_ctrlc_exit = config::config(Tag::unknown())? .get("ctrlc_exit") - .map(|s| match s.as_string().unwrap().as_ref() { + .map(|s| match s.value.expect_string() { "true" => true, _ => false, }) @@ -501,8 +504,8 @@ fn set_env_from_config() { let value = config.get("env"); match value { - Some(Tagged { - item: Value::Row(r), + Some(Value { + value: UntaggedValue::Row(r), .. }) => { for (k, v) in &r.entries { @@ -524,8 +527,8 @@ fn set_env_from_config() { match value { Some(value) => match value { - Tagged { - item: Value::Table(table), + Value { + value: UntaggedValue::Table(table), .. } => { let mut paths = vec![]; @@ -583,11 +586,11 @@ async fn process_line(readline: Result, ctx: &mut Context Err(err) => return LineResult::Error(line.to_string(), err), }; - match pipeline.commands.last() { + match pipeline.commands.list.last() { Some(ClassifiedCommand::External(_)) => {} _ => pipeline .commands - .item + .list .push(ClassifiedCommand::Internal(InternalCommand { name: "autoview".to_string(), name_tag: Tag::unknown(), @@ -595,13 +598,13 @@ async fn process_line(readline: Result, ctx: &mut Context Box::new(hir::Expression::synthetic_string("autoview")), None, None, - ) - .spanned_unknown(), + Span::unknown(), + ), })), } let mut input = ClassifiedInputStream::new(); - let mut iter = pipeline.commands.item.into_iter().peekable(); + let mut iter = pipeline.commands.list.into_iter().peekable(); // Check the config to see if we need to update the path // TODO: make sure config is cached so we don't path this load every call @@ -659,8 +662,8 @@ async fn process_line(readline: Result, ctx: &mut Context let mut output_stream: OutputStream = val.into(); loop { match output_stream.try_next().await { - Ok(Some(ReturnSuccess::Value(Tagged { - item: Value::Error(e), + Ok(Some(ReturnSuccess::Value(Value { + value: UntaggedValue::Error(e), .. }))) => { return LineResult::Error(line.to_string(), e); @@ -723,7 +726,7 @@ fn classify_pipeline( source: &Text, ) -> Result { let mut pipeline_list = vec![pipeline.clone()]; - let mut iterator = TokensIterator::all(&mut pipeline_list, pipeline.span()); + let mut iterator = TokensIterator::all(&mut pipeline_list, source.clone(), pipeline.span()); let result = expand_syntax( &PipelineShape, @@ -749,19 +752,21 @@ pub(crate) fn external_command( context: &ExpandContext, name: Tagged<&str>, ) -> Result { - let Spanned { item, span } = expand_syntax(&ExternalTokensShape, tokens, context)?; + let Spanned { item, span } = expand_syntax(&ExternalTokensShape, tokens, context)?.tokens; Ok(ClassifiedCommand::External(ExternalCommand { name: name.to_string(), name_tag: name.tag(), - args: item - .iter() - .map(|x| Tagged { - tag: x.span.into(), - item: x.item.clone(), - }) - .collect::>() - .spanned(span), + args: ExternalArgs { + list: item + .iter() + .map(|x| ExternalArg { + tag: x.span.into(), + arg: x.item.clone(), + }) + .collect(), + span, + }, })) } diff --git a/src/commands/append.rs b/src/commands/append.rs index fe22c9065e..a41e3e4a23 100644 --- a/src/commands/append.rs +++ b/src/commands/append.rs @@ -5,7 +5,7 @@ use crate::prelude::*; #[derive(Deserialize)] struct AppendArgs { - row: Tagged, + row: Value, } pub struct Append; @@ -40,7 +40,7 @@ fn append( AppendArgs { row }: AppendArgs, RunnableContext { input, .. }: RunnableContext, ) -> Result { - let mut after: VecDeque> = VecDeque::new(); + let mut after: VecDeque = VecDeque::new(); after.push_back(row); Ok(OutputStream::from_input(input.values.chain(after))) diff --git a/src/commands/autoview.rs b/src/commands/autoview.rs index 0d92553f5e..26e9532697 100644 --- a/src/commands/autoview.rs +++ b/src/commands/autoview.rs @@ -93,9 +93,9 @@ pub fn autoview( let raw = raw.clone(); - let input: Vec> = new_input.into(); + let input: Vec = new_input.into(); - if input.len() > 0 && input.iter().all(|value| value.is_error()) { + if input.len() > 0 && input.iter().all(|value| value.value.is_error()) { let first = &input[0]; let mut host = context.host.clone(); @@ -107,7 +107,7 @@ pub fn autoview( Ok(val) => val }; - crate::cli::print_err(first.item.expect_error(), &*host, &context.source); + crate::cli::print_err(first.value.expect_error(), &*host, &context.source); return; } @@ -131,30 +131,30 @@ pub fn autoview( _ => { if let ReturnSuccess::Value(x) = x { match x { - Tagged { - item: Value::Primitive(Primitive::String(ref s)), + Value { + value: UntaggedValue::Primitive(Primitive::String(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).tagged(Tag { anchor, span })); + stream.push_back(UntaggedValue::string(s).into_value(Tag { anchor, span })); let result = text.run(raw.with_input(stream.into()), &context.commands); result.collect::>().await; } else { outln!("{}", s); } } - Tagged { - item: Value::Primitive(Primitive::String(s)), + Value { + value: UntaggedValue::Primitive(Primitive::String(s)), .. } => { outln!("{}", s); } - Tagged { item: Value::Primitive(Primitive::Binary(ref b)), .. } => { + Value { value: UntaggedValue::Primitive(Primitive::Binary(ref b)), .. } => { if let Some(binary) = binary { let mut stream = VecDeque::new(); - stream.push_back(x.clone()); + stream.push_back(x); let result = binary.run(raw.with_input(stream.into()), &context.commands); result.collect::>().await; } else { @@ -163,13 +163,13 @@ pub fn autoview( } } - Tagged { item: Value::Error(e), .. } => { + Value { value: UntaggedValue::Error(e), .. } => { yield Err(e); } - Tagged { item: ref item, .. } => { + Value { value: ref item, .. } => { if let Some(table) = table { let mut stream = VecDeque::new(); - stream.push_back(x.clone()); + stream.push_back(x); let result = table.run(raw.with_input(stream.into()), &context.commands); result.collect::>().await; } else { @@ -188,7 +188,7 @@ pub fn autoview( // Needed for async_stream to type check if false { - yield ReturnSuccess::value(Value::nothing().tagged_unknown()); + yield ReturnSuccess::value(UntaggedValue::nothing().into_untagged_value()); } })) } diff --git a/src/commands/classified.rs b/src/commands/classified.rs index 7dd72af4fa..da857135d4 100644 --- a/src/commands/classified.rs +++ b/src/commands/classified.rs @@ -4,9 +4,8 @@ use bytes::{BufMut, BytesMut}; use derive_new::new; use futures::stream::StreamExt; use futures_codec::{Decoder, Encoder, Framed}; -use itertools::Itertools; use log::{log_enabled, trace}; -use std::fmt; +use nu_source::PrettyDebug; use std::io::{Error, ErrorKind}; use subprocess::Exec; @@ -54,7 +53,7 @@ pub(crate) struct ClassifiedInputStream { impl ClassifiedInputStream { pub(crate) fn new() -> ClassifiedInputStream { ClassifiedInputStream { - objects: vec![Value::nothing().tagged(Tag::unknown())].into(), + objects: vec![UntaggedValue::nothing().into_value(Tag::unknown())].into(), stdin: None, } } @@ -75,16 +74,42 @@ impl ClassifiedInputStream { } #[derive(Debug, Clone)] -pub(crate) struct ClassifiedPipeline { - pub(crate) commands: Spanned>, +pub struct Commands { + pub list: Vec, + pub span: Span, } -impl FormatDebug for ClassifiedPipeline { - fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result { - f.say_str( - "classified pipeline", - self.commands.iter().map(|c| c.debug(source)).join(" | "), +impl std::ops::Deref for Commands { + type Target = [ClassifiedCommand]; + + fn deref(&self) -> &Self::Target { + &self.list + } +} + +#[derive(Debug, Clone)] +pub(crate) struct ClassifiedPipeline { + pub commands: Commands, +} + +impl ClassifiedPipeline { + pub fn commands(list: Vec, span: impl Into) -> ClassifiedPipeline { + ClassifiedPipeline { + commands: Commands { + list, + span: span.into(), + }, + } + } +} + +impl PrettyDebugWithSource for ClassifiedPipeline { + fn pretty_debug(&self, source: &str) -> DebugDocBuilder { + b::intersperse( + self.commands.iter().map(|c| c.pretty_debug(source)), + b::operator(" | "), ) + .or(b::delimit("<", b::description("empty pipeline"), ">")) } } @@ -95,22 +120,22 @@ impl HasSpan for ClassifiedPipeline { } #[derive(Debug, Clone, Eq, PartialEq)] -pub(crate) enum ClassifiedCommand { +pub enum ClassifiedCommand { #[allow(unused)] Expr(TokenNode), - Internal(InternalCommand), #[allow(unused)] - Dynamic(Spanned), + Dynamic(hir::Call), + Internal(InternalCommand), External(ExternalCommand), } -impl FormatDebug for ClassifiedCommand { - fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result { +impl PrettyDebugWithSource for ClassifiedCommand { + fn pretty_debug(&self, source: &str) -> DebugDocBuilder { match self { - ClassifiedCommand::Expr(expr) => expr.fmt_debug(f, source), - ClassifiedCommand::Internal(internal) => internal.fmt_debug(f, source), - ClassifiedCommand::Dynamic(dynamic) => dynamic.fmt_debug(f, source), - ClassifiedCommand::External(external) => external.fmt_debug(f, source), + ClassifiedCommand::Expr(token) => b::typed("command", token.pretty_debug(source)), + ClassifiedCommand::Dynamic(call) => b::typed("command", call.pretty_debug(source)), + ClassifiedCommand::Internal(internal) => internal.pretty_debug(source), + ClassifiedCommand::External(external) => external.pretty_debug(source), } } } @@ -127,10 +152,19 @@ impl HasSpan for ClassifiedCommand { } #[derive(new, Debug, Clone, Eq, PartialEq)] -pub(crate) struct InternalCommand { +pub struct InternalCommand { pub(crate) name: String, pub(crate) name_tag: Tag, - pub(crate) args: Spanned, + pub(crate) args: hir::Call, +} + +impl PrettyDebugWithSource for InternalCommand { + fn pretty_debug(&self, source: &str) -> DebugDocBuilder { + b::typed( + "internal command", + b::description(&self.name) + b::space() + self.args.pretty_debug(source), + ) + } } impl HasSpan for InternalCommand { @@ -141,12 +175,6 @@ impl HasSpan for InternalCommand { } } -impl FormatDebug for InternalCommand { - fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result { - f.say("internal", self.args.debug(source)) - } -} - #[derive(new, Debug, Eq, PartialEq)] pub(crate) struct DynamicCommand { pub(crate) args: hir::Call, @@ -165,21 +193,15 @@ impl InternalCommand { trace!(target: "nu::run::internal", "{}", self.args.debug(&source)); } - let objects: InputStream = trace_stream!(target: "nu::trace_stream::internal", source: source, "input" = input.objects); + let objects: InputStream = + trace_stream!(target: "nu::trace_stream::internal", "input" = input.objects); let command = context.expect_command(&self.name); - let result = { - context.run_command( - command, - self.name_tag.clone(), - self.args.item, - &source, - objects, - ) - }; + let result = + { context.run_command(command, self.name_tag.clone(), self.args, &source, objects) }; - let result = trace_out_stream!(target: "nu::trace_stream::internal", source: source, "output" = result); + let result = trace_out_stream!(target: "nu::trace_stream::internal", "output" = result); let mut result = result.values; let mut context = context.clone(); @@ -200,13 +222,13 @@ impl InternalCommand { } CommandAction::EnterHelpShell(value) => { match value { - Tagged { - item: Value::Primitive(Primitive::String(cmd)), + Value { + value: UntaggedValue::Primitive(Primitive::String(cmd)), tag, } => { context.shell_manager.insert_at_current(Box::new( HelpShell::for_command( - Value::string(cmd).tagged(tag), + UntaggedValue::string(cmd).into_value(tag), &context.registry(), ).unwrap(), )); @@ -250,7 +272,7 @@ impl InternalCommand { Ok(ReturnSuccess::DebugValue(v)) => { yielded = true; - let doc = v.item.pretty_doc(); + let doc = PrettyDebug::pretty_doc(&v); let mut buffer = termcolor::Buffer::ansi(); doc.render_raw( @@ -260,7 +282,7 @@ impl InternalCommand { let value = String::from_utf8_lossy(buffer.as_slice()); - yield Ok(Value::string(value).tagged_unknown()) + yield Ok(UntaggedValue::string(value).into_untagged_value()) } Err(err) => { @@ -276,23 +298,60 @@ impl InternalCommand { } #[derive(Debug, Clone, Eq, PartialEq)] -pub(crate) struct ExternalCommand { +pub struct ExternalArg { + pub arg: String, + pub tag: Tag, +} + +impl std::ops::Deref for ExternalArg { + type Target = str; + + fn deref(&self) -> &str { + &self.arg + } +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct ExternalArgs { + pub list: Vec, + pub span: Span, +} + +impl ExternalArgs { + pub fn iter(&self) -> impl Iterator { + self.list.iter() + } +} + +impl std::ops::Deref for ExternalArgs { + type Target = [ExternalArg]; + + fn deref(&self) -> &[ExternalArg] { + &self.list + } +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct ExternalCommand { pub(crate) name: String, pub(crate) name_tag: Tag, - pub(crate) args: Spanned>>, + pub(crate) args: ExternalArgs, } -impl FormatDebug for ExternalCommand { - fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result { - write!(f, "{}", self.name)?; - - if self.args.item.len() > 0 { - write!(f, " ")?; - write!(f, "{}", self.args.iter().map(|i| i.debug(source)).join(" "))?; - } - - Ok(()) +impl PrettyDebug for ExternalCommand { + fn pretty(&self) -> DebugDocBuilder { + b::typed( + "external command", + b::description(&self.name) + + b::preceded( + b::space(), + b::intersperse( + self.args.iter().map(|a| b::primitive(format!("{}", a.arg))), + b::space(), + ), + ), + ) } } @@ -317,13 +376,13 @@ impl ExternalCommand { stream_next: StreamNext, ) -> Result { let stdin = input.stdin; - let inputs: Vec> = input.objects.into_vec().await; + let inputs: Vec = input.objects.into_vec().await; trace!(target: "nu::run::external", "-> {}", self.name); trace!(target: "nu::run::external", "inputs = {:?}", inputs); let mut arg_string = format!("{}", self.name); - for arg in &self.args.item { + for arg in self.args.iter() { arg_string.push_str(&arg); } @@ -334,13 +393,13 @@ impl ExternalCommand { let input_strings = inputs .iter() .map(|i| { - i.as_string().map_err(|_| { - let arg = self.args.iter().find(|arg| arg.item.contains("$it")); + i.as_string().map(|s| s.to_string()).map_err(|_| { + let arg = self.args.iter().find(|arg| arg.contains("$it")); if let Some(arg) = arg { ShellError::labeled_error( "External $it needs string data", "given row instead of string data", - arg.tag(), + &arg.tag, ) } else { ShellError::labeled_error( @@ -368,7 +427,7 @@ impl ExternalCommand { process = Exec::shell(itertools::join(commands, " && ")) } else { process = Exec::cmd(&self.name); - for arg in &self.args.item { + for arg in self.args.iter() { let arg_chars: Vec<_> = arg.chars().collect(); if arg_chars.len() > 1 && arg_chars[0] == '"' @@ -378,7 +437,7 @@ impl ExternalCommand { let new_arg: String = arg_chars[1..arg_chars.len() - 1].iter().collect(); process = process.arg(new_arg); } else { - process = process.arg(arg.item.clone()); + process = process.arg(arg.arg.clone()); } } } @@ -435,10 +494,11 @@ impl ExternalCommand { 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()).tagged(&name_tag)); + let stream = stream.map(move |line| { + UntaggedValue::string(line.unwrap()).into_value(&name_tag) + }); Ok(ClassifiedInputStream::from_input_stream( - stream.boxed() as BoxStream<'static, Tagged> + stream.boxed() as BoxStream<'static, Value> )) } } diff --git a/src/commands/clip.rs b/src/commands/clip.rs index ac3ded1d4b..3b59d9eed6 100644 --- a/src/commands/clip.rs +++ b/src/commands/clip.rs @@ -40,7 +40,7 @@ pub mod clipboard { RunnableContext { input, name, .. }: RunnableContext, ) -> Result { let stream = async_stream! { - let values: Vec> = input.values.collect().await; + let values: Vec = input.values.collect().await; let mut clip_stream = inner_clip(values, name).await; while let Some(value) = clip_stream.next().await { @@ -53,7 +53,7 @@ pub mod clipboard { Ok(OutputStream::from(stream)) } - async fn inner_clip(input: Vec>, name: Tag) -> OutputStream { + async fn inner_clip(input: Vec, name: Tag) -> OutputStream { let mut clip_context: ClipboardContext = ClipboardProvider::new().unwrap(); let mut new_copy_data = String::new(); diff --git a/src/commands/command.rs b/src/commands/command.rs index 49166d9157..97c4fa373a 100644 --- a/src/commands/command.rs +++ b/src/commands/command.rs @@ -7,7 +7,6 @@ use crate::prelude::*; use derive_new::new; use getset::Getters; use serde::{Deserialize, Serialize}; -use std::fmt; use std::ops::Deref; use std::path::PathBuf; use std::sync::atomic::AtomicBool; @@ -19,12 +18,6 @@ pub struct UnevaluatedCallInfo { pub name_tag: Tag, } -impl FormatDebug for UnevaluatedCallInfo { - fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result { - self.args.fmt_debug(f, source) - } -} - impl UnevaluatedCallInfo { pub fn evaluate( self, @@ -85,7 +78,7 @@ pub struct RawCommandArgs { } impl RawCommandArgs { - pub fn with_input(self, input: Vec>) -> CommandArgs { + pub fn with_input(self, input: Vec) -> CommandArgs { CommandArgs { host: self.host, ctrl_c: self.ctrl_c, @@ -106,12 +99,6 @@ impl std::fmt::Debug for CommandArgs { } } -impl FormatDebug for CommandArgs { - fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result { - self.call_info.fmt_debug(f, source) - } -} - impl CommandArgs { pub fn evaluate_once( self, @@ -366,11 +353,11 @@ impl EvaluatedCommandArgs { &self.call_info.args } - pub fn nth(&self, pos: usize) -> Option<&Tagged> { + pub fn nth(&self, pos: usize) -> Option<&Value> { self.call_info.args.nth(pos) } - pub fn expect_nth(&self, pos: usize) -> Result<&Tagged, ShellError> { + pub fn expect_nth(&self, pos: usize) -> Result<&Value, ShellError> { self.call_info.args.expect_nth(pos) } @@ -378,11 +365,11 @@ impl EvaluatedCommandArgs { self.call_info.args.len() } - pub fn get(&self, name: &str) -> Option<&Tagged> { + pub fn get(&self, name: &str) -> Option<&Value> { self.call_info.args.get(name) } - pub fn slice_from(&self, from: usize) -> Vec> { + pub fn slice_from(&self, from: usize) -> Vec { let positional = &self.call_info.args.positional; match positional { @@ -402,55 +389,50 @@ pub enum CommandAction { Exit, Error(ShellError), EnterShell(String), - EnterValueShell(Tagged), - EnterHelpShell(Tagged), + EnterValueShell(Value), + EnterHelpShell(Value), PreviousShell, NextShell, LeaveShell, } -impl FormatDebug for CommandAction { - fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result { +impl PrettyDebug for CommandAction { + fn pretty(&self) -> DebugDocBuilder { match self { - CommandAction::ChangePath(s) => write!(f, "action:change-path={}", s), - CommandAction::Exit => write!(f, "action:exit"), - CommandAction::Error(_) => write!(f, "action:error"), - CommandAction::EnterShell(s) => write!(f, "action:enter-shell={}", s), - CommandAction::EnterValueShell(t) => { - write!(f, "action:enter-value-shell={}", t.debug(source)) - } - CommandAction::EnterHelpShell(t) => { - write!(f, "action:enter-help-shell={}", t.debug(source)) - } - CommandAction::PreviousShell => write!(f, "action:previous-shell"), - CommandAction::NextShell => write!(f, "action:next-shell"), - CommandAction::LeaveShell => write!(f, "action:leave-shell"), + CommandAction::ChangePath(path) => b::typed("change path", b::description(path)), + CommandAction::Exit => b::description("exit"), + CommandAction::Error(_) => b::error("error"), + CommandAction::EnterShell(s) => b::typed("enter shell", b::description(s)), + CommandAction::EnterValueShell(v) => b::typed("enter value shell", v.pretty()), + CommandAction::EnterHelpShell(v) => b::typed("enter help shell", v.pretty()), + CommandAction::PreviousShell => b::description("previous shell"), + CommandAction::NextShell => b::description("next shell"), + CommandAction::LeaveShell => b::description("leave shell"), } } } #[derive(Debug, Clone, Serialize, Deserialize)] pub enum ReturnSuccess { - Value(Tagged), - DebugValue(Tagged), + Value(Value), + DebugValue(Value), Action(CommandAction), } -pub type ReturnValue = Result; - -impl FormatDebug for ReturnValue { - fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result { +impl PrettyDebug for ReturnSuccess { + fn pretty(&self) -> DebugDocBuilder { match self { - Err(err) => write!(f, "{}", err.debug(source)), - Ok(ReturnSuccess::Value(v)) => write!(f, "{}", v.debug(source)), - Ok(ReturnSuccess::DebugValue(v)) => v.fmt_debug(f, source), - Ok(ReturnSuccess::Action(a)) => write!(f, "{}", a.debug(source)), + ReturnSuccess::Value(value) => b::typed("value", value.pretty()), + ReturnSuccess::DebugValue(value) => b::typed("debug value", value.pretty()), + ReturnSuccess::Action(action) => b::typed("action", action.pretty()), } } } -impl From> for ReturnValue { - fn from(input: Tagged) -> ReturnValue { +pub type ReturnValue = Result; + +impl From for ReturnValue { + fn from(input: Value) -> ReturnValue { Ok(ReturnSuccess::Value(input)) } } @@ -460,11 +442,11 @@ impl ReturnSuccess { Ok(ReturnSuccess::Action(CommandAction::ChangePath(path))) } - pub fn value(input: impl Into>) -> ReturnValue { + pub fn value(input: impl Into) -> ReturnValue { Ok(ReturnSuccess::Value(input.into())) } - pub fn debug_value(input: impl Into>) -> ReturnValue { + pub fn debug_value(input: impl Into) -> ReturnValue { Ok(ReturnSuccess::DebugValue(input.into())) } @@ -521,7 +503,7 @@ pub trait PerItemCommand: Send + Sync { call_info: &CallInfo, registry: &CommandRegistry, raw_args: &RawCommandArgs, - input: Tagged, + input: Value, ) -> Result; fn is_binary(&self) -> bool { @@ -534,6 +516,29 @@ pub enum Command { PerItem(Arc), } +impl PrettyDebugWithSource for Command { + fn pretty_debug(&self, source: &str) -> DebugDocBuilder { + match self { + Command::WholeStream(command) => b::typed( + "whole stream command", + b::description(command.name()) + + b::space() + + b::equals() + + b::space() + + command.signature().pretty_debug(source), + ), + Command::PerItem(command) => b::typed( + "per item command", + b::description(command.name()) + + b::space() + + b::equals() + + b::space() + + command.signature().pretty_debug(source), + ), + } + } +} + impl std::fmt::Debug for Command { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { diff --git a/src/commands/compact.rs b/src/commands/compact.rs index 4660e88adc..b2bd01b29d 100644 --- a/src/commands/compact.rs +++ b/src/commands/compact.rs @@ -1,8 +1,10 @@ use crate::commands::WholeStreamCommand; +use crate::data::base::UntaggedValue; use crate::errors::ShellError; use crate::parser::registry::{CommandRegistry, Signature}; use crate::prelude::*; use futures::stream::StreamExt; +use nu_source::Tagged; pub struct Compact; @@ -42,8 +44,8 @@ pub fn compact( item.is_some() } else { match item { - Tagged { - item: Value::Row(ref r), + Value { + value: UntaggedValue::Row(ref r), .. } => columns .iter() diff --git a/src/commands/config.rs b/src/commands/config.rs index 3c41cceae4..1cabfd2c57 100644 --- a/src/commands/config.rs +++ b/src/commands/config.rs @@ -4,6 +4,7 @@ use crate::errors::ShellError; use crate::parser::hir::SyntaxShape; use crate::parser::registry::{self}; use crate::prelude::*; +use nu_source::Tagged; use std::path::PathBuf; pub struct Config; @@ -11,7 +12,7 @@ pub struct Config; #[derive(Deserialize)] pub struct ConfigArgs { load: Option>, - set: Option<(Tagged, Tagged)>, + set: Option<(Tagged, Value)>, set_into: Option>, get: Option>, clear: Tagged, @@ -90,11 +91,12 @@ pub fn config( .ok_or_else(|| ShellError::labeled_error("Missing key in config", "key", v.tag()))?; match value { - Tagged { - item: Value::Table(list), + Value { + value: UntaggedValue::Table(list), .. } => { for l in list { + let value = l.clone(); yield ReturnSuccess::value(l.clone()); } } @@ -106,10 +108,10 @@ pub fn config( config::write(&result, &configuration)?; - yield ReturnSuccess::value(Value::Row(result.into()).tagged(value.tag())); + yield ReturnSuccess::value(UntaggedValue::Row(result.into()).into_value(&value.tag)); } else if let Some(v) = set_into { - let rows: Vec> = input.values.collect().await; + let rows: Vec = input.values.collect().await; let key = v.to_string(); if rows.len() == 0 { @@ -122,16 +124,16 @@ pub fn config( config::write(&result, &configuration)?; - yield ReturnSuccess::value(Value::Row(result.into()).tagged(name)); + yield ReturnSuccess::value(UntaggedValue::Row(result.into()).into_value(name)); } else { // Take in the pipeline as a table - let value = Value::Table(rows).tagged(name.clone()); + let value = UntaggedValue::Table(rows).into_value(name.clone()); result.insert(key.to_string(), value.clone()); config::write(&result, &configuration)?; - yield ReturnSuccess::value(Value::Row(result.into()).tagged(name)); + yield ReturnSuccess::value(UntaggedValue::Row(result.into()).into_value(name)); } } else if let Tagged { item: true, tag } = clear { @@ -139,14 +141,14 @@ pub fn config( config::write(&result, &configuration)?; - yield ReturnSuccess::value(Value::Row(result.into()).tagged(tag)); + yield ReturnSuccess::value(UntaggedValue::Row(result.into()).into_value(tag)); return; } else if let Tagged { item: true, tag } = path { let path = config::default_path_for(&configuration)?; - yield ReturnSuccess::value(Value::Primitive(Primitive::Path(path)).tagged(tag)); + yield ReturnSuccess::value(UntaggedValue::Primitive(Primitive::Path(path)).into_value(tag)); } else if let Some(v) = remove { let key = v.to_string(); @@ -162,10 +164,10 @@ pub fn config( )); } - yield ReturnSuccess::value(Value::Row(result.into()).tagged(v.tag())); + yield ReturnSuccess::value(UntaggedValue::Row(result.into()).into_value(v.tag())); } else { - yield ReturnSuccess::value(Value::Row(result.into()).tagged(name)); + yield ReturnSuccess::value(UntaggedValue::Row(result.into()).into_value(name)); } }; diff --git a/src/commands/count.rs b/src/commands/count.rs index 5e44283737..1bfa746f6a 100644 --- a/src/commands/count.rs +++ b/src/commands/count.rs @@ -37,9 +37,9 @@ pub fn count( RunnableContext { input, name, .. }: RunnableContext, ) -> Result { let stream = async_stream! { - let rows: Vec> = input.values.collect().await; + let rows: Vec = input.values.collect().await; - yield ReturnSuccess::value(Value::int(rows.len()).tagged(name)) + yield ReturnSuccess::value(UntaggedValue::int(rows.len()).into_value(name)) }; Ok(stream.to_output_stream()) diff --git a/src/commands/cp.rs b/src/commands/cp.rs index 5ca21adb1e..2ef0af269b 100644 --- a/src/commands/cp.rs +++ b/src/commands/cp.rs @@ -3,6 +3,7 @@ use crate::errors::ShellError; use crate::parser::hir::SyntaxShape; use crate::parser::registry::{CommandRegistry, Signature}; use crate::prelude::*; +use nu_source::Tagged; use std::path::PathBuf; pub struct Cpy; @@ -35,7 +36,7 @@ impl PerItemCommand for Cpy { call_info: &CallInfo, _registry: &CommandRegistry, raw_args: &RawCommandArgs, - _input: Tagged, + _input: Value, ) -> Result { call_info.process(&raw_args.shell_manager, cp)?.run() } diff --git a/src/commands/date.rs b/src/commands/date.rs index 24ebc876e4..d4c094819f 100644 --- a/src/commands/date.rs +++ b/src/commands/date.rs @@ -35,26 +35,44 @@ impl WholeStreamCommand for Date { } } -pub fn date_to_value(dt: DateTime, tag: Tag) -> Tagged +pub fn date_to_value(dt: DateTime, tag: Tag) -> Value where T::Offset: Display, { let mut indexmap = IndexMap::new(); - indexmap.insert("year".to_string(), Value::int(dt.year()).tagged(&tag)); - indexmap.insert("month".to_string(), Value::int(dt.month()).tagged(&tag)); - indexmap.insert("day".to_string(), Value::int(dt.day()).tagged(&tag)); - indexmap.insert("hour".to_string(), Value::int(dt.hour()).tagged(&tag)); - indexmap.insert("minute".to_string(), Value::int(dt.minute()).tagged(&tag)); - indexmap.insert("second".to_string(), Value::int(dt.second()).tagged(&tag)); + indexmap.insert( + "year".to_string(), + UntaggedValue::int(dt.year()).into_value(&tag), + ); + indexmap.insert( + "month".to_string(), + UntaggedValue::int(dt.month()).into_value(&tag), + ); + indexmap.insert( + "day".to_string(), + UntaggedValue::int(dt.day()).into_value(&tag), + ); + indexmap.insert( + "hour".to_string(), + UntaggedValue::int(dt.hour()).into_value(&tag), + ); + indexmap.insert( + "minute".to_string(), + UntaggedValue::int(dt.minute()).into_value(&tag), + ); + indexmap.insert( + "second".to_string(), + UntaggedValue::int(dt.second()).into_value(&tag), + ); let tz = dt.offset(); indexmap.insert( "timezone".to_string(), - Value::string(format!("{}", tz)).tagged(&tag), + UntaggedValue::string(format!("{}", tz)).into_value(&tag), ); - Value::Row(Dictionary::from(indexmap)).tagged(&tag) + UntaggedValue::Row(Dictionary::from(indexmap)).into_value(&tag) } pub fn date(args: CommandArgs, registry: &CommandRegistry) -> Result { diff --git a/src/commands/debug.rs b/src/commands/debug.rs index 08bd8259be..63662fece5 100644 --- a/src/commands/debug.rs +++ b/src/commands/debug.rs @@ -34,6 +34,8 @@ fn debug_value( ) -> Result { Ok(input .values - .map(|v| ReturnSuccess::value(Value::string(format!("{:?}", v)).tagged_unknown())) + .map(|v| { + ReturnSuccess::value(UntaggedValue::string(format!("{:?}", v)).into_untagged_value()) + }) .to_output_stream()) } diff --git a/src/commands/default.rs b/src/commands/default.rs index 52d33e463c..9107eb9d0d 100644 --- a/src/commands/default.rs +++ b/src/commands/default.rs @@ -2,11 +2,12 @@ use crate::commands::WholeStreamCommand; use crate::errors::ShellError; use crate::parser::CommandRegistry; use crate::prelude::*; +use nu_source::Tagged; #[derive(Deserialize)] struct DefaultArgs { column: Tagged, - value: Tagged, + value: Value, } pub struct Default; @@ -49,15 +50,15 @@ fn default( let mut result = VecDeque::new(); let should_add = match item { - Tagged { - item: Value::Row(ref r), + Value { + value: UntaggedValue::Row(ref r), .. } => r.get_data(&column.item).borrow().is_none(), _ => false, }; if should_add { - match item.insert_data_at_path(&column.item, value.item.clone()) { + match item.insert_data_at_path(&column.item, value.clone()) { Some(new_value) => result.push_back(ReturnSuccess::value(new_value)), None => result.push_back(ReturnSuccess::value(item)), } diff --git a/src/commands/echo.rs b/src/commands/echo.rs index 6e59d51f44..45b6daf479 100644 --- a/src/commands/echo.rs +++ b/src/commands/echo.rs @@ -24,7 +24,7 @@ impl PerItemCommand for Echo { call_info: &CallInfo, registry: &CommandRegistry, raw_args: &RawCommandArgs, - _input: Tagged, + _input: Value, ) -> Result { run(call_info, registry, raw_args) } @@ -42,16 +42,16 @@ fn run( match i.as_string() { Ok(s) => { output.push(Ok(ReturnSuccess::Value( - Value::string(s).tagged(i.tag.clone()), + UntaggedValue::string(s).into_value(i.tag.clone()), ))); } _ => match i { - Tagged { - item: Value::Table(table), + Value { + value: UntaggedValue::Table(table), .. } => { - for item in table { - output.push(Ok(ReturnSuccess::Value(item.clone()))); + for value in table { + output.push(Ok(ReturnSuccess::Value(value.clone()))); } } _ => { diff --git a/src/commands/enter.rs b/src/commands/enter.rs index 2153a0a084..66d5c0c86e 100644 --- a/src/commands/enter.rs +++ b/src/commands/enter.rs @@ -30,13 +30,13 @@ impl PerItemCommand for Enter { call_info: &CallInfo, registry: ®istry::CommandRegistry, raw_args: &RawCommandArgs, - _input: Tagged, + _input: Value, ) -> Result { let registry = registry.clone(); let raw_args = raw_args.clone(); match call_info.args.expect_nth(0)? { - Tagged { - item: Value::Primitive(Primitive::Path(location)), + Value { + value: UntaggedValue::Primitive(Primitive::Path(location)), tag, .. } => { @@ -51,12 +51,12 @@ impl PerItemCommand for Enter { if registry.has(command) { Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterHelpShell( - Value::string(command).tagged(Tag::unknown()), + UntaggedValue::string(command).into_value(Tag::unknown()), )))] .into()) } else { Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterHelpShell( - Value::nothing().tagged(Tag::unknown()), + UntaggedValue::nothing().into_value(Tag::unknown()), )))] .into()) } @@ -80,8 +80,8 @@ impl PerItemCommand for Enter { ).await?; match contents { - Value::Primitive(Primitive::String(_)) => { - let tagged_contents = contents.tagged(&contents_tag); + UntaggedValue::Primitive(Primitive::String(_)) => { + let tagged_contents = contents.into_value(&contents_tag); if let Some(extension) = file_extension { let command_name = format!("from-{}", extension); @@ -97,6 +97,7 @@ impl PerItemCommand for Enter { head: raw_args.call_info.args.head, positional: None, named: None, + span: Span::unknown() }, source: raw_args.call_info.source, name_tag: raw_args.call_info.name_tag, @@ -110,13 +111,13 @@ impl PerItemCommand for Enter { result.drain_vec().await; for res in result_vec { match res { - Ok(ReturnSuccess::Value(Tagged { - item, + Ok(ReturnSuccess::Value(Value { + value, .. })) => { yield Ok(ReturnSuccess::Action(CommandAction::EnterValueShell( - Tagged { - item, + Value { + value, tag: contents_tag.clone(), }))); } @@ -131,7 +132,7 @@ impl PerItemCommand for Enter { } } _ => { - let tagged_contents = contents.tagged(contents_tag); + let tagged_contents = contents.into_value(contents_tag); yield Ok(ReturnSuccess::Action(CommandAction::EnterValueShell(tagged_contents))); } diff --git a/src/commands/env.rs b/src/commands/env.rs index 0572b499c1..add9df82ff 100644 --- a/src/commands/env.rs +++ b/src/commands/env.rs @@ -33,34 +33,49 @@ impl WholeStreamCommand for Env { } } -pub fn get_environment(tag: Tag) -> Result, Box> { +pub fn get_environment(tag: Tag) -> Result> { let mut indexmap = IndexMap::new(); let path = std::env::current_dir()?; - indexmap.insert("cwd".to_string(), Value::path(path).tagged(&tag)); + indexmap.insert( + "cwd".to_string(), + UntaggedValue::path(path).into_value(&tag), + ); if let Some(home) = dirs::home_dir() { - indexmap.insert("home".to_string(), Value::path(home).tagged(&tag)); + indexmap.insert( + "home".to_string(), + UntaggedValue::path(home).into_value(&tag), + ); } let config = config::default_path()?; - indexmap.insert("config".to_string(), Value::path(config).tagged(&tag)); + indexmap.insert( + "config".to_string(), + UntaggedValue::path(config).into_value(&tag), + ); let history = History::path(); - indexmap.insert("history".to_string(), Value::path(history).tagged(&tag)); + indexmap.insert( + "history".to_string(), + UntaggedValue::path(history).into_value(&tag), + ); let temp = std::env::temp_dir(); - indexmap.insert("temp".to_string(), Value::path(temp).tagged(&tag)); + indexmap.insert( + "temp".to_string(), + UntaggedValue::path(temp).into_value(&tag), + ); let mut dict = TaggedDictBuilder::new(&tag); for v in std::env::vars() { - dict.insert(v.0, Value::string(v.1)); + dict.insert_untagged(v.0, UntaggedValue::string(v.1)); } if !dict.is_empty() { - indexmap.insert("vars".to_string(), dict.into_tagged_value()); + indexmap.insert("vars".to_string(), dict.into_value()); } - Ok(Value::Row(Dictionary::from(indexmap)).tagged(&tag)) + Ok(UntaggedValue::Row(Dictionary::from(indexmap)).into_value(&tag)) } pub fn env(args: CommandArgs, registry: &CommandRegistry) -> Result { diff --git a/src/commands/evaluate_by.rs b/src/commands/evaluate_by.rs index 05311db70e..d0d568f9aa 100644 --- a/src/commands/evaluate_by.rs +++ b/src/commands/evaluate_by.rs @@ -1,6 +1,8 @@ use crate::commands::WholeStreamCommand; use crate::parser::hir::SyntaxShape; use crate::prelude::*; +use nu_source::{SpannedItem, Tagged}; + pub struct EvaluateBy; #[derive(Deserialize)] @@ -39,7 +41,7 @@ pub fn evaluate_by( RunnableContext { input, name, .. }: RunnableContext, ) -> Result { let stream = async_stream! { - let values: Vec> = input.values.collect().await; + let values: Vec = input.values.collect().await; if values.is_empty() { @@ -66,30 +68,18 @@ pub fn evaluate_by( Ok(stream.to_output_stream()) } -fn fetch( - key: Option, -) -> Box, Tag) -> Option> + 'static> { - Box::new(move |value: Tagged, tag| match key { - Some(ref key_given) => { - if let Some(Tagged { - item, - tag: Tag { span, .. }, - }) = value.get_data_by_key(key_given[..].spanned(tag.span)) - { - Some(item.clone().tagged(tag)) - } else { - None - } - } - None => Some(Value::int(1).tagged(tag)), +fn fetch(key: Option) -> Box Option + 'static> { + Box::new(move |value: Value, tag| match &key { + Some(key_given) => value.get_data_by_key(key_given[..].spanned(tag.span)), + None => Some(UntaggedValue::int(1).into_value(tag)), }) } pub fn evaluate( - values: &Tagged, + values: &Value, evaluator: Option, tag: impl Into, -) -> Result, ShellError> { +) -> Result { let tag = tag.into(); let evaluate_with = match evaluator { @@ -97,44 +87,44 @@ pub fn evaluate( None => fetch(None), }; - let results: Tagged = match values { - Tagged { - item: Value::Table(datasets), + let results: Value = match values { + Value { + value: UntaggedValue::Table(datasets), .. } => { let datasets: Vec<_> = datasets .into_iter() .map(|subsets| match subsets { - Tagged { - item: Value::Table(subsets), + Value { + value: UntaggedValue::Table(subsets), .. } => { let subsets: Vec<_> = subsets .clone() .into_iter() .map(|data| match data { - Tagged { - item: Value::Table(data), + Value { + value: UntaggedValue::Table(data), .. } => { let data: Vec<_> = data .into_iter() .map(|x| evaluate_with(x.clone(), tag.clone()).unwrap()) .collect(); - Value::Table(data).tagged(&tag) + UntaggedValue::Table(data).into_value(&tag) } - _ => Value::Table(vec![]).tagged(&tag), + _ => UntaggedValue::Table(vec![]).into_value(&tag), }) .collect(); - Value::Table(subsets).tagged(&tag) + UntaggedValue::Table(subsets).into_value(&tag) } - _ => Value::Table(vec![]).tagged(&tag), + _ => UntaggedValue::Table(vec![]).into_value(&tag), }) .collect(); - Value::Table(datasets.clone()).tagged(&tag) + UntaggedValue::Table(datasets.clone()).into_value(&tag) } - _ => Value::Table(vec![]).tagged(&tag), + _ => UntaggedValue::Table(vec![]).into_value(&tag), }; Ok(results) @@ -146,28 +136,28 @@ mod tests { use crate::commands::evaluate_by::{evaluate, fetch}; use crate::commands::group_by::group; use crate::commands::t_sort_by::t_sort; - use crate::data::meta::*; use crate::prelude::*; use crate::Value; use indexmap::IndexMap; + use nu_source::TaggedItem; - fn int(s: impl Into) -> Tagged { - Value::int(s).tagged_unknown() + fn int(s: impl Into) -> Value { + UntaggedValue::int(s).into_untagged_value() } - fn string(input: impl Into) -> Tagged { - Value::string(input.into()).tagged_unknown() + fn string(input: impl Into) -> Value { + UntaggedValue::string(input.into()).into_untagged_value() } - fn row(entries: IndexMap>) -> Tagged { - Value::row(entries).tagged_unknown() + fn row(entries: IndexMap) -> Value { + UntaggedValue::row(entries).into_untagged_value() } - fn table(list: &Vec>) -> Tagged { - Value::table(list).tagged_unknown() + fn table(list: &Vec) -> Value { + UntaggedValue::table(list).into_untagged_value() } - fn nu_releases_sorted_by_date() -> Tagged { + fn nu_releases_sorted_by_date() -> Value { let key = String::from("date"); t_sort( @@ -179,12 +169,12 @@ mod tests { .unwrap() } - fn nu_releases_grouped_by_date() -> Tagged { + fn nu_releases_grouped_by_date() -> Value { let key = String::from("date").tagged_unknown(); group(&key, nu_releases_commiters(), Tag::unknown()).unwrap() } - fn nu_releases_commiters() -> Vec> { + fn nu_releases_commiters() -> Vec { vec![ row( indexmap! {"name".into() => string("AR"), "country".into() => string("EC"), "date".into() => string("August 23-2019")}, @@ -232,7 +222,7 @@ mod tests { assert_eq!( evaluator(subject, Tag::unknown()), - Some(Value::int(1).tagged_unknown()) + Some(UntaggedValue::int(1).into_untagged_value()) ); } diff --git a/src/commands/fetch.rs b/src/commands/fetch.rs index 8fe3ca247a..0432f917e1 100644 --- a/src/commands/fetch.rs +++ b/src/commands/fetch.rs @@ -1,15 +1,15 @@ use crate::commands::UnevaluatedCallInfo; -use crate::context::AnchorLocation; -use crate::data::meta::Span; -use crate::data::Value; +use crate::data::base::Value; use crate::errors::ShellError; use crate::parser::hir::SyntaxShape; use crate::parser::registry::Signature; use crate::prelude::*; use mime::Mime; +use nu_source::{AnchorLocation, Span}; use std::path::PathBuf; use std::str::FromStr; use surf::mime; + pub struct Fetch; impl PerItemCommand for Fetch { @@ -36,7 +36,7 @@ impl PerItemCommand for Fetch { call_info: &CallInfo, registry: &CommandRegistry, raw_args: &RawCommandArgs, - _input: Tagged, + _input: Value, ) -> Result { run(call_info, registry, raw_args) } @@ -81,7 +81,7 @@ fn run( file_extension.or(path_str.split('.').last().map(String::from)) }; - let tagged_contents = contents.tagged(&contents_tag); + let tagged_contents = contents.retag(&contents_tag); if let Some(extension) = file_extension { let command_name = format!("from-{}", extension); @@ -94,7 +94,8 @@ fn run( args: crate::parser::hir::Call { head: raw_args.call_info.args.head, positional: None, - named: None + named: None, + span: Span::unknown() }, source: raw_args.call_info.source, name_tag: raw_args.call_info.name_tag, @@ -104,13 +105,13 @@ fn run( let result_vec: Vec> = result.drain_vec().await; for res in result_vec { match res { - Ok(ReturnSuccess::Value(Tagged { item: Value::Table(list), ..})) => { + Ok(ReturnSuccess::Value(Value { value: UntaggedValue::Table(list), ..})) => { for l in list { yield Ok(ReturnSuccess::Value(l)); } } - Ok(ReturnSuccess::Value(Tagged { item, .. })) => { - yield Ok(ReturnSuccess::Value(Tagged { item, tag: contents_tag.clone() })); + Ok(ReturnSuccess::Value(Value { value, .. })) => { + yield Ok(ReturnSuccess::Value(value.into_value(contents_tag.clone()))); } x => yield x, } @@ -126,7 +127,10 @@ fn run( Ok(stream.to_output_stream()) } -pub async fn fetch(location: &str, span: Span) -> Result<(Option, Value, Tag), ShellError> { +pub async fn fetch( + location: &str, + span: Span, +) -> Result<(Option, UntaggedValue, Tag), ShellError> { if let Err(_) = url::Url::parse(location) { return Err(ShellError::labeled_error( "Incomplete or incorrect url", @@ -143,7 +147,7 @@ pub async fn fetch(location: &str, span: Span) -> Result<(Option, Value, match (content_type.type_(), content_type.subtype()) { (mime::APPLICATION, mime::XML) => Ok(( Some("xml".to_string()), - Value::string(r.body_string().await.map_err(|_| { + UntaggedValue::string(r.body_string().await.map_err(|_| { ShellError::labeled_error( "Could not load text from remote url", "could not load", @@ -157,7 +161,7 @@ pub async fn fetch(location: &str, span: Span) -> Result<(Option, Value, )), (mime::APPLICATION, mime::JSON) => Ok(( Some("json".to_string()), - Value::string(r.body_string().await.map_err(|_| { + UntaggedValue::string(r.body_string().await.map_err(|_| { ShellError::labeled_error( "Could not load text from remote url", "could not load", @@ -179,7 +183,7 @@ pub async fn fetch(location: &str, span: Span) -> Result<(Option, Value, })?; Ok(( None, - Value::binary(buf), + UntaggedValue::binary(buf), Tag { span, anchor: Some(AnchorLocation::Url(location.to_string())), @@ -188,7 +192,7 @@ pub async fn fetch(location: &str, span: Span) -> Result<(Option, Value, } (mime::IMAGE, mime::SVG) => Ok(( Some("svg".to_string()), - Value::string(r.body_string().await.map_err(|_| { + UntaggedValue::string(r.body_string().await.map_err(|_| { ShellError::labeled_error( "Could not load svg from remote url", "could not load", @@ -210,7 +214,7 @@ pub async fn fetch(location: &str, span: Span) -> Result<(Option, Value, })?; Ok(( Some(image_ty.to_string()), - Value::binary(buf), + UntaggedValue::binary(buf), Tag { span, anchor: Some(AnchorLocation::Url(location.to_string())), @@ -219,7 +223,7 @@ pub async fn fetch(location: &str, span: Span) -> Result<(Option, Value, } (mime::TEXT, mime::HTML) => Ok(( Some("html".to_string()), - Value::string(r.body_string().await.map_err(|_| { + UntaggedValue::string(r.body_string().await.map_err(|_| { ShellError::labeled_error( "Could not load text from remote url", "could not load", @@ -245,7 +249,7 @@ pub async fn fetch(location: &str, span: Span) -> Result<(Option, Value, Ok(( path_extension, - Value::string(r.body_string().await.map_err(|_| { + UntaggedValue::string(r.body_string().await.map_err(|_| { ShellError::labeled_error( "Could not load text from remote url", "could not load", @@ -260,7 +264,10 @@ pub async fn fetch(location: &str, span: Span) -> Result<(Option, Value, } (ty, sub_ty) => Ok(( None, - Value::string(format!("Not yet supported MIME type: {} {}", ty, sub_ty)), + UntaggedValue::string(format!( + "Not yet supported MIME type: {} {}", + ty, sub_ty + )), Tag { span, anchor: Some(AnchorLocation::Url(location.to_string())), @@ -270,7 +277,7 @@ pub async fn fetch(location: &str, span: Span) -> Result<(Option, Value, } None => Ok(( None, - Value::string(format!("No content type found")), + UntaggedValue::string(format!("No content type found")), Tag { span, anchor: Some(AnchorLocation::Url(location.to_string())), diff --git a/src/commands/first.rs b/src/commands/first.rs index a9a287978a..1113691bf1 100644 --- a/src/commands/first.rs +++ b/src/commands/first.rs @@ -2,6 +2,7 @@ use crate::commands::WholeStreamCommand; use crate::errors::ShellError; use crate::parser::CommandRegistry; use crate::prelude::*; +use nu_source::Tagged; pub struct First; diff --git a/src/commands/from_bson.rs b/src/commands/from_bson.rs index 469e15f35e..e6a41907ad 100644 --- a/src/commands/from_bson.rs +++ b/src/commands/from_bson.rs @@ -1,8 +1,9 @@ use crate::commands::WholeStreamCommand; -use crate::data::{Primitive, TaggedDictBuilder, Value}; +use crate::data::TaggedDictBuilder; use crate::errors::ExpectedRange; use crate::prelude::*; use bson::{decode_document, spec::BinarySubtype, Bson}; +use nu_source::SpannedItem; use std::str::FromStr; pub struct FromBSON; @@ -29,7 +30,7 @@ impl WholeStreamCommand for FromBSON { } } -fn bson_array(input: &Vec, tag: Tag) -> Result>, ShellError> { +fn bson_array(input: &Vec, tag: Tag) -> Result, ShellError> { let mut out = vec![]; for value in input { @@ -39,109 +40,114 @@ fn bson_array(input: &Vec, tag: Tag) -> Result>, ShellEr Ok(out) } -fn convert_bson_value_to_nu_value( - v: &Bson, - tag: impl Into, -) -> Result, ShellError> { +fn convert_bson_value_to_nu_value(v: &Bson, tag: impl Into) -> Result { let tag = tag.into(); + let span = tag.span; Ok(match v { - Bson::FloatingPoint(n) => Value::Primitive(Primitive::from(*n)).tagged(&tag), - Bson::String(s) => Value::Primitive(Primitive::String(String::from(s))).tagged(&tag), - Bson::Array(a) => Value::Table(bson_array(a, tag.clone())?).tagged(&tag), + Bson::FloatingPoint(n) => UntaggedValue::Primitive(Primitive::from(*n)).into_value(&tag), + Bson::String(s) => { + UntaggedValue::Primitive(Primitive::String(String::from(s))).into_value(&tag) + } + Bson::Array(a) => UntaggedValue::Table(bson_array(a, tag.clone())?).into_value(&tag), Bson::Document(doc) => { let mut collected = TaggedDictBuilder::new(tag.clone()); for (k, v) in doc.iter() { - collected.insert_tagged(k.clone(), convert_bson_value_to_nu_value(v, &tag)?); + collected.insert_value(k.clone(), convert_bson_value_to_nu_value(v, &tag)?); } - collected.into_tagged_value() + collected.into_value() } - Bson::Boolean(b) => Value::Primitive(Primitive::Boolean(*b)).tagged(&tag), - Bson::Null => Value::Primitive(Primitive::Nothing).tagged(&tag), + Bson::Boolean(b) => UntaggedValue::Primitive(Primitive::Boolean(*b)).into_value(&tag), + Bson::Null => UntaggedValue::Primitive(Primitive::Nothing).into_value(&tag), Bson::RegExp(r, opts) => { let mut collected = TaggedDictBuilder::new(tag.clone()); - collected.insert_tagged( + collected.insert_value( "$regex".to_string(), - Value::Primitive(Primitive::String(String::from(r))).tagged(&tag), + UntaggedValue::Primitive(Primitive::String(String::from(r))).into_value(&tag), ); - collected.insert_tagged( + collected.insert_value( "$options".to_string(), - Value::Primitive(Primitive::String(String::from(opts))).tagged(&tag), + UntaggedValue::Primitive(Primitive::String(String::from(opts))).into_value(&tag), ); - collected.into_tagged_value() + collected.into_value() } - Bson::I32(n) => Value::number(n).tagged(&tag), - Bson::I64(n) => Value::number(n).tagged(&tag), + Bson::I32(n) => UntaggedValue::number(n).into_value(&tag), + Bson::I64(n) => UntaggedValue::number(n).into_value(&tag), Bson::Decimal128(n) => { // TODO: this really isn't great, and we should update this to do a higher // fidelity translation let decimal = BigDecimal::from_str(&format!("{}", n)).map_err(|_| { ShellError::range_error( ExpectedRange::BigDecimal, - &n.tagged(&tag), + &n.spanned(span), format!("converting BSON Decimal128 to BigDecimal"), ) })?; - Value::Primitive(Primitive::Decimal(decimal)).tagged(&tag) + UntaggedValue::Primitive(Primitive::Decimal(decimal)).into_value(&tag) } Bson::JavaScriptCode(js) => { let mut collected = TaggedDictBuilder::new(tag.clone()); - collected.insert_tagged( + collected.insert_value( "$javascript".to_string(), - Value::Primitive(Primitive::String(String::from(js))).tagged(&tag), + UntaggedValue::Primitive(Primitive::String(String::from(js))).into_value(&tag), ); - collected.into_tagged_value() + collected.into_value() } Bson::JavaScriptCodeWithScope(js, doc) => { let mut collected = TaggedDictBuilder::new(tag.clone()); - collected.insert_tagged( + collected.insert_value( "$javascript".to_string(), - Value::Primitive(Primitive::String(String::from(js))).tagged(&tag), + UntaggedValue::Primitive(Primitive::String(String::from(js))).into_value(&tag), ); - collected.insert_tagged( + collected.insert_value( "$scope".to_string(), convert_bson_value_to_nu_value(&Bson::Document(doc.to_owned()), tag.clone())?, ); - collected.into_tagged_value() + collected.into_value() } Bson::TimeStamp(ts) => { let mut collected = TaggedDictBuilder::new(tag.clone()); - collected.insert_tagged("$timestamp".to_string(), Value::number(ts).tagged(&tag)); - collected.into_tagged_value() + collected.insert_value( + "$timestamp".to_string(), + UntaggedValue::number(ts).into_value(&tag), + ); + collected.into_value() } Bson::Binary(bst, bytes) => { let mut collected = TaggedDictBuilder::new(tag.clone()); - collected.insert_tagged( + collected.insert_value( "$binary_subtype".to_string(), match bst { - BinarySubtype::UserDefined(u) => Value::number(u), - _ => Value::Primitive(Primitive::String(binary_subtype_to_string(*bst))), + BinarySubtype::UserDefined(u) => UntaggedValue::number(u), + _ => { + UntaggedValue::Primitive(Primitive::String(binary_subtype_to_string(*bst))) + } } - .tagged(&tag), + .into_value(&tag), ); - collected.insert_tagged( + collected.insert_value( "$binary".to_string(), - Value::Primitive(Primitive::Binary(bytes.to_owned())).tagged(&tag), + UntaggedValue::Primitive(Primitive::Binary(bytes.to_owned())).into_value(&tag), ); - collected.into_tagged_value() + collected.into_value() } Bson::ObjectId(obj_id) => { let mut collected = TaggedDictBuilder::new(tag.clone()); - collected.insert_tagged( + collected.insert_value( "$object_id".to_string(), - Value::Primitive(Primitive::String(obj_id.to_hex())).tagged(&tag), + UntaggedValue::Primitive(Primitive::String(obj_id.to_hex())).into_value(&tag), ); - collected.into_tagged_value() + collected.into_value() } - Bson::UtcDatetime(dt) => Value::Primitive(Primitive::Date(*dt)).tagged(&tag), + Bson::UtcDatetime(dt) => UntaggedValue::Primitive(Primitive::Date(*dt)).into_value(&tag), Bson::Symbol(s) => { let mut collected = TaggedDictBuilder::new(tag.clone()); - collected.insert_tagged( + collected.insert_value( "$symbol".to_string(), - Value::Primitive(Primitive::String(String::from(s))).tagged(&tag), + UntaggedValue::Primitive(Primitive::String(String::from(s))).into_value(&tag), ); - collected.into_tagged_value() + collected.into_value() } }) } @@ -183,10 +189,7 @@ impl std::io::Read for BytesReader { } } -pub fn from_bson_bytes_to_value( - bytes: Vec, - tag: impl Into, -) -> Result, ShellError> { +pub fn from_bson_bytes_to_value(bytes: Vec, tag: impl Into) -> Result { let mut docs = Vec::new(); let mut b_reader = BytesReader::new(bytes); while let Ok(v) = decode_document(&mut b_reader) { @@ -202,12 +205,12 @@ fn from_bson(args: CommandArgs, registry: &CommandRegistry) -> Result> = input.values.collect().await; + let values: Vec = input.values.collect().await; for value in values { - let value_tag = value.tag(); - match value.item { - Value::Primitive(Primitive::Binary(vb)) => + let value_tag = &value.tag; + match value.value { + UntaggedValue::Primitive(Primitive::Binary(vb)) => match from_bson_bytes_to_value(vb, tag.clone()) { Ok(x) => yield ReturnSuccess::value(x), Err(_) => { diff --git a/src/commands/from_csv.rs b/src/commands/from_csv.rs index df09c9dbe3..663b2fd255 100644 --- a/src/commands/from_csv.rs +++ b/src/commands/from_csv.rs @@ -8,7 +8,7 @@ pub struct FromCSV; #[derive(Deserialize)] pub struct FromCSVArgs { headerless: bool, - separator: Option>, + separator: Option, } impl WholeStreamCommand for FromCSV { @@ -47,8 +47,8 @@ fn from_csv( runnable_context: RunnableContext, ) -> Result { let sep = match separator { - Some(Tagged { - item: Value::Primitive(Primitive::String(s)), + Some(Value { + value: UntaggedValue::Primitive(Primitive::String(s)), tag, .. }) => { diff --git a/src/commands/from_delimited_data.rs b/src/commands/from_delimited_data.rs index e499323774..805f187eb3 100644 --- a/src/commands/from_delimited_data.rs +++ b/src/commands/from_delimited_data.rs @@ -7,7 +7,7 @@ fn from_delimited_string_to_value( headerless: bool, separator: char, tag: impl Into, -) -> Result, csv::Error> { +) -> Result { let mut reader = ReaderBuilder::new() .has_headers(!headerless) .delimiter(separator as u8) @@ -26,15 +26,15 @@ fn from_delimited_string_to_value( for row in reader.records() { let mut tagged_row = TaggedDictBuilder::new(&tag); for (value, header) in row?.iter().zip(headers.iter()) { - tagged_row.insert_tagged( + tagged_row.insert_value( header, - Value::Primitive(Primitive::String(String::from(value))).tagged(&tag), + UntaggedValue::Primitive(Primitive::String(String::from(value))).into_value(&tag), ) } - rows.push(tagged_row.into_tagged_value()); + rows.push(tagged_row.into_value()); } - Ok(Value::Table(rows).tagged(&tag)) + Ok(UntaggedValue::Table(rows).into_value(&tag)) } pub fn from_delimited_data( @@ -46,16 +46,16 @@ pub fn from_delimited_data( let name_tag = name; let stream = async_stream! { - let values: Vec> = input.values.collect().await; + let values: Vec = input.values.collect().await; let mut concat_string = String::new(); let mut latest_tag: Option = None; for value in values { - let value_tag = value.tag(); + let value_tag = &value.tag; latest_tag = Some(value_tag.clone()); - match value.item { - Value::Primitive(Primitive::String(s)) => { + match &value.value { + UntaggedValue::Primitive(Primitive::String(s)) => { concat_string.push_str(&s); concat_string.push_str("\n"); } @@ -72,7 +72,7 @@ pub fn from_delimited_data( match from_delimited_string_to_value(concat_string, headerless, sep, name_tag.clone()) { Ok(x) => match x { - Tagged { item: Value::Table(list), .. } => { + Value { value: UntaggedValue::Table(list), .. } => { for l in list { yield ReturnSuccess::value(l); } diff --git a/src/commands/from_ini.rs b/src/commands/from_ini.rs index e55bbd45c4..bd2282ea4c 100644 --- a/src/commands/from_ini.rs +++ b/src/commands/from_ini.rs @@ -27,40 +27,37 @@ impl WholeStreamCommand for FromINI { } } -fn convert_ini_second_to_nu_value( - v: &HashMap, - tag: impl Into, -) -> Tagged { +fn convert_ini_second_to_nu_value(v: &HashMap, tag: impl Into) -> Value { let mut second = TaggedDictBuilder::new(tag); for (key, value) in v.into_iter() { - second.insert(key.clone(), Primitive::String(value.clone())); + second.insert_untagged(key.clone(), Primitive::String(value.clone())); } - second.into_tagged_value() + second.into_value() } fn convert_ini_top_to_nu_value( v: &HashMap>, tag: impl Into, -) -> Tagged { +) -> Value { let tag = tag.into(); let mut top_level = TaggedDictBuilder::new(tag.clone()); for (key, value) in v.iter() { - top_level.insert_tagged( + top_level.insert_value( key.clone(), convert_ini_second_to_nu_value(value, tag.clone()), ); } - top_level.into_tagged_value() + top_level.into_value() } pub fn from_ini_string_to_value( s: String, tag: impl Into, -) -> Result, serde_ini::de::Error> { +) -> Result { let v: HashMap> = serde_ini::from_str(&s)?; Ok(convert_ini_top_to_nu_value(&v, tag)) } @@ -68,28 +65,29 @@ pub fn from_ini_string_to_value( fn from_ini(args: CommandArgs, registry: &CommandRegistry) -> Result { let args = args.evaluate_once(registry)?; let tag = args.name_tag(); + let span = tag.span; let input = args.input; let stream = async_stream! { - let values: Vec> = input.values.collect().await; + let values: Vec = input.values.collect().await; let mut concat_string = String::new(); let mut latest_tag: Option = None; for value in values { - let value_tag = value.tag(); - latest_tag = Some(value_tag.clone()); - match value.item { - Value::Primitive(Primitive::String(s)) => { + 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( "Expected a string from pipeline", "requires string input", - &tag, + span, "value originates from here", - &value_tag, + value_span, )), } @@ -97,7 +95,7 @@ fn from_ini(args: CommandArgs, registry: &CommandRegistry) -> Result match x { - Tagged { item: Value::Table(list), .. } => { + Value { value: UntaggedValue::Table(list), .. } => { for l in list { yield ReturnSuccess::value(l); } diff --git a/src/commands/from_json.rs b/src/commands/from_json.rs index 01883818c6..0eff08daa6 100644 --- a/src/commands/from_json.rs +++ b/src/commands/from_json.rs @@ -31,39 +31,36 @@ impl WholeStreamCommand for FromJSON { } } -fn convert_json_value_to_nu_value(v: &serde_hjson::Value, tag: impl Into) -> Tagged { +fn convert_json_value_to_nu_value(v: &serde_hjson::Value, tag: impl Into) -> Value { let tag = tag.into(); match v { - serde_hjson::Value::Null => Value::Primitive(Primitive::Nothing).tagged(&tag), - serde_hjson::Value::Bool(b) => Value::boolean(*b).tagged(&tag), - serde_hjson::Value::F64(n) => Value::number(n).tagged(&tag), - serde_hjson::Value::U64(n) => Value::number(n).tagged(&tag), - serde_hjson::Value::I64(n) => Value::number(n).tagged(&tag), + serde_hjson::Value::Null => UntaggedValue::Primitive(Primitive::Nothing).into_value(&tag), + serde_hjson::Value::Bool(b) => UntaggedValue::boolean(*b).into_value(&tag), + serde_hjson::Value::F64(n) => UntaggedValue::number(n).into_value(&tag), + serde_hjson::Value::U64(n) => UntaggedValue::number(n).into_value(&tag), + serde_hjson::Value::I64(n) => UntaggedValue::number(n).into_value(&tag), serde_hjson::Value::String(s) => { - Value::Primitive(Primitive::String(String::from(s))).tagged(&tag) + UntaggedValue::Primitive(Primitive::String(String::from(s))).into_value(&tag) } - serde_hjson::Value::Array(a) => Value::Table( + serde_hjson::Value::Array(a) => UntaggedValue::Table( a.iter() .map(|x| convert_json_value_to_nu_value(x, &tag)) .collect(), ) - .tagged(tag), + .into_value(tag), serde_hjson::Value::Object(o) => { let mut collected = TaggedDictBuilder::new(&tag); for (k, v) in o.iter() { - collected.insert_tagged(k.clone(), convert_json_value_to_nu_value(v, &tag)); + collected.insert_value(k.clone(), convert_json_value_to_nu_value(v, &tag)); } - collected.into_tagged_value() + collected.into_value() } } } -pub fn from_json_string_to_value( - s: String, - tag: impl Into, -) -> serde_hjson::Result> { +pub fn from_json_string_to_value(s: String, tag: impl Into) -> serde_hjson::Result { let v: serde_hjson::Value = serde_hjson::from_str(&s)?; Ok(convert_json_value_to_nu_value(&v, tag)) } @@ -72,28 +69,29 @@ fn from_json( FromJSONArgs { objects }: FromJSONArgs, RunnableContext { input, name, .. }: RunnableContext, ) -> Result { + let name_span = name.span; let name_tag = name; let stream = async_stream! { - let values: Vec> = input.values.collect().await; + let values: Vec = input.values.collect().await; let mut concat_string = String::new(); let mut latest_tag: Option = None; for value in values { - let value_tag = value.tag(); - latest_tag = Some(value_tag.clone()); - match value.item { - Value::Primitive(Primitive::String(s)) => { + 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( "Expected a string from pipeline", "requires string input", - &name_tag, + name_span, "value originates from here", - &value_tag, + value_span, )), } @@ -125,7 +123,7 @@ fn from_json( match from_json_string_to_value(concat_string, name_tag.clone()) { Ok(x) => match x { - Tagged { item: Value::Table(list), .. } => { + Value { value: UntaggedValue::Table(list), .. } => { for l in list { yield ReturnSuccess::value(l); } diff --git a/src/commands/from_sqlite.rs b/src/commands/from_sqlite.rs index 55dff62a47..15bfbb6cab 100644 --- a/src/commands/from_sqlite.rs +++ b/src/commands/from_sqlite.rs @@ -57,7 +57,7 @@ impl WholeStreamCommand for FromDB { pub fn convert_sqlite_file_to_nu_value( path: &Path, tag: impl Into + Clone, -) -> Result, rusqlite::Error> { +) -> Result { let conn = Connection::open(path)?; let mut meta_out = Vec::new(); @@ -72,48 +72,54 @@ pub fn convert_sqlite_file_to_nu_value( while let Some(table_row) = table_rows.next()? { out.push(convert_sqlite_row_to_nu_value(table_row, tag.clone())?) } - meta_dict.insert_tagged( + meta_dict.insert_value( "table_name".to_string(), - Value::Primitive(Primitive::String(table_name)).tagged(tag.clone()), + UntaggedValue::Primitive(Primitive::String(table_name)).into_value(tag.clone()), ); - meta_dict.insert_tagged("table_values", Value::Table(out).tagged(tag.clone())); - meta_out.push(meta_dict.into_tagged_value()); + meta_dict.insert_value( + "table_values", + UntaggedValue::Table(out).into_value(tag.clone()), + ); + meta_out.push(meta_dict.into_value()); } let tag = tag.into(); - Ok(Value::Table(meta_out).tagged(tag)) + Ok(UntaggedValue::Table(meta_out).into_value(tag)) } fn convert_sqlite_row_to_nu_value( row: &Row, tag: impl Into + Clone, -) -> Result, rusqlite::Error> { +) -> Result { let mut collected = TaggedDictBuilder::new(tag.clone()); for (i, c) in row.columns().iter().enumerate() { - collected.insert_tagged( + collected.insert_value( c.name().to_string(), convert_sqlite_value_to_nu_value(row.get_raw(i), tag.clone()), ); } - return Ok(collected.into_tagged_value()); + return Ok(collected.into_value()); } -fn convert_sqlite_value_to_nu_value(value: ValueRef, tag: impl Into + Clone) -> Tagged { +fn convert_sqlite_value_to_nu_value(value: ValueRef, tag: impl Into + Clone) -> Value { match value { - ValueRef::Null => Value::Primitive(Primitive::String(String::from(""))).tagged(tag), - ValueRef::Integer(i) => Value::number(i).tagged(tag), - ValueRef::Real(f) => Value::number(f).tagged(tag), + ValueRef::Null => { + UntaggedValue::Primitive(Primitive::String(String::from(""))).into_value(tag) + } + ValueRef::Integer(i) => UntaggedValue::number(i).into_value(tag), + ValueRef::Real(f) => UntaggedValue::number(f).into_value(tag), t @ ValueRef::Text(_) => { // this unwrap is safe because we know the ValueRef is Text. - Value::Primitive(Primitive::String(t.as_str().unwrap().to_string())).tagged(tag) + UntaggedValue::Primitive(Primitive::String(t.as_str().unwrap().to_string())) + .into_value(tag) } - ValueRef::Blob(u) => Value::binary(u.to_owned()).tagged(tag), + ValueRef::Blob(u) => UntaggedValue::binary(u.to_owned()).into_value(tag), } } pub fn from_sqlite_bytes_to_value( mut bytes: Vec, tag: impl Into + Clone, -) -> Result, std::io::Error> { +) -> Result { // FIXME: should probably write a sqlite virtual filesystem // that will allow us to use bytes as a file to avoid this // write out, but this will require C code. Might be @@ -132,15 +138,15 @@ fn from_sqlite(args: CommandArgs, registry: &CommandRegistry) -> Result> = input.values.collect().await; + let values: Vec = input.values.collect().await; for value in values { - let value_tag = value.tag(); - match value.item { - Value::Primitive(Primitive::Binary(vb)) => + let value_tag = &value.tag; + match value.value { + UntaggedValue::Primitive(Primitive::Binary(vb)) => match from_sqlite_bytes_to_value(vb, tag.clone()) { Ok(x) => match x { - Tagged { item: Value::Table(list), .. } => { + Value { value: UntaggedValue::Table(list), .. } => { for l in list { yield ReturnSuccess::value(l); } diff --git a/src/commands/from_ssv.rs b/src/commands/from_ssv.rs index 269d4d1d72..a77ecf4f50 100644 --- a/src/commands/from_ssv.rs +++ b/src/commands/from_ssv.rs @@ -1,6 +1,7 @@ use crate::commands::WholeStreamCommand; use crate::data::{Primitive, TaggedDictBuilder, Value}; use crate::prelude::*; +use nu_source::Tagged; pub struct FromSSV; @@ -223,23 +224,24 @@ fn from_ssv_string_to_value( aligned_columns: bool, split_at: usize, tag: impl Into, -) -> Option> { +) -> Option { let tag = tag.into(); let rows = string_to_table(s, headerless, aligned_columns, split_at)? .iter() .map(|row| { let mut tagged_dict = TaggedDictBuilder::new(&tag); for (col, entry) in row { - tagged_dict.insert_tagged( + tagged_dict.insert_value( col, - Value::Primitive(Primitive::String(String::from(entry))).tagged(&tag), + UntaggedValue::Primitive(Primitive::String(String::from(entry))) + .into_value(&tag), ) } - tagged_dict.into_tagged_value() + tagged_dict.into_value() }) .collect(); - Some(Value::Table(rows).tagged(&tag)) + Some(UntaggedValue::Table(rows).into_value(&tag)) } fn from_ssv( @@ -251,7 +253,7 @@ fn from_ssv( RunnableContext { input, name, .. }: RunnableContext, ) -> Result { let stream = async_stream! { - let values: Vec> = input.values.collect().await; + let values: Vec = input.values.collect().await; let mut concat_string = String::new(); let mut latest_tag: Option = None; let split_at = match minimum_spaces { @@ -260,10 +262,10 @@ fn from_ssv( }; for value in values { - let value_tag = value.tag(); + let value_tag = value.tag.clone(); latest_tag = Some(value_tag.clone()); - match value.item { - Value::Primitive(Primitive::String(s)) => { + match &value.value { + UntaggedValue::Primitive(Primitive::String(s)) => { concat_string.push_str(&s); } _ => yield Err(ShellError::labeled_error_with_secondary ( @@ -278,7 +280,7 @@ fn from_ssv( match from_ssv_string_to_value(&concat_string, headerless, aligned_columns, split_at, name.clone()) { Some(x) => match x { - Tagged { item: Value::Table(list), ..} => { + Value { value: UntaggedValue::Table(list), ..} => { for l in list { yield ReturnSuccess::value(l) } } x => yield ReturnSuccess::value(x) diff --git a/src/commands/from_toml.rs b/src/commands/from_toml.rs index 2cfd059165..70ddde6b7d 100644 --- a/src/commands/from_toml.rs +++ b/src/commands/from_toml.rs @@ -26,39 +26,38 @@ impl WholeStreamCommand for FromTOML { } } -pub fn convert_toml_value_to_nu_value(v: &toml::Value, tag: impl Into) -> Tagged { +pub fn convert_toml_value_to_nu_value(v: &toml::Value, tag: impl Into) -> Value { let tag = tag.into(); match v { - toml::Value::Boolean(b) => Value::boolean(*b).tagged(tag), - toml::Value::Integer(n) => Value::number(n).tagged(tag), - toml::Value::Float(n) => Value::number(n).tagged(tag), - toml::Value::String(s) => Value::Primitive(Primitive::String(String::from(s))).tagged(tag), - toml::Value::Array(a) => Value::Table( + toml::Value::Boolean(b) => UntaggedValue::boolean(*b).into_value(tag), + toml::Value::Integer(n) => UntaggedValue::number(n).into_value(tag), + toml::Value::Float(n) => UntaggedValue::number(n).into_value(tag), + toml::Value::String(s) => { + UntaggedValue::Primitive(Primitive::String(String::from(s))).into_value(tag) + } + toml::Value::Array(a) => UntaggedValue::Table( a.iter() .map(|x| convert_toml_value_to_nu_value(x, &tag)) .collect(), ) - .tagged(tag), + .into_value(tag), toml::Value::Datetime(dt) => { - Value::Primitive(Primitive::String(dt.to_string())).tagged(tag) + UntaggedValue::Primitive(Primitive::String(dt.to_string())).into_value(tag) } toml::Value::Table(t) => { let mut collected = TaggedDictBuilder::new(&tag); for (k, v) in t.iter() { - collected.insert_tagged(k.clone(), convert_toml_value_to_nu_value(v, &tag)); + collected.insert_value(k.clone(), convert_toml_value_to_nu_value(v, &tag)); } - collected.into_tagged_value() + collected.into_value() } } } -pub fn from_toml_string_to_value( - s: String, - tag: impl Into, -) -> Result, toml::de::Error> { +pub fn from_toml_string_to_value(s: String, tag: impl Into) -> Result { let v: toml::Value = s.parse::()?; Ok(convert_toml_value_to_nu_value(&v, tag)) } @@ -69,28 +68,29 @@ pub fn from_toml( ) -> Result { let args = args.evaluate_once(registry)?; let tag = args.name_tag(); + let name_span = tag.span; let input = args.input; let stream = async_stream! { - let values: Vec> = input.values.collect().await; + let values: Vec = input.values.collect().await; let mut concat_string = String::new(); let mut latest_tag: Option = None; for value in values { - let value_tag = value.tag(); - latest_tag = Some(value_tag.clone()); - match value.item { - Value::Primitive(Primitive::String(s)) => { + 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( "Expected a string from pipeline", "requires string input", - &tag, + name_span, "value originates from here", - &value_tag, + value_span, )), } @@ -98,7 +98,7 @@ pub fn from_toml( match from_toml_string_to_value(concat_string, tag.clone()) { Ok(x) => match x { - Tagged { item: Value::Table(list), .. } => { + Value { value: UntaggedValue::Table(list), .. } => { for l in list { yield ReturnSuccess::value(l); } diff --git a/src/commands/from_url.rs b/src/commands/from_url.rs index ad23ea5b53..e3b6694ad3 100644 --- a/src/commands/from_url.rs +++ b/src/commands/from_url.rs @@ -29,27 +29,28 @@ impl WholeStreamCommand for FromURL { fn from_url(args: CommandArgs, registry: &CommandRegistry) -> Result { let args = args.evaluate_once(registry)?; let tag = args.name_tag(); + let name_span = tag.span; let input = args.input; let stream = async_stream! { - let values: Vec> = input.values.collect().await; + let values: Vec = input.values.collect().await; let mut concat_string = String::new(); let mut latest_tag: Option = None; for value in values { - let value_tag = value.tag(); - latest_tag = Some(value_tag.clone()); - match value.item { - Value::Primitive(Primitive::String(s)) => { + 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); } _ => yield Err(ShellError::labeled_error_with_secondary( "Expected a string from pipeline", "requires string input", - &tag, + name_span, "value originates from here", - &value_tag, + value_span, )), } @@ -62,10 +63,10 @@ fn from_url(args: CommandArgs, registry: &CommandRegistry) -> Result { if let Some(last_tag) = latest_tag { diff --git a/src/commands/from_xlsx.rs b/src/commands/from_xlsx.rs index da6e3c883e..bfd350d012 100644 --- a/src/commands/from_xlsx.rs +++ b/src/commands/from_xlsx.rs @@ -45,12 +45,14 @@ fn from_xlsx( let tag = runnable_context.name; let stream = async_stream! { - let values: Vec> = input.values.collect().await; + let values: Vec = input.values.collect().await; for value in values { - let value_tag = value.tag(); - match value.item { - Value::Primitive(Primitive::Binary(vb)) => { + let value_span = value.tag.span; + let value_tag = value.tag.clone(); + + match value.value { + UntaggedValue::Primitive(Primitive::Binary(vb)) => { let mut buf: Cursor> = Cursor::new(vb); let mut xls = Xlsx::<_>::new(buf).unwrap(); @@ -67,24 +69,24 @@ fn from_xlsx( let mut row_output = TaggedDictBuilder::new(&tag); for (i, cell) in row.iter().enumerate() { let value = match cell { - DataType::Empty => Value::nothing(), - DataType::String(s) => Value::string(s), - DataType::Float(f) => Value::decimal(*f), - DataType::Int(i) => Value::int(*i), - DataType::Bool(b) => Value::boolean(*b), - _ => Value::nothing(), + DataType::Empty => UntaggedValue::nothing(), + DataType::String(s) => UntaggedValue::string(s), + DataType::Float(f) => UntaggedValue::decimal(*f), + DataType::Int(i) => UntaggedValue::int(*i), + DataType::Bool(b) => UntaggedValue::boolean(*b), + _ => UntaggedValue::nothing(), }; - row_output.insert(&format!("Column{}", i), value); + row_output.insert_untagged(&format!("Column{}", i), value); } - sheet_output.push(row_output.into_tagged_value().item); + sheet_output.push_untagged(row_output.into_untagged_value()); } - dict.insert(sheet_name, sheet_output.into_tagged_value().item); + dict.insert_untagged(sheet_name, sheet_output.into_untagged_value()); } - yield ReturnSuccess::value(dict.into_tagged_value()); + yield ReturnSuccess::value(dict.into_value()); } _ => yield Err(ShellError::labeled_error_with_secondary( "Expected binary data from pipeline", diff --git a/src/commands/from_xml.rs b/src/commands/from_xml.rs index e99e5664e5..1b97646980 100644 --- a/src/commands/from_xml.rs +++ b/src/commands/from_xml.rs @@ -1,5 +1,6 @@ use crate::commands::WholeStreamCommand; -use crate::data::{Primitive, TaggedDictBuilder, Value}; +use crate::data::base::{Primitive, UntaggedValue, Value}; +use crate::data::TaggedDictBuilder; use crate::prelude::*; pub struct FromXML; @@ -26,7 +27,7 @@ impl WholeStreamCommand for FromXML { } } -fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>, tag: impl Into) -> Tagged { +fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>, tag: impl Into) -> Value { let tag = tag.into(); if n.is_element() { @@ -37,11 +38,11 @@ fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>, tag: impl Into) children_values.push(from_node_to_value(&c, &tag)); } - let children_values: Vec> = children_values + let children_values: Vec = children_values .into_iter() .filter(|x| match x { - Tagged { - item: Value::Primitive(Primitive::String(f)), + Value { + value: UntaggedValue::Primitive(Primitive::String(f)), .. } => { if f.trim() == "" { @@ -55,28 +56,25 @@ fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>, tag: impl Into) .collect(); let mut collected = TaggedDictBuilder::new(tag); - collected.insert(name.clone(), Value::Table(children_values)); + collected.insert_untagged(name.clone(), UntaggedValue::Table(children_values)); - collected.into_tagged_value() + collected.into_value() } else if n.is_comment() { - Value::string("").tagged(tag) + UntaggedValue::string("").into_value(tag) } else if n.is_pi() { - Value::string("").tagged(tag) + UntaggedValue::string("").into_value(tag) } else if n.is_text() { - Value::string(n.text().unwrap()).tagged(tag) + UntaggedValue::string(n.text().unwrap()).into_value(tag) } else { - Value::string("").tagged(tag) + UntaggedValue::string("").into_value(tag) } } -fn from_document_to_value(d: &roxmltree::Document, tag: impl Into) -> Tagged { +fn from_document_to_value(d: &roxmltree::Document, tag: impl Into) -> Value { from_node_to_value(&d.root_element(), tag) } -pub fn from_xml_string_to_value( - s: String, - tag: impl Into, -) -> Result, roxmltree::Error> { +pub fn from_xml_string_to_value(s: String, tag: impl Into) -> Result { let parsed = roxmltree::Document::parse(&s)?; Ok(from_document_to_value(&parsed, tag)) } @@ -84,28 +82,30 @@ pub fn from_xml_string_to_value( fn from_xml(args: CommandArgs, registry: &CommandRegistry) -> Result { let args = args.evaluate_once(registry)?; let tag = args.name_tag(); + let name_span = tag.span; let input = args.input; let stream = async_stream! { - let values: Vec> = input.values.collect().await; + let values: Vec = input.values.collect().await; let mut concat_string = String::new(); let mut latest_tag: Option = None; for value in values { - let value_tag = value.tag(); - latest_tag = Some(value_tag.clone()); - match value.item { - Value::Primitive(Primitive::String(s)) => { + 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( "Expected a string from pipeline", "requires string input", - &tag, + name_span, "value originates from here", - &value_tag, + value_span, )), } @@ -113,7 +113,7 @@ fn from_xml(args: CommandArgs, registry: &CommandRegistry) -> Result match x { - Tagged { item: Value::Table(list), .. } => { + Value { value: UntaggedValue::Table(list), .. } => { for l in list { yield ReturnSuccess::value(l); } @@ -139,23 +139,23 @@ fn from_xml(args: CommandArgs, registry: &CommandRegistry) -> Result) -> Tagged { - Value::string(input.into()).tagged_unknown() + fn string(input: impl Into) -> Value { + UntaggedValue::string(input.into()).into_untagged_value() } - fn row(entries: IndexMap>) -> Tagged { - Value::row(entries).tagged_unknown() + fn row(entries: IndexMap) -> Value { + UntaggedValue::row(entries).into_untagged_value() } - fn table(list: &Vec>) -> Tagged { - Value::table(list).tagged_unknown() + fn table(list: &Vec) -> Value { + UntaggedValue::table(list).into_untagged_value() } - fn parse(xml: &str) -> Tagged { + fn parse(xml: &str) -> Value { from_xml::from_xml_string_to_value(xml.to_string(), Tag::unknown()).unwrap() } diff --git a/src/commands/from_yaml.rs b/src/commands/from_yaml.rs index 3ba8033ddf..6377efd77f 100644 --- a/src/commands/from_yaml.rs +++ b/src/commands/from_yaml.rs @@ -50,47 +50,44 @@ impl WholeStreamCommand for FromYML { } } -fn convert_yaml_value_to_nu_value(v: &serde_yaml::Value, tag: impl Into) -> Tagged { +fn convert_yaml_value_to_nu_value(v: &serde_yaml::Value, tag: impl Into) -> Value { let tag = tag.into(); match v { - serde_yaml::Value::Bool(b) => Value::boolean(*b).tagged(tag), + serde_yaml::Value::Bool(b) => UntaggedValue::boolean(*b).into_value(tag), serde_yaml::Value::Number(n) if n.is_i64() => { - Value::number(n.as_i64().unwrap()).tagged(tag) + UntaggedValue::number(n.as_i64().unwrap()).into_value(tag) } serde_yaml::Value::Number(n) if n.is_f64() => { - Value::Primitive(Primitive::from(n.as_f64().unwrap())).tagged(tag) + UntaggedValue::Primitive(Primitive::from(n.as_f64().unwrap())).into_value(tag) } - serde_yaml::Value::String(s) => Value::string(s).tagged(tag), - serde_yaml::Value::Sequence(a) => Value::Table( + serde_yaml::Value::String(s) => UntaggedValue::string(s).into_value(tag), + serde_yaml::Value::Sequence(a) => UntaggedValue::Table( a.iter() .map(|x| convert_yaml_value_to_nu_value(x, &tag)) .collect(), ) - .tagged(tag), + .into_value(tag), serde_yaml::Value::Mapping(t) => { let mut collected = TaggedDictBuilder::new(&tag); for (k, v) in t.iter() { match k { serde_yaml::Value::String(k) => { - collected.insert_tagged(k.clone(), convert_yaml_value_to_nu_value(v, &tag)); + collected.insert_value(k.clone(), convert_yaml_value_to_nu_value(v, &tag)); } _ => unimplemented!("Unknown key type"), } } - collected.into_tagged_value() + collected.into_value() } - serde_yaml::Value::Null => Value::Primitive(Primitive::Nothing).tagged(tag), + serde_yaml::Value::Null => UntaggedValue::Primitive(Primitive::Nothing).into_value(tag), x => unimplemented!("Unsupported yaml case: {:?}", x), } } -pub fn from_yaml_string_to_value( - s: String, - tag: impl Into, -) -> serde_yaml::Result> { +pub fn from_yaml_string_to_value(s: String, tag: impl Into) -> serde_yaml::Result { let v: serde_yaml::Value = serde_yaml::from_str(&s)?; Ok(convert_yaml_value_to_nu_value(&v, tag)) } @@ -98,28 +95,30 @@ pub fn from_yaml_string_to_value( fn from_yaml(args: CommandArgs, registry: &CommandRegistry) -> Result { let args = args.evaluate_once(registry)?; let tag = args.name_tag(); + let name_span = tag.span; let input = args.input; let stream = async_stream! { - let values: Vec> = input.values.collect().await; + let values: Vec = input.values.collect().await; let mut concat_string = String::new(); let mut latest_tag: Option = None; for value in values { - let value_tag = value.tag(); - latest_tag = Some(value_tag.clone()); - match value.item { - Value::Primitive(Primitive::String(s)) => { + 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( "Expected a string from pipeline", "requires string input", - &tag, + name_span, "value originates from here", - &value_tag, + value_span, )), } @@ -127,7 +126,7 @@ fn from_yaml(args: CommandArgs, registry: &CommandRegistry) -> Result match x { - Tagged { item: Value::Table(list), .. } => { + Value { value: UntaggedValue::Table(list), .. } => { for l in list { yield ReturnSuccess::value(l); } diff --git a/src/commands/get.rs b/src/commands/get.rs index 9b17f89128..fe39287620 100644 --- a/src/commands/get.rs +++ b/src/commands/get.rs @@ -7,6 +7,7 @@ use crate::utils::did_you_mean; use crate::ColumnPath; use futures_util::pin_mut; use log::trace; +use nu_source::{span_for_spanned_list, PrettyDebug}; pub struct Get; @@ -40,31 +41,31 @@ impl WholeStreamCommand for Get { } } -pub fn get_column_path( - path: &ColumnPath, - obj: &Tagged, -) -> Result, ShellError> { +pub fn get_column_path(path: &ColumnPath, obj: &Value) -> Result { let fields = path.clone(); - let value = obj.get_data_by_column_path( + obj.get_data_by_column_path( path, Box::new(move |(obj_source, column_path_tried, error)| { - match obj_source { - Value::Table(rows) => { + match &obj_source.value { + UntaggedValue::Table(rows) => { let total = rows.len(); let end_tag = match fields .members() .iter() .nth_back(if fields.members().len() > 2 { 1 } else { 0 }) { - Some(last_field) => last_field.span(), - None => column_path_tried.span(), + Some(last_field) => last_field.span, + None => column_path_tried.span, }; return ShellError::labeled_error_with_secondary( "Row not found", - format!("There isn't a row indexed at {}", **column_path_tried), - column_path_tried.span(), + format!( + "There isn't a row indexed at {}", + column_path_tried.display() + ), + column_path_tried.span, if total == 1 { format!("The table only has 1 row") } else { @@ -81,7 +82,7 @@ pub fn get_column_path( return ShellError::labeled_error( "Unknown column", format!("did you mean '{}'?", suggestions[0].1), - span_for_spanned_list(fields.members().iter().map(|p| p.span())), + span_for_spanned_list(fields.members().iter().map(|p| p.span)), ) } None => {} @@ -89,14 +90,7 @@ pub fn get_column_path( return error; }), - ); - - let res = match value { - Ok(Tagged { item: v, tag }) => Ok((v.clone()).tagged(&tag)), - Err(reason) => Err(reason), - }; - - res + ) } pub fn get( @@ -112,7 +106,7 @@ pub fn get( let mut index = 0; while let Some(row) = values.next().await { - shapes.add(&row.item, index); + shapes.add(&row, index); index += 1; } @@ -144,8 +138,8 @@ pub fn get( match res { Ok(got) => match got { - Tagged { - item: Value::Table(rows), + Value { + value: UntaggedValue::Table(rows), .. } => { for item in rows { @@ -154,8 +148,9 @@ pub fn get( } other => result.push_back(ReturnSuccess::value(other.clone())), }, - Err(reason) => result - .push_back(ReturnSuccess::value(Value::Error(reason).tagged_unknown())), + Err(reason) => result.push_back(ReturnSuccess::value( + UntaggedValue::Error(reason).into_untagged_value(), + )), } } diff --git a/src/commands/group_by.rs b/src/commands/group_by.rs index 66bbb42718..066950db72 100644 --- a/src/commands/group_by.rs +++ b/src/commands/group_by.rs @@ -1,7 +1,9 @@ use crate::commands::WholeStreamCommand; +use crate::data::base::UntaggedValue; use crate::data::TaggedDictBuilder; use crate::errors::ShellError; use crate::prelude::*; +use nu_source::Tagged; pub struct GroupBy; @@ -41,7 +43,7 @@ pub fn group_by( RunnableContext { input, name, .. }: RunnableContext, ) -> Result { let stream = async_stream! { - let values: Vec> = input.values.collect().await; + let values: Vec = input.values.collect().await; if values.is_empty() { yield Err(ShellError::labeled_error( @@ -62,9 +64,9 @@ pub fn group_by( pub fn group( column_name: &Tagged, - values: Vec>, + values: Vec, tag: impl Into, -) -> Result, ShellError> { +) -> Result { let tag = tag.into(); let mut groups = indexmap::IndexMap::new(); @@ -105,33 +107,32 @@ pub fn group( let mut out = TaggedDictBuilder::new(&tag); for (k, v) in groups.iter() { - out.insert(k, Value::table(v)); + out.insert_untagged(k, UntaggedValue::table(v)); } - Ok(out.into_tagged_value()) + Ok(out.into_value()) } #[cfg(test)] mod tests { - use crate::commands::group_by::group; - use crate::data::meta::*; - use crate::Value; + use crate::data::base::{UntaggedValue, Value}; use indexmap::IndexMap; + use nu_source::*; - fn string(input: impl Into) -> Tagged { - Value::string(input.into()).tagged_unknown() + fn string(input: impl Into) -> Value { + UntaggedValue::string(input.into()).into_untagged_value() } - fn row(entries: IndexMap>) -> Tagged { - Value::row(entries).tagged_unknown() + fn row(entries: IndexMap) -> Value { + UntaggedValue::row(entries).into_untagged_value() } - fn table(list: &Vec>) -> Tagged { - Value::table(list).tagged_unknown() + fn table(list: &Vec) -> Value { + UntaggedValue::table(list).into_untagged_value() } - fn nu_releases_commiters() -> Vec> { + fn nu_releases_commiters() -> Vec { vec![ row( indexmap! {"name".into() => string("AR"), "country".into() => string("EC"), "date".into() => string("August 23-2019")}, diff --git a/src/commands/help.rs b/src/commands/help.rs index 487313352d..1082b9b35e 100644 --- a/src/commands/help.rs +++ b/src/commands/help.rs @@ -3,6 +3,7 @@ use crate::data::{command_dict, TaggedDictBuilder}; use crate::errors::ShellError; use crate::parser::registry::{self, NamedType, PositionalType}; use crate::prelude::*; +use nu_source::SpannedItem; pub struct Help; @@ -24,13 +25,13 @@ impl PerItemCommand for Help { call_info: &CallInfo, registry: &CommandRegistry, _raw_args: &RawCommandArgs, - _input: Tagged, + _input: Value, ) -> Result { let tag = &call_info.name_tag; match call_info.args.nth(0) { - Some(Tagged { - item: Value::Primitive(Primitive::String(document)), + Some(Value { + value: UntaggedValue::Primitive(Primitive::String(document)), tag, }) => { let mut help = VecDeque::new(); @@ -41,8 +42,8 @@ impl PerItemCommand for Help { let mut short_desc = TaggedDictBuilder::new(tag.clone()); let value = command_dict(registry.get_command(&cmd).unwrap(), tag.clone()); - short_desc.insert("name", cmd); - short_desc.insert( + short_desc.insert_untagged("name", cmd); + short_desc.insert_untagged( "description", value .get_data_by_key("usage".spanned_unknown()) @@ -51,7 +52,7 @@ impl PerItemCommand for Help { .unwrap(), ); - help.push_back(ReturnSuccess::value(short_desc.into_tagged_value())); + help.push_back(ReturnSuccess::value(short_desc.into_value())); } } else { if let Some(command) = registry.get_command(document) { @@ -148,7 +149,7 @@ impl PerItemCommand for Help { } help.push_back(ReturnSuccess::value( - Value::string(long_desc).tagged(tag.clone()), + UntaggedValue::string(long_desc).into_value(tag.clone()), )); } } @@ -166,7 +167,9 @@ You can also learn more at https://book.nushell.sh"#; let mut output_stream = VecDeque::new(); - output_stream.push_back(ReturnSuccess::value(Value::string(msg).tagged(tag))); + output_stream.push_back(ReturnSuccess::value( + UntaggedValue::string(msg).into_value(tag), + )); Ok(output_stream.to_output_stream()) } diff --git a/src/commands/histogram.rs b/src/commands/histogram.rs index bff24aa029..533126ccf8 100644 --- a/src/commands/histogram.rs +++ b/src/commands/histogram.rs @@ -8,6 +8,7 @@ use crate::commands::WholeStreamCommand; use crate::data::TaggedDictBuilder; use crate::errors::ShellError; use crate::prelude::*; +use nu_source::Tagged; use num_traits::cast::ToPrimitive; pub struct Histogram; @@ -54,7 +55,7 @@ pub fn histogram( RunnableContext { input, name, .. }: RunnableContext, ) -> Result { let stream = async_stream! { - let values: Vec> = input.values.collect().await; + let values: Vec = input.values.collect().await; let Tagged { item: group_by, .. } = column_name.clone(); @@ -67,8 +68,8 @@ pub fn histogram( let percents = percentages(&reduced, maxima, &name)?; match percents { - Tagged { - item: Value::Table(datasets), + Value { + value: UntaggedValue::Table(datasets), .. } => { @@ -84,20 +85,21 @@ pub fn histogram( let column = (*column_name).clone(); - if let Tagged { item: Value::Table(start), .. } = datasets.get(0).unwrap() { + if let Value { value: UntaggedValue::Table(start), .. } = datasets.get(0).unwrap() { for percentage in start.into_iter() { let mut fact = TaggedDictBuilder::new(&name); let value: Tagged = group_labels.get(idx).unwrap().clone(); - fact.insert_tagged(&column, Value::string(value.item).tagged(value.tag)); + fact.insert_value(&column, UntaggedValue::string(value.item).into_value(value.tag)); - if let Tagged { item: Value::Primitive(Primitive::Int(ref num)), .. } = percentage.clone() { - fact.insert(&frequency_column_name, std::iter::repeat("*").take(num.to_i32().unwrap() as usize).collect::()); + if let Value { value: UntaggedValue::Primitive(Primitive::Int(ref num)), .. } = percentage.clone() { + let string = std::iter::repeat("*").take(num.to_i32().unwrap() as usize).collect::(); + fact.insert_untagged(&frequency_column_name, UntaggedValue::string(string)); } idx = idx + 1; - yield ReturnSuccess::value(fact.into_tagged_value()); + yield ReturnSuccess::value(fact.into_value()); } } } @@ -108,54 +110,53 @@ pub fn histogram( Ok(stream.to_output_stream()) } -fn percentages( - values: &Tagged, - max: Tagged, - tag: impl Into, -) -> Result, ShellError> { +fn percentages(values: &Value, max: Value, tag: impl Into) -> Result { let tag = tag.into(); - let results: Tagged = match values { - Tagged { - item: Value::Table(datasets), + let results: Value = match values { + Value { + value: UntaggedValue::Table(datasets), .. } => { let datasets: Vec<_> = datasets .into_iter() .map(|subsets| match subsets { - Tagged { - item: Value::Table(data), + Value { + value: UntaggedValue::Table(data), .. } => { - let data = data - .into_iter() - .map(|d| match d { - Tagged { - item: Value::Primitive(Primitive::Int(n)), - .. - } => { - let max = match max { - Tagged { - item: Value::Primitive(Primitive::Int(ref maxima)), + let data = + data.into_iter() + .map(|d| match d { + Value { + value: UntaggedValue::Primitive(Primitive::Int(n)), .. - } => maxima.to_i32().unwrap(), - _ => 0, - }; + } => { + let max = match max { + Value { + value: + UntaggedValue::Primitive(Primitive::Int( + ref maxima, + )), + .. + } => maxima.to_i32().unwrap(), + _ => 0, + }; - let n = { n.to_i32().unwrap() * 100 / max }; + let n = { n.to_i32().unwrap() * 100 / max }; - Value::number(n).tagged(&tag) - } - _ => Value::number(0).tagged(&tag), - }) - .collect::>(); - Value::Table(data).tagged(&tag) + UntaggedValue::number(n).into_value(&tag) + } + _ => UntaggedValue::number(0).into_value(&tag), + }) + .collect::>(); + UntaggedValue::Table(data).into_value(&tag) } - _ => Value::Table(vec![]).tagged(&tag), + _ => UntaggedValue::Table(vec![]).into_value(&tag), }) .collect(); - Value::Table(datasets).tagged(&tag) + UntaggedValue::Table(datasets).into_value(&tag) } other => other.clone(), }; diff --git a/src/commands/history.rs b/src/commands/history.rs index fdc6d655a2..9c4fc7e80c 100644 --- a/src/commands/history.rs +++ b/src/commands/history.rs @@ -26,7 +26,7 @@ impl PerItemCommand for History { call_info: &CallInfo, _registry: &CommandRegistry, _raw_args: &RawCommandArgs, - _input: Tagged, + _input: Value, ) -> Result { let tag = call_info.name_tag.clone(); @@ -37,7 +37,7 @@ impl PerItemCommand for History { let reader = BufReader::new(file); for line in reader.lines() { if let Ok(line) = line { - yield ReturnSuccess::value(Value::string(line).tagged(tag.clone())); + yield ReturnSuccess::value(UntaggedValue::string(line).into_value(tag.clone())); } } } else { diff --git a/src/commands/last.rs b/src/commands/last.rs index abb10f5fce..35d84de861 100644 --- a/src/commands/last.rs +++ b/src/commands/last.rs @@ -2,6 +2,7 @@ use crate::commands::WholeStreamCommand; use crate::errors::ShellError; use crate::parser::CommandRegistry; use crate::prelude::*; +use nu_source::Tagged; pub struct Last; @@ -50,7 +51,7 @@ fn last(LastArgs { rows }: LastArgs, context: RunnableContext) -> Result = x.clone(); + let y: Value = x.clone(); yield ReturnSuccess::value(y) } } diff --git a/src/commands/lines.rs b/src/commands/lines.rs index cf8bfc9b6c..0338d91e94 100644 --- a/src/commands/lines.rs +++ b/src/commands/lines.rs @@ -1,5 +1,5 @@ use crate::commands::WholeStreamCommand; -use crate::data::{Primitive, Value}; +use crate::data::Primitive; use crate::errors::ShellError; use crate::prelude::*; use log::trace; @@ -33,12 +33,13 @@ impl WholeStreamCommand for Lines { fn lines(args: CommandArgs, registry: &CommandRegistry) -> Result { let args = args.evaluate_once(registry)?; let tag = args.name_tag(); + let name_span = tag.span; let input = args.input; let stream = input .values - .map(move |v| match v.item { - Value::Primitive(Primitive::String(s)) => { + .map(move |v| match v.value { + UntaggedValue::Primitive(Primitive::String(s)) => { let split_result: Vec<_> = s.lines().filter(|s| s.trim() != "").collect(); trace!("split result = {:?}", split_result); @@ -46,19 +47,21 @@ fn lines(args: CommandArgs, registry: &CommandRegistry) -> Result { let mut result = VecDeque::new(); + let value_span = v.tag.span; + result.push_back(Err(ShellError::labeled_error_with_secondary( "Expected a string from pipeline", "requires string input", - &tag, + name_span, "value originates from here", - v.tag(), + value_span, ))); result } diff --git a/src/commands/ls.rs b/src/commands/ls.rs index 6bc2daa28d..ddb58ebaf4 100644 --- a/src/commands/ls.rs +++ b/src/commands/ls.rs @@ -1,6 +1,7 @@ use crate::commands::WholeStreamCommand; use crate::errors::ShellError; use crate::prelude::*; +use nu_source::Tagged; use std::path::PathBuf; pub struct LS; diff --git a/src/commands/map_max_by.rs b/src/commands/map_max_by.rs index ea2fc99219..7b34f05432 100644 --- a/src/commands/map_max_by.rs +++ b/src/commands/map_max_by.rs @@ -1,7 +1,9 @@ use crate::commands::WholeStreamCommand; use crate::parser::hir::SyntaxShape; use crate::prelude::*; +use nu_source::Tagged; use num_traits::cast::ToPrimitive; + pub struct MapMaxBy; #[derive(Deserialize)] @@ -40,7 +42,7 @@ pub fn map_max_by( RunnableContext { input, name, .. }: RunnableContext, ) -> Result { let stream = async_stream! { - let values: Vec> = input.values.collect().await; + let values: Vec = input.values.collect().await; if values.is_empty() { @@ -68,27 +70,27 @@ pub fn map_max_by( } pub fn map_max( - values: &Tagged, + values: &Value, _map_by_column_name: Option, tag: impl Into, -) -> Result, ShellError> { +) -> Result { let tag = tag.into(); - let results: Tagged = match values { - Tagged { - item: Value::Table(datasets), + let results: Value = match values { + Value { + value: UntaggedValue::Table(datasets), .. } => { let datasets: Vec<_> = datasets .into_iter() .map(|subsets| match subsets { - Tagged { - item: Value::Table(data), + Value { + value: UntaggedValue::Table(data), .. } => { let data = data.into_iter().fold(0, |acc, value| match value { - Tagged { - item: Value::Primitive(Primitive::Int(n)), + Value { + value: UntaggedValue::Primitive(Primitive::Int(n)), .. } => { if n.to_i32().unwrap() > acc { @@ -99,15 +101,15 @@ pub fn map_max( } _ => acc, }); - Value::number(data).tagged(&tag) + UntaggedValue::number(data).into_value(&tag) } - _ => Value::number(0).tagged(&tag), + _ => UntaggedValue::number(0).into_value(&tag), }) .collect(); let datasets = datasets.iter().fold(0, |max, value| match value { - Tagged { - item: Value::Primitive(Primitive::Int(n)), + Value { + value: UntaggedValue::Primitive(Primitive::Int(n)), .. } => { if n.to_i32().unwrap() > max { @@ -118,9 +120,9 @@ pub fn map_max( } _ => max, }); - Value::number(datasets).tagged(&tag) + UntaggedValue::number(datasets).into_value(&tag) } - _ => Value::number(-1).tagged(&tag), + _ => UntaggedValue::number(-1).into_value(&tag), }; Ok(results) @@ -134,28 +136,28 @@ mod tests { use crate::commands::map_max_by::map_max; use crate::commands::reduce_by::reduce; use crate::commands::t_sort_by::t_sort; - use crate::data::meta::*; use crate::prelude::*; use crate::Value; use indexmap::IndexMap; + use nu_source::*; - fn int(s: impl Into) -> Tagged { - Value::int(s).tagged_unknown() + fn int(s: impl Into) -> Value { + UntaggedValue::int(s).into_untagged_value() } - fn string(input: impl Into) -> Tagged { - Value::string(input.into()).tagged_unknown() + fn string(input: impl Into) -> Value { + UntaggedValue::string(input.into()).into_untagged_value() } - fn row(entries: IndexMap>) -> Tagged { - Value::row(entries).tagged_unknown() + fn row(entries: IndexMap) -> Value { + UntaggedValue::row(entries).into_untagged_value() } - fn nu_releases_evaluated_by_default_one() -> Tagged { + fn nu_releases_evaluated_by_default_one() -> Value { evaluate(&nu_releases_sorted_by_date(), None, Tag::unknown()).unwrap() } - fn nu_releases_reduced_by_sum() -> Tagged { + fn nu_releases_reduced_by_sum() -> Value { reduce( &nu_releases_evaluated_by_default_one(), Some(String::from("sum")), @@ -164,7 +166,7 @@ mod tests { .unwrap() } - fn nu_releases_sorted_by_date() -> Tagged { + fn nu_releases_sorted_by_date() -> Value { let key = String::from("date"); t_sort( @@ -176,12 +178,12 @@ mod tests { .unwrap() } - fn nu_releases_grouped_by_date() -> Tagged { + fn nu_releases_grouped_by_date() -> Value { let key = String::from("date").tagged_unknown(); group(&key, nu_releases_commiters(), Tag::unknown()).unwrap() } - fn nu_releases_commiters() -> Vec> { + fn nu_releases_commiters() -> Vec { vec![ row( indexmap! {"name".into() => string("AR"), "country".into() => string("EC"), "date".into() => string("August 23-2019")}, diff --git a/src/commands/mkdir.rs b/src/commands/mkdir.rs index e801a27530..561f5c4c96 100644 --- a/src/commands/mkdir.rs +++ b/src/commands/mkdir.rs @@ -2,6 +2,7 @@ use crate::commands::command::RunnablePerItemContext; use crate::errors::ShellError; use crate::parser::registry::{CommandRegistry, Signature}; use crate::prelude::*; +use nu_source::Tagged; use std::path::PathBuf; pub struct Mkdir; @@ -29,7 +30,7 @@ impl PerItemCommand for Mkdir { call_info: &CallInfo, _registry: &CommandRegistry, raw_args: &RawCommandArgs, - _input: Tagged, + _input: Value, ) -> Result { call_info.process(&raw_args.shell_manager, mkdir)?.run() } diff --git a/src/commands/mv.rs b/src/commands/mv.rs index a9a11f5064..6e90d1087f 100644 --- a/src/commands/mv.rs +++ b/src/commands/mv.rs @@ -3,6 +3,7 @@ use crate::errors::ShellError; use crate::parser::hir::SyntaxShape; use crate::parser::registry::{CommandRegistry, Signature}; use crate::prelude::*; +use nu_source::Tagged; use std::path::PathBuf; pub struct Move; @@ -41,7 +42,7 @@ impl PerItemCommand for Move { call_info: &CallInfo, _registry: &CommandRegistry, raw_args: &RawCommandArgs, - _input: Tagged, + _input: Value, ) -> Result { call_info.process(&raw_args.shell_manager, mv)?.run() } diff --git a/src/commands/nth.rs b/src/commands/nth.rs index bcd3057879..8e7e0828bf 100644 --- a/src/commands/nth.rs +++ b/src/commands/nth.rs @@ -2,6 +2,7 @@ use crate::commands::WholeStreamCommand; use crate::errors::ShellError; use crate::parser::CommandRegistry; use crate::prelude::*; +use nu_source::Tagged; #[derive(Deserialize)] struct NthArgs { diff --git a/src/commands/open.rs b/src/commands/open.rs index 3d7e066a26..47fc2ecc8b 100644 --- a/src/commands/open.rs +++ b/src/commands/open.rs @@ -1,11 +1,11 @@ use crate::commands::UnevaluatedCallInfo; -use crate::context::AnchorLocation; -use crate::data::meta::Span; use crate::data::Value; use crate::errors::ShellError; use crate::parser::hir::SyntaxShape; use crate::parser::registry::Signature; use crate::prelude::*; +use nu_source::AnchorLocation; +use nu_source::Span; use std::path::{Path, PathBuf}; pub struct Open; @@ -33,7 +33,7 @@ impl PerItemCommand for Open { call_info: &CallInfo, registry: &CommandRegistry, raw_args: &RawCommandArgs, - _input: Tagged, + _input: Value, ) -> Result { run(call_info, registry, raw_args) } @@ -48,15 +48,14 @@ fn run( let cwd = PathBuf::from(shell_manager.path()); let full_path = PathBuf::from(cwd); - let path = match call_info.args.nth(0).ok_or_else(|| { + let path = call_info.args.nth(0).ok_or_else(|| { ShellError::labeled_error( "No file or directory specified", "for command", &call_info.name_tag, ) - })? { - file => file, - }; + })?; + let path_buf = path.as_path()?; let path_str = path_buf.display().to_string(); let path_span = path.tag.span; @@ -82,7 +81,7 @@ fn run( file_extension.or(path_str.split('.').last().map(String::from)) }; - let tagged_contents = contents.tagged(&contents_tag); + let tagged_contents = contents.into_value(&contents_tag); if let Some(extension) = file_extension { let command_name = format!("from-{}", extension); @@ -95,7 +94,8 @@ fn run( args: crate::parser::hir::Call { head: raw_args.call_info.args.head, positional: None, - named: None + named: None, + span: Span::unknown() }, source: raw_args.call_info.source, name_tag: raw_args.call_info.name_tag, @@ -105,13 +105,13 @@ fn run( let result_vec: Vec> = result.drain_vec().await; for res in result_vec { match res { - Ok(ReturnSuccess::Value(Tagged { item: Value::Table(list), ..})) => { + Ok(ReturnSuccess::Value(Value { value: UntaggedValue::Table(list), ..})) => { for l in list { yield Ok(ReturnSuccess::Value(l)); } } - Ok(ReturnSuccess::Value(Tagged { item, .. })) => { - yield Ok(ReturnSuccess::Value(Tagged { item, tag: contents_tag.clone() })); + Ok(ReturnSuccess::Value(Value { value, .. })) => { + yield Ok(ReturnSuccess::Value(Value { value, tag: contents_tag.clone() })); } x => yield x, } @@ -131,7 +131,7 @@ pub async fn fetch( cwd: &PathBuf, location: &str, span: Span, -) -> Result<(Option, Value, Tag), ShellError> { +) -> Result<(Option, UntaggedValue, Tag), ShellError> { let mut cwd = cwd.clone(); cwd.push(Path::new(location)); @@ -141,7 +141,7 @@ pub async fn fetch( Ok(s) => Ok(( cwd.extension() .map(|name| name.to_string_lossy().to_string()), - Value::string(s), + UntaggedValue::string(s), Tag { span, anchor: Some(AnchorLocation::File(cwd.to_string_lossy().to_string())), @@ -159,7 +159,7 @@ pub async fn fetch( Ok(s) => Ok(( cwd.extension() .map(|name| name.to_string_lossy().to_string()), - Value::string(s), + UntaggedValue::string(s), Tag { span, anchor: Some(AnchorLocation::File( @@ -169,7 +169,7 @@ pub async fn fetch( )), Err(_) => Ok(( None, - Value::binary(bytes), + UntaggedValue::binary(bytes), Tag { span, anchor: Some(AnchorLocation::File( @@ -181,7 +181,7 @@ pub async fn fetch( } else { Ok(( None, - Value::binary(bytes), + UntaggedValue::binary(bytes), Tag { span, anchor: Some(AnchorLocation::File( @@ -200,7 +200,7 @@ pub async fn fetch( Ok(s) => Ok(( cwd.extension() .map(|name| name.to_string_lossy().to_string()), - Value::string(s), + UntaggedValue::string(s), Tag { span, anchor: Some(AnchorLocation::File( @@ -210,7 +210,7 @@ pub async fn fetch( )), Err(_) => Ok(( None, - Value::binary(bytes), + UntaggedValue::binary(bytes), Tag { span, anchor: Some(AnchorLocation::File( @@ -222,7 +222,7 @@ pub async fn fetch( } else { Ok(( None, - Value::binary(bytes), + UntaggedValue::binary(bytes), Tag { span, anchor: Some(AnchorLocation::File( @@ -234,7 +234,7 @@ pub async fn fetch( } _ => Ok(( None, - Value::binary(bytes), + UntaggedValue::binary(bytes), Tag { span, anchor: Some(AnchorLocation::File( diff --git a/src/commands/pick.rs b/src/commands/pick.rs index b9c4e53bcc..a6cdbf040a 100644 --- a/src/commands/pick.rs +++ b/src/commands/pick.rs @@ -3,6 +3,7 @@ use crate::context::CommandRegistry; use crate::data::base::select_fields; use crate::errors::ShellError; use crate::prelude::*; +use nu_source::Tagged; #[derive(Deserialize)] struct PickArgs { @@ -49,7 +50,7 @@ fn pick( let objects = input .values - .map(move |value| select_fields(&value.item, &fields, value.tag())); + .map(move |value| select_fields(&value, &fields, value.tag.clone())); Ok(objects.from_input_stream()) } diff --git a/src/commands/pivot.rs b/src/commands/pivot.rs index a431f883b5..86d25c4d4b 100644 --- a/src/commands/pivot.rs +++ b/src/commands/pivot.rs @@ -2,6 +2,7 @@ use crate::commands::WholeStreamCommand; use crate::errors::ShellError; use crate::prelude::*; use crate::TaggedDictBuilder; +use nu_source::{SpannedItem, Tagged}; pub struct Pivot; @@ -42,7 +43,7 @@ impl WholeStreamCommand for Pivot { } } -fn merge_descriptors(values: &[Tagged]) -> Vec { +fn merge_descriptors(values: &[Value]) -> Vec { let mut ret = vec![]; for value in values { for desc in value.data_descriptors() { @@ -110,23 +111,23 @@ pub fn pivot(args: PivotArgs, context: RunnableContext) -> Result { - dict.insert_tagged(headers[column_num].clone(), x.clone()); + dict.insert_value(headers[column_num].clone(), x.clone()); } _ => { - dict.insert(headers[column_num].clone(), Value::nothing()); + dict.insert_untagged(headers[column_num].clone(), UntaggedValue::nothing()); } } column_num += 1; } - yield ReturnSuccess::value(dict.into_tagged_value()); + yield ReturnSuccess::value(dict.into_value()); } diff --git a/src/commands/plugin.rs b/src/commands/plugin.rs index c9cc514af4..c7dc318717 100644 --- a/src/commands/plugin.rs +++ b/src/commands/plugin.rs @@ -79,11 +79,11 @@ pub fn filter_plugin( .spawn() .expect("Failed to spawn child process"); - let mut bos: VecDeque> = VecDeque::new(); - bos.push_back(Value::Primitive(Primitive::BeginningOfStream).tagged_unknown()); + let mut bos: VecDeque = VecDeque::new(); + bos.push_back(UntaggedValue::Primitive(Primitive::BeginningOfStream).into_untagged_value()); - let mut eos: VecDeque> = VecDeque::new(); - eos.push_back(Value::Primitive(Primitive::EndOfStream).tagged_unknown()); + let mut eos: VecDeque = VecDeque::new(); + eos.push_back(UntaggedValue::Primitive(Primitive::EndOfStream).into_untagged_value()); let call_info = args.call_info.clone(); @@ -93,8 +93,8 @@ pub fn filter_plugin( .chain(args.input.values) .chain(eos) .map(move |v| match v { - Tagged { - item: Value::Primitive(Primitive::BeginningOfStream), + Value { + value: UntaggedValue::Primitive(Primitive::BeginningOfStream), .. } => { let stdin = child.stdin.as_mut().expect("Failed to open stdin"); @@ -146,8 +146,8 @@ pub fn filter_plugin( } } } - Tagged { - item: Value::Primitive(Primitive::EndOfStream), + Value { + value: UntaggedValue::Primitive(Primitive::EndOfStream), .. } => { let stdin = child.stdin.as_mut().expect("Failed to open stdin"); @@ -298,7 +298,7 @@ pub fn sink_plugin( let call_info = args.call_info.clone(); let stream = async_stream! { - let input: Vec> = args.input.values.collect().await; + let input: Vec = args.input.values.collect().await; let request = JsonRpc::new("sink", (call_info.clone(), input)); let request_raw = serde_json::to_string(&request).unwrap(); @@ -315,7 +315,7 @@ pub fn sink_plugin( // Needed for async_stream to type check if false { - yield ReturnSuccess::value(Value::nothing().tagged_unknown()); + yield ReturnSuccess::value(UntaggedValue::nothing().into_untagged_value()); } }; Ok(OutputStream::new(stream)) diff --git a/src/commands/post.rs b/src/commands/post.rs index 92e4e8f135..1d4d1e7856 100644 --- a/src/commands/post.rs +++ b/src/commands/post.rs @@ -1,12 +1,12 @@ use crate::commands::UnevaluatedCallInfo; -use crate::context::AnchorLocation; -use crate::data::Value; +use crate::data::base::{UntaggedValue, Value}; use crate::errors::ShellError; use crate::parser::hir::SyntaxShape; use crate::parser::registry::Signature; use crate::prelude::*; use base64::encode; use mime::Mime; +use nu_source::AnchorLocation; use std::path::PathBuf; use std::str::FromStr; use surf::mime; @@ -55,7 +55,7 @@ impl PerItemCommand for Post { call_info: &CallInfo, registry: &CommandRegistry, raw_args: &RawCommandArgs, - _input: Tagged, + _input: Value, ) -> Result { run(call_info, registry, raw_args) } @@ -74,6 +74,7 @@ fn run( })? { file => file.clone(), }; + let path_tag = path.tag.clone(); let body = match call_info.args.nth(1).ok_or_else(|| { ShellError::labeled_error("No body specified", "for command", &name_tag) @@ -81,7 +82,6 @@ fn run( file => file.clone(), }; let path_str = path.as_string()?; - let path_span = path.tag(); let has_raw = call_info.args.has("raw"); let user = call_info.args.get("user").map(|x| x.as_string().unwrap()); let password = call_info @@ -95,7 +95,7 @@ fn run( let stream = async_stream! { let (file_extension, contents, contents_tag) = - post(&path_str, &body, user, password, &headers, path_span, ®istry, &raw_args).await.unwrap(); + post(&path_str, &body, user, password, &headers, path_tag.clone(), ®istry, &raw_args).await.unwrap(); let file_extension = if has_raw { None @@ -105,7 +105,7 @@ fn run( file_extension.or(path_str.split('.').last().map(String::from)) }; - let tagged_contents = contents.tagged(&contents_tag); + let tagged_contents = contents.into_value(&contents_tag); if let Some(extension) = file_extension { let command_name = format!("from-{}", extension); @@ -118,7 +118,8 @@ fn run( args: crate::parser::hir::Call { head: raw_args.call_info.args.head, positional: None, - named: None + named: None, + span: Span::unknown() }, source: raw_args.call_info.source, name_tag: raw_args.call_info.name_tag, @@ -128,13 +129,13 @@ fn run( let result_vec: Vec> = result.drain_vec().await; for res in result_vec { match res { - Ok(ReturnSuccess::Value(Tagged { item: Value::Table(list), ..})) => { + Ok(ReturnSuccess::Value(Value { value: UntaggedValue::Table(list), ..})) => { for l in list { yield Ok(ReturnSuccess::Value(l)); } } - Ok(ReturnSuccess::Value(Tagged { item, .. })) => { - yield Ok(ReturnSuccess::Value(Tagged { item, tag: contents_tag.clone() })); + Ok(ReturnSuccess::Value(Value { value, .. })) => { + yield Ok(ReturnSuccess::Value(Value { value, tag: contents_tag.clone() })); } x => yield x, } @@ -180,11 +181,11 @@ fn extract_header_value(call_info: &CallInfo, key: &str) -> Result s.clone(), - Some(Tagged { tag, .. }) => { + Some(Value { tag, .. }) => { return Err(ShellError::labeled_error( format!("{} not in expected format. Expected string.", key), "post error", @@ -207,14 +208,14 @@ fn extract_header_value(call_info: &CallInfo, key: &str) -> Result, + body: &Value, user: Option, password: Option, headers: &Vec, tag: Tag, registry: &CommandRegistry, raw_args: &RawCommandArgs, -) -> Result<(Option, Value, Tag), ShellError> { +) -> Result<(Option, UntaggedValue, Tag), ShellError> { let registry = registry.clone(); let raw_args = raw_args.clone(); if location.starts_with("http:") || location.starts_with("https:") { @@ -224,8 +225,8 @@ pub async fn post( _ => None, }; let response = match body { - Tagged { - item: Value::Primitive(Primitive::String(body_str)), + Value { + value: UntaggedValue::Primitive(Primitive::String(body_str)), .. } => { let mut s = surf::post(location).body_string(body_str.to_string()); @@ -241,8 +242,8 @@ pub async fn post( } s.await } - Tagged { - item: Value::Primitive(Primitive::Binary(b)), + Value { + value: UntaggedValue::Primitive(Primitive::Binary(b)), .. } => { let mut s = surf::post(location).body_bytes(b); @@ -251,7 +252,7 @@ pub async fn post( } s.await } - Tagged { item, tag } => { + Value { value, tag } => { if let Some(converter) = registry.get_command("to-json") { let new_args = RawCommandArgs { host: raw_args.host, @@ -262,13 +263,14 @@ pub async fn post( head: raw_args.call_info.args.head, positional: None, named: None, + span: Span::unknown(), }, source: raw_args.call_info.source, name_tag: raw_args.call_info.name_tag, }, }; let mut result = converter.run( - new_args.with_input(vec![item.clone().tagged(tag.clone())]), + new_args.with_input(vec![value.clone().into_value(tag.clone())]), ®istry, ); let result_vec: Vec> = @@ -276,8 +278,8 @@ pub async fn post( let mut result_string = String::new(); for res in result_vec { match res { - Ok(ReturnSuccess::Value(Tagged { - item: Value::Primitive(Primitive::String(s)), + Ok(ReturnSuccess::Value(Value { + value: UntaggedValue::Primitive(Primitive::String(s)), .. })) => { result_string.push_str(&s); @@ -314,7 +316,7 @@ pub async fn post( match (content_type.type_(), content_type.subtype()) { (mime::APPLICATION, mime::XML) => Ok(( Some("xml".to_string()), - Value::string(r.body_string().await.map_err(|_| { + UntaggedValue::string(r.body_string().await.map_err(|_| { ShellError::labeled_error( "Could not load text from remote url", "could not load", @@ -328,7 +330,7 @@ pub async fn post( )), (mime::APPLICATION, mime::JSON) => Ok(( Some("json".to_string()), - Value::string(r.body_string().await.map_err(|_| { + UntaggedValue::string(r.body_string().await.map_err(|_| { ShellError::labeled_error( "Could not load text from remote url", "could not load", @@ -350,7 +352,7 @@ pub async fn post( })?; Ok(( None, - Value::binary(buf), + UntaggedValue::binary(buf), Tag { anchor: Some(AnchorLocation::Url(location.to_string())), span: tag.span, @@ -367,7 +369,7 @@ pub async fn post( })?; Ok(( Some(image_ty.to_string()), - Value::binary(buf), + UntaggedValue::binary(buf), Tag { anchor: Some(AnchorLocation::Url(location.to_string())), span: tag.span, @@ -376,7 +378,7 @@ pub async fn post( } (mime::TEXT, mime::HTML) => Ok(( Some("html".to_string()), - Value::string(r.body_string().await.map_err(|_| { + UntaggedValue::string(r.body_string().await.map_err(|_| { ShellError::labeled_error( "Could not load text from remote url", "could not load", @@ -402,7 +404,7 @@ pub async fn post( Ok(( path_extension, - Value::string(r.body_string().await.map_err(|_| { + UntaggedValue::string(r.body_string().await.map_err(|_| { ShellError::labeled_error( "Could not load text from remote url", "could not load", @@ -417,7 +419,7 @@ pub async fn post( } (ty, sub_ty) => Ok(( None, - Value::string(format!( + UntaggedValue::string(format!( "Not yet supported MIME type: {} {}", ty, sub_ty )), @@ -430,7 +432,7 @@ pub async fn post( } None => Ok(( None, - Value::string(format!("No content type found")), + UntaggedValue::string(format!("No content type found")), Tag { anchor: Some(AnchorLocation::Url(location.to_string())), span: tag.span, diff --git a/src/commands/prepend.rs b/src/commands/prepend.rs index b6fa935b0b..de2cc499f1 100644 --- a/src/commands/prepend.rs +++ b/src/commands/prepend.rs @@ -5,7 +5,7 @@ use crate::prelude::*; #[derive(Deserialize)] struct PrependArgs { - row: Tagged, + row: Value, } pub struct Prepend; @@ -40,7 +40,7 @@ fn prepend( PrependArgs { row }: PrependArgs, RunnableContext { input, .. }: RunnableContext, ) -> Result { - let mut prepend: VecDeque> = VecDeque::new(); + let mut prepend: VecDeque = VecDeque::new(); prepend.push_back(row); Ok(OutputStream::from_input(prepend.chain(input.values))) diff --git a/src/commands/reduce_by.rs b/src/commands/reduce_by.rs index 53ddf7e15d..24ad5950e9 100644 --- a/src/commands/reduce_by.rs +++ b/src/commands/reduce_by.rs @@ -1,7 +1,9 @@ use crate::commands::WholeStreamCommand; use crate::parser::hir::SyntaxShape; use crate::prelude::*; +use nu_source::Tagged; use num_traits::cast::ToPrimitive; + pub struct ReduceBy; #[derive(Deserialize)] @@ -40,7 +42,7 @@ pub fn reduce_by( RunnableContext { input, name, .. }: RunnableContext, ) -> Result { let stream = async_stream! { - let values: Vec> = input.values.collect().await; + let values: Vec = input.values.collect().await; if values.is_empty() { yield Err(ShellError::labeled_error( @@ -66,10 +68,10 @@ pub fn reduce_by( Ok(stream.to_output_stream()) } -fn sum(data: Vec>) -> i32 { +fn sum(data: Vec) -> i32 { data.into_iter().fold(0, |acc, value| match value { - Tagged { - item: Value::Primitive(Primitive::Int(n)), + Value { + value: UntaggedValue::Primitive(Primitive::Int(n)), .. } => acc + n.to_i32().unwrap(), _ => acc, @@ -78,15 +80,15 @@ fn sum(data: Vec>) -> i32 { fn formula( acc_begin: i32, - calculator: Box>) -> i32 + 'static>, -) -> Box>) -> i32 + 'static> { + calculator: Box) -> i32 + 'static>, +) -> Box) -> i32 + 'static> { Box::new(move |acc, datax| -> i32 { let result = acc * acc_begin; result + calculator(datax) }) } -fn reducer_for(command: Reduce) -> Box>) -> i32 + 'static> { +fn reducer_for(command: Reduce) -> Box) -> i32 + 'static> { match command { Reduce::Sum | Reduce::Default => Box::new(formula(0, Box::new(sum))), } @@ -98,10 +100,10 @@ pub enum Reduce { } pub fn reduce( - values: &Tagged, + values: &Value, reducer: Option, tag: impl Into, -) -> Result, ShellError> { +) -> Result { let tag = tag.into(); let reduce_with = match reducer { @@ -109,9 +111,9 @@ pub fn reduce( Some(_) | None => reducer_for(Reduce::Default), }; - let results: Tagged = match values { - Tagged { - item: Value::Table(datasets), + let results: Value = match values { + Value { + value: UntaggedValue::Table(datasets), .. } => { let datasets: Vec<_> = datasets @@ -119,35 +121,35 @@ pub fn reduce( .map(|subsets| { let mut acc = 0; match subsets { - Tagged { - item: Value::Table(data), + Value { + value: UntaggedValue::Table(data), .. } => { let data = data .into_iter() .map(|d| { - if let Tagged { - item: Value::Table(x), + if let Value { + value: UntaggedValue::Table(x), .. } = d { acc = reduce_with(acc, x.clone()); - Value::number(acc).tagged(&tag) + UntaggedValue::number(acc).into_value(&tag) } else { - Value::number(0).tagged(&tag) + UntaggedValue::number(0).into_value(&tag) } }) .collect::>(); - Value::Table(data).tagged(&tag) + UntaggedValue::Table(data).into_value(&tag) } - _ => Value::Table(vec![]).tagged(&tag), + _ => UntaggedValue::Table(vec![]).into_value(&tag), } }) .collect(); - Value::Table(datasets).tagged(&tag) + UntaggedValue::Table(datasets).into_value(&tag) } - _ => Value::Table(vec![]).tagged(&tag), + _ => UntaggedValue::Table(vec![]).into_value(&tag), }; Ok(results) @@ -160,28 +162,28 @@ mod tests { use crate::commands::group_by::group; use crate::commands::reduce_by::{reduce, reducer_for, Reduce}; use crate::commands::t_sort_by::t_sort; - use crate::data::meta::*; use crate::prelude::*; use crate::Value; use indexmap::IndexMap; + use nu_source::*; - fn int(s: impl Into) -> Tagged { - Value::int(s).tagged_unknown() + fn int(s: impl Into) -> Value { + UntaggedValue::int(s).into_untagged_value() } - fn string(input: impl Into) -> Tagged { - Value::string(input.into()).tagged_unknown() + fn string(input: impl Into) -> Value { + UntaggedValue::string(input.into()).into_untagged_value() } - fn row(entries: IndexMap>) -> Tagged { - Value::row(entries).tagged_unknown() + fn row(entries: IndexMap) -> Value { + UntaggedValue::row(entries).into_untagged_value() } - fn table(list: &Vec>) -> Tagged { - Value::table(list).tagged_unknown() + fn table(list: &Vec) -> Value { + UntaggedValue::table(list).into_untagged_value() } - fn nu_releases_sorted_by_date() -> Tagged { + fn nu_releases_sorted_by_date() -> Value { let key = String::from("date"); t_sort( @@ -193,16 +195,16 @@ mod tests { .unwrap() } - fn nu_releases_evaluated_by_default_one() -> Tagged { + fn nu_releases_evaluated_by_default_one() -> Value { evaluate(&nu_releases_sorted_by_date(), None, Tag::unknown()).unwrap() } - fn nu_releases_grouped_by_date() -> Tagged { + fn nu_releases_grouped_by_date() -> Value { let key = String::from("date").tagged_unknown(); group(&key, nu_releases_commiters(), Tag::unknown()).unwrap() } - fn nu_releases_commiters() -> Vec> { + fn nu_releases_commiters() -> Vec { vec![ row( indexmap! {"name".into() => string("AR"), "country".into() => string("EC"), "date".into() => string("August 23-2019")}, diff --git a/src/commands/reject.rs b/src/commands/reject.rs index f02a72aa4c..8df4cfcd37 100644 --- a/src/commands/reject.rs +++ b/src/commands/reject.rs @@ -2,6 +2,7 @@ use crate::commands::WholeStreamCommand; use crate::data::base::reject_fields; use crate::errors::ShellError; use crate::prelude::*; +use nu_source::Tagged; #[derive(Deserialize)] pub struct RejectArgs { @@ -48,7 +49,7 @@ fn reject( let stream = input .values - .map(move |item| reject_fields(&item, &fields, item.tag()).into_tagged_value()); + .map(move |item| reject_fields(&item, &fields, &item.tag)); Ok(stream.from_input_stream()) } diff --git a/src/commands/rm.rs b/src/commands/rm.rs index 76222d2c28..c1f4104137 100644 --- a/src/commands/rm.rs +++ b/src/commands/rm.rs @@ -3,6 +3,7 @@ use crate::errors::ShellError; use crate::parser::hir::SyntaxShape; use crate::parser::registry::{CommandRegistry, Signature}; use crate::prelude::*; +use nu_source::Tagged; use std::path::PathBuf; pub struct Remove; @@ -38,7 +39,7 @@ impl PerItemCommand for Remove { call_info: &CallInfo, _registry: &CommandRegistry, raw_args: &RawCommandArgs, - _input: Tagged, + _input: Value, ) -> Result { call_info.process(&raw_args.shell_manager, rm)?.run() } diff --git a/src/commands/save.rs b/src/commands/save.rs index 4aaac0b14f..9c065dadd8 100644 --- a/src/commands/save.rs +++ b/src/commands/save.rs @@ -2,6 +2,7 @@ use crate::commands::{UnevaluatedCallInfo, WholeStreamCommand}; use crate::data::Value; use crate::errors::ShellError; use crate::prelude::*; +use nu_source::Tagged; use std::path::{Path, PathBuf}; pub struct Save; @@ -11,8 +12,8 @@ macro_rules! process_string { let mut result_string = String::new(); for res in $input { match res { - Tagged { - item: Value::Primitive(Primitive::String(s)), + Value { + value: UntaggedValue::Primitive(Primitive::String(s)), .. } => { result_string.push_str(&s); @@ -35,8 +36,8 @@ macro_rules! process_string_return_success { let mut result_string = String::new(); for res in $result_vec { match res { - Ok(ReturnSuccess::Value(Tagged { - item: Value::Primitive(Primitive::String(s)), + Ok(ReturnSuccess::Value(Value { + value: UntaggedValue::Primitive(Primitive::String(s)), .. })) => { result_string.push_str(&s); @@ -59,8 +60,8 @@ macro_rules! process_binary_return_success { let mut result_binary: Vec = Vec::new(); for res in $result_vec { match res { - Ok(ReturnSuccess::Value(Tagged { - item: Value::Primitive(Primitive::Binary(b)), + Ok(ReturnSuccess::Value(Value { + value: UntaggedValue::Primitive(Primitive::Binary(b)), .. })) => { for u in b.into_iter() { @@ -133,11 +134,11 @@ fn save( let name_tag = name.clone(); let stream = async_stream! { - let input: Vec> = input.values.collect().await; + let input: Vec = input.values.collect().await; if path.is_none() { // If there is no filename, check the metadata for the anchor filename if input.len() > 0 { - let anchor = input[0].anchor(); + let anchor = input[0].tag.anchor(); match anchor { Some(path) => match path { AnchorLocation::File(file) => { @@ -187,7 +188,8 @@ fn save( args: crate::parser::hir::Call { head: raw_args.call_info.args.head, positional: None, - named: None + named: None, + span: Span::unknown() }, source: raw_args.call_info.source, name_tag: raw_args.call_info.name_tag, @@ -224,7 +226,7 @@ fn save( Ok(OutputStream::new(stream)) } -fn string_from(input: &Vec>) -> String { +fn string_from(input: &Vec) -> String { let mut save_data = String::new(); if input.len() > 0 { diff --git a/src/commands/shells.rs b/src/commands/shells.rs index 6058a42032..aac5f8e7d7 100644 --- a/src/commands/shells.rs +++ b/src/commands/shells.rs @@ -36,14 +36,14 @@ fn shells(args: CommandArgs, _registry: &CommandRegistry) -> Result Result { let input = args.input; let tag = args.call_info.name_tag; + let name_span = tag.span; + Ok(input .values - .map(move |v| match v.item { - Value::Primitive(Primitive::String(ref s)) => ReturnSuccess::value(count(s, v.tag())), + .map(move |v| match v.value { + UntaggedValue::Primitive(Primitive::String(ref s)) => { + ReturnSuccess::value(count(s, &v.tag)) + } _ => Err(ShellError::labeled_error_with_secondary( "Expected a string from pipeline", "requires string input", - &tag, + name_span, "value originates from here", - v.tag(), + v.tag.span, )), }) .to_output_stream()) } -fn count(contents: &str, tag: impl Into) -> Tagged { +fn count(contents: &str, tag: impl Into) -> Value { let mut lines: i64 = 0; let mut words: i64 = 0; let mut chars: i64 = 0; @@ -72,11 +76,11 @@ fn count(contents: &str, tag: impl Into) -> Tagged { let mut dict = TaggedDictBuilder::new(tag); //TODO: add back in name when we have it in the tag - //dict.insert("name", Value::string(name)); - dict.insert("lines", Value::int(lines)); - dict.insert("words", Value::int(words)); - dict.insert("chars", Value::int(chars)); - dict.insert("max length", Value::int(bytes)); + //dict.insert("name", UntaggedValue::string(name)); + dict.insert_untagged("lines", UntaggedValue::int(lines)); + dict.insert_untagged("words", UntaggedValue::int(words)); + dict.insert_untagged("chars", UntaggedValue::int(chars)); + dict.insert_untagged("max length", UntaggedValue::int(bytes)); - dict.into_tagged_value() + dict.into_value() } diff --git a/src/commands/skip_while.rs b/src/commands/skip_while.rs index e8bec7dac2..9e1cfe14c5 100644 --- a/src/commands/skip_while.rs +++ b/src/commands/skip_while.rs @@ -1,4 +1,5 @@ use crate::commands::WholeStreamCommand; +use crate::data::base::Block; use crate::errors::ShellError; use crate::prelude::*; use log::trace; @@ -7,7 +8,7 @@ pub struct SkipWhile; #[derive(Deserialize)] pub struct SkipWhileArgs { - condition: value::Block, + condition: Block, } impl WholeStreamCommand for SkipWhile { diff --git a/src/commands/sort_by.rs b/src/commands/sort_by.rs index da872b9b31..8d6378a8c4 100644 --- a/src/commands/sort_by.rs +++ b/src/commands/sort_by.rs @@ -1,6 +1,7 @@ use crate::commands::WholeStreamCommand; use crate::errors::ShellError; use crate::prelude::*; +use nu_source::Tagged; pub struct SortBy; @@ -38,10 +39,10 @@ fn sort_by( Ok(OutputStream::new(async_stream! { let mut vec = context.input.drain_vec().await; - let calc_key = |item: &Tagged| { + let calc_key = |item: &crate::data::base::Value| { rest.iter() .map(|f| item.get_data_by_key(f.borrow_spanned()).map(|i| i.clone())) - .collect::>>>() + .collect::>>() }; vec.sort_by_cached_key(calc_key); diff --git a/src/commands/split_by.rs b/src/commands/split_by.rs index 3744d7c788..7821d3cfcb 100644 --- a/src/commands/split_by.rs +++ b/src/commands/split_by.rs @@ -1,7 +1,9 @@ use crate::commands::WholeStreamCommand; +use crate::data::base::UntaggedValue; use crate::data::TaggedDictBuilder; use crate::errors::ShellError; use crate::prelude::*; +use nu_source::Tagged; pub struct SplitBy; @@ -41,7 +43,7 @@ pub fn split_by( RunnableContext { input, name, .. }: RunnableContext, ) -> Result { let stream = async_stream! { - let values: Vec> = input.values.collect().await; + let values: Vec = input.values.collect().await; if values.len() > 1 || values.is_empty() { yield Err(ShellError::labeled_error( @@ -62,22 +64,22 @@ pub fn split_by( pub fn split( column_name: &Tagged, - value: &Tagged, + value: &Value, tag: impl Into, -) -> Result, ShellError> { +) -> Result { let origin_tag = tag.into(); let mut splits = indexmap::IndexMap::new(); match value { - Tagged { - item: Value::Row(group_sets), + Value { + value: UntaggedValue::Row(group_sets), .. } => { for (group_key, group_value) in group_sets.entries.iter() { match *group_value { - Tagged { - item: Value::Table(ref dataset), + Value { + value: UntaggedValue::Table(ref dataset), .. } => { let group = crate::commands::group_by::group( @@ -87,14 +89,14 @@ pub fn split( )?; match group { - Tagged { - item: Value::Row(o), + Value { + value: UntaggedValue::Row(o), .. } => { for (split_label, subset) in o.entries.into_iter() { match subset { - Tagged { - item: Value::Table(subset), + Value { + value: UntaggedValue::Table(subset), tag, } => { let s = splits @@ -102,7 +104,7 @@ pub fn split( .or_insert(indexmap::IndexMap::new()); s.insert( group_key.clone(), - Value::table(&subset).tagged(tag), + UntaggedValue::table(&subset).into_value(tag), ); } other => { @@ -142,38 +144,38 @@ pub fn split( let mut out = TaggedDictBuilder::new(&origin_tag); for (k, v) in splits.into_iter() { - out.insert(k, Value::row(v)); + out.insert_untagged(k, UntaggedValue::row(v)); } - Ok(out.into_tagged_value()) + Ok(out.into_value()) } #[cfg(test)] mod tests { use crate::commands::group_by::group; use crate::commands::split_by::split; - use crate::data::meta::*; - use crate::Value; + use crate::data::base::{UntaggedValue, Value}; use indexmap::IndexMap; + use nu_source::*; - fn string(input: impl Into) -> Tagged { - Value::string(input.into()).tagged_unknown() + fn string(input: impl Into) -> Value { + UntaggedValue::string(input.into()).into_untagged_value() } - fn row(entries: IndexMap>) -> Tagged { - Value::row(entries).tagged_unknown() + fn row(entries: IndexMap) -> Value { + UntaggedValue::row(entries).into_untagged_value() } - fn table(list: &Vec>) -> Tagged { - Value::table(list).tagged_unknown() + fn table(list: &Vec) -> Value { + UntaggedValue::table(list).into_untagged_value() } - fn nu_releases_grouped_by_date() -> Tagged { + fn nu_releases_grouped_by_date() -> Value { let key = String::from("date").tagged_unknown(); group(&key, nu_releases_commiters(), Tag::unknown()).unwrap() } - fn nu_releases_commiters() -> Vec> { + fn nu_releases_commiters() -> Vec { vec![ row( indexmap! {"name".into() => string("AR"), "country".into() => string("EC"), "date".into() => string("August 23-2019")}, @@ -211,7 +213,7 @@ mod tests { assert_eq!( split(&for_key, &nu_releases_grouped_by_date(), Tag::unknown()).unwrap(), - Value::row(indexmap! { + UntaggedValue::row(indexmap! { "EC".into() => row(indexmap! { "August 23-2019".into() => table(&vec![ row(indexmap!{"name".into() => string("AR"), "country".into() => string("EC"), "date".into() => string("August 23-2019")}) @@ -245,7 +247,7 @@ mod tests { row(indexmap!{"name".into() => string("YK"), "country".into() => string("US"), "date".into() => string("October 10-2019")}) ]) }) - }).tagged_unknown() + }).into_untagged_value() ); } @@ -258,7 +260,7 @@ mod tests { row(indexmap!{"name".into() => string("AR"), "country".into() => string("EC"), "date".into() => string("August 23-2019")}) ]), "Sept 24-2019".into() => table(&vec![ - row(indexmap!{"name".into() => Value::string("JT").tagged(Tag::from(Span::new(5,10))), "date".into() => string("Sept 24-2019")}) + row(indexmap!{"name".into() => UntaggedValue::string("JT").into_value(Tag::from(Span::new(5,10))), "date".into() => string("Sept 24-2019")}) ]), "October 10-2019".into() => table(&vec![ row(indexmap!{"name".into() => string("YK"), "country".into() => string("US"), "date".into() => string("October 10-2019")}) diff --git a/src/commands/split_column.rs b/src/commands/split_column.rs index fd872d452d..874c6ebb66 100644 --- a/src/commands/split_column.rs +++ b/src/commands/split_column.rs @@ -1,8 +1,9 @@ use crate::commands::WholeStreamCommand; -use crate::data::{Primitive, TaggedDictBuilder, Value}; +use crate::data::{Primitive, TaggedDictBuilder}; use crate::errors::ShellError; use crate::prelude::*; use log::trace; +use nu_source::Tagged; #[derive(Deserialize)] struct SplitColumnArgs { @@ -51,10 +52,12 @@ fn split_column( }: SplitColumnArgs, RunnableContext { input, name, .. }: RunnableContext, ) -> Result { + let name_span = name.span; + Ok(input .values - .map(move |v| match v.item { - Value::Primitive(Primitive::String(ref s)) => { + .map(move |v| match v.value { + UntaggedValue::Primitive(Primitive::String(ref s)) => { let splitter = separator.replace("\\n", "\n"); trace!("splitting with {:?}", splitter); @@ -75,32 +78,38 @@ fn split_column( gen_columns.push(format!("Column{}", i + 1)); } - let mut dict = TaggedDictBuilder::new(v.tag()); + let mut dict = TaggedDictBuilder::new(&v.tag); for (&k, v) in split_result.iter().zip(gen_columns.iter()) { - dict.insert(v.clone(), Primitive::String(k.into())); + dict.insert_untagged(v.clone(), Primitive::String(k.into())); } - ReturnSuccess::value(dict.into_tagged_value()) + ReturnSuccess::value(dict.into_value()) } else if split_result.len() == positional.len() { - let mut dict = TaggedDictBuilder::new(v.tag()); + let mut dict = TaggedDictBuilder::new(&v.tag); for (&k, v) in split_result.iter().zip(positional.iter()) { - dict.insert(v, Value::Primitive(Primitive::String(k.into()))); + dict.insert_untagged( + v, + UntaggedValue::Primitive(Primitive::String(k.into())), + ); } - ReturnSuccess::value(dict.into_tagged_value()) + ReturnSuccess::value(dict.into_value()) } else { - let mut dict = TaggedDictBuilder::new(v.tag()); + let mut dict = TaggedDictBuilder::new(&v.tag); for (&k, v) in split_result.iter().zip(positional.iter()) { - dict.insert(v, Value::Primitive(Primitive::String(k.into()))); + dict.insert_untagged( + v, + UntaggedValue::Primitive(Primitive::String(k.into())), + ); } - ReturnSuccess::value(dict.into_tagged_value()) + ReturnSuccess::value(dict.into_value()) } } _ => Err(ShellError::labeled_error_with_secondary( "Expected a string from pipeline", "requires string input", - &name, + name_span, "value originates from here", - v.tag(), + v.tag.span, )), }) .to_output_stream()) diff --git a/src/commands/split_row.rs b/src/commands/split_row.rs index 6c848c325a..209e25c578 100644 --- a/src/commands/split_row.rs +++ b/src/commands/split_row.rs @@ -1,8 +1,9 @@ use crate::commands::WholeStreamCommand; -use crate::data::{Primitive, Value}; +use crate::data::Primitive; use crate::errors::ShellError; use crate::prelude::*; use log::trace; +use nu_source::Tagged; #[derive(Deserialize)] struct SplitRowArgs { @@ -43,8 +44,8 @@ fn split_row( ) -> Result { let stream = input .values - .map(move |v| match v.item { - Value::Primitive(Primitive::String(ref s)) => { + .map(move |v| match v.value { + UntaggedValue::Primitive(Primitive::String(ref s)) => { let splitter = separator.item.replace("\\n", "\n"); trace!("splitting with {:?}", splitter); let split_result: Vec<_> = s.split(&splitter).filter(|s| s.trim() != "").collect(); @@ -54,7 +55,7 @@ fn split_row( let mut result = VecDeque::new(); for s in split_result { result.push_back(ReturnSuccess::value( - Value::Primitive(Primitive::String(s.into())).tagged(v.tag()), + UntaggedValue::Primitive(Primitive::String(s.into())).into_value(&v.tag), )); } result @@ -64,9 +65,9 @@ fn split_row( result.push_back(Err(ShellError::labeled_error_with_secondary( "Expected a string from pipeline", "requires string input", - &name, + name.span, "value originates from here", - v.tag(), + v.tag.span, ))); result } diff --git a/src/commands/t_sort_by.rs b/src/commands/t_sort_by.rs index 3cfcae71fc..e0e639108a 100644 --- a/src/commands/t_sort_by.rs +++ b/src/commands/t_sort_by.rs @@ -3,6 +3,7 @@ use crate::data::{TaggedDictBuilder, TaggedListBuilder}; use crate::errors::ShellError; use crate::prelude::*; use chrono::{DateTime, NaiveDate, Utc}; +use nu_source::Tagged; pub struct TSortBy; @@ -57,7 +58,7 @@ fn t_sort_by( RunnableContext { input, name, .. }: RunnableContext, ) -> Result { Ok(OutputStream::new(async_stream! { - let values: Vec> = input.values.collect().await; + let values: Vec = input.values.collect().await; let column_grouped_by_name = if let Some(grouped_by) = group_by { Some(grouped_by.item().clone()) @@ -67,7 +68,7 @@ fn t_sort_by( if show_columns { for label in columns_sorted(column_grouped_by_name, &values[0], &name).into_iter() { - yield ReturnSuccess::value(Value::string(label.item).tagged(label.tag)); + yield ReturnSuccess::value(UntaggedValue::string(label.item).into_value(label.tag)); } } else { match t_sort(column_grouped_by_name, None, &values[0], name) { @@ -80,41 +81,41 @@ fn t_sort_by( pub fn columns_sorted( _group_by_name: Option, - value: &Tagged, + value: &Value, tag: impl Into, ) -> Vec> { let origin_tag = tag.into(); match value { - Tagged { - item: Value::Row(rows), + Value { + value: UntaggedValue::Row(rows), .. } => { - let mut keys: Vec> = - rows.entries - .keys() - .map(|s| s.as_ref()) - .map(|k: &str| { - let date = NaiveDate::parse_from_str(k, "%B %d-%Y"); + let mut keys: Vec = rows + .entries + .keys() + .map(|s| s.as_ref()) + .map(|k: &str| { + let date = NaiveDate::parse_from_str(k, "%B %d-%Y"); - let date = match date { - Ok(parsed) => Value::Primitive(Primitive::Date( - DateTime::::from_utc(parsed.and_hms(12, 34, 56), Utc), - )), - Err(_) => Value::string(k), - }; + let date = match date { + Ok(parsed) => UntaggedValue::Primitive(Primitive::Date( + DateTime::::from_utc(parsed.and_hms(12, 34, 56), Utc), + )), + Err(_) => UntaggedValue::string(k), + }; - date.tagged_unknown() - }) - .collect(); + date.into_untagged_value() + }) + .collect(); keys.sort(); let keys: Vec = keys .into_iter() .map(|k| match k { - Tagged { - item: Value::Primitive(Primitive::Date(d)), + Value { + value: UntaggedValue::Primitive(Primitive::Date(d)), .. } => format!("{}", d.format("%B %d-%Y")), _ => k.as_string().unwrap(), @@ -130,9 +131,9 @@ pub fn columns_sorted( pub fn t_sort( group_by_name: Option, split_by_name: Option, - value: &Tagged, + value: &Value, tag: impl Into, -) -> Result, ShellError> { +) -> Result { let origin_tag = tag.into(); match group_by_name { @@ -143,12 +144,12 @@ pub fn t_sort( match split_by_name { None => { let mut dataset = TaggedDictBuilder::new(&origin_tag); - dataset.insert_tagged("default", value.clone()); - let dataset = dataset.into_tagged_value(); + dataset.insert_value("default", value.clone()); + let dataset = dataset.into_value(); let split_labels: Vec> = match &dataset { - Tagged { - item: Value::Row(rows), + Value { + value: UntaggedValue::Row(rows), .. } => { let mut keys: Vec> = rows @@ -164,7 +165,7 @@ pub fn t_sort( _ => vec![], }; - let results: Vec>> = split_labels + let results: Vec> = split_labels .iter() .map(|split| { let groups = dataset.get_data_by_key(split.borrow_spanned()); @@ -173,14 +174,14 @@ pub fn t_sort( .clone() .into_iter() .map(|label| match &groups { - Some(Tagged { - item: Value::Row(dict), + Some(Value { + value: UntaggedValue::Row(dict), .. }) => dict .get_data_by_key(label.borrow_spanned()) .unwrap() .clone(), - _ => Value::Table(vec![]).tagged(&origin_tag), + _ => UntaggedValue::Table(vec![]).into_value(&origin_tag), }) .collect() }) @@ -189,15 +190,15 @@ pub fn t_sort( let mut outer = TaggedListBuilder::new(&origin_tag); for i in results { - outer.insert_tagged(Value::Table(i).tagged(&origin_tag)); + outer.push_value(UntaggedValue::Table(i).into_value(&origin_tag)); } - return Ok(Value::Table(outer.list).tagged(&origin_tag)); + return Ok(UntaggedValue::Table(outer.list).into_value(&origin_tag)); } - Some(_) => return Ok(Value::nothing().tagged(&origin_tag)), + Some(_) => return Ok(UntaggedValue::nothing().into_value(&origin_tag)), } } - None => return Ok(Value::nothing().tagged(&origin_tag)), + None => return Ok(UntaggedValue::nothing().into_value(&origin_tag)), } } #[cfg(test)] @@ -205,28 +206,28 @@ mod tests { use crate::commands::group_by::group; use crate::commands::t_sort_by::{columns_sorted, t_sort}; - use crate::data::meta::*; - use crate::Value; + use crate::data::base::{UntaggedValue, Value}; use indexmap::IndexMap; + use nu_source::*; - fn string(input: impl Into) -> Tagged { - Value::string(input.into()).tagged_unknown() + fn string(input: impl Into) -> Value { + UntaggedValue::string(input.into()).into_untagged_value() } - fn row(entries: IndexMap>) -> Tagged { - Value::row(entries).tagged_unknown() + fn row(entries: IndexMap) -> Value { + UntaggedValue::row(entries).into_untagged_value() } - fn table(list: &Vec>) -> Tagged { - Value::table(list).tagged_unknown() + fn table(list: &Vec) -> Value { + UntaggedValue::table(list).into_untagged_value() } - fn nu_releases_grouped_by_date() -> Tagged { + fn nu_releases_grouped_by_date() -> Value { let key = String::from("date").tagged_unknown(); group(&key, nu_releases_commiters(), Tag::unknown()).unwrap() } - fn nu_releases_commiters() -> Vec> { + fn nu_releases_commiters() -> Vec { vec![ row( indexmap! {"name".into() => string("AR"), "country".into() => string("EC"), "date".into() => string("August 23-2019")}, diff --git a/src/commands/table.rs b/src/commands/table.rs index f8cdcd13c7..71ee30c824 100644 --- a/src/commands/table.rs +++ b/src/commands/table.rs @@ -37,7 +37,7 @@ fn table(args: CommandArgs, registry: &CommandRegistry) -> Result { + Some(Value { value: UntaggedValue::Primitive(Primitive::Int(i)), .. }) => { i.to_usize().unwrap() } _ => { @@ -45,7 +45,7 @@ fn table(args: CommandArgs, registry: &CommandRegistry) -> Result> = args.input.into_vec().await; + let input: Vec = args.input.into_vec().await; if input.len() > 0 { let mut host = host.lock().unwrap(); let view = TableView::from_list(&input, start_number); @@ -56,7 +56,7 @@ fn table(args: CommandArgs, registry: &CommandRegistry) -> Result Result { - tags.insert("anchor", Value::string(source)); + tags.insert_untagged("anchor", UntaggedValue::string(source)); } Some(AnchorLocation::Url(source)) => { - tags.insert("anchor", Value::string(source)); + tags.insert_untagged("anchor", UntaggedValue::string(source)); } _ => {} } } - tags.into_tagged_value() + tags.into_value() }) .to_output_stream()) } diff --git a/src/commands/to_bson.rs b/src/commands/to_bson.rs index c4685be344..9156532b7e 100644 --- a/src/commands/to_bson.rs +++ b/src/commands/to_bson.rs @@ -1,7 +1,7 @@ use crate::commands::WholeStreamCommand; use crate::data::{Dictionary, Primitive, Value}; use crate::prelude::*; -use crate::RawPathMember; +use crate::UnspannedPathMember; use bson::{encode_document, oid::ObjectId, spec::BinarySubtype, Bson, Document}; use std::convert::TryInto; @@ -33,46 +33,48 @@ impl WholeStreamCommand for ToBSON { } } -pub fn value_to_bson_value(v: &Tagged) -> Result { - Ok(match &v.item { - Value::Primitive(Primitive::Boolean(b)) => Bson::Boolean(*b), +pub fn value_to_bson_value(v: &Value) -> Result { + Ok(match &v.value { + UntaggedValue::Primitive(Primitive::Boolean(b)) => Bson::Boolean(*b), // FIXME: What about really big decimals? - Value::Primitive(Primitive::Bytes(decimal)) => Bson::FloatingPoint( + UntaggedValue::Primitive(Primitive::Bytes(decimal)) => Bson::FloatingPoint( (decimal) .to_f64() .expect("Unimplemented BUG: What about big decimals?"), ), - Value::Primitive(Primitive::Duration(secs)) => Bson::I64(*secs as i64), - Value::Primitive(Primitive::Date(d)) => Bson::UtcDatetime(*d), - Value::Primitive(Primitive::EndOfStream) => Bson::Null, - Value::Primitive(Primitive::BeginningOfStream) => Bson::Null, - Value::Primitive(Primitive::Decimal(d)) => Bson::FloatingPoint(d.to_f64().unwrap()), - Value::Primitive(Primitive::Int(i)) => { + UntaggedValue::Primitive(Primitive::Duration(secs)) => Bson::I64(*secs as i64), + UntaggedValue::Primitive(Primitive::Date(d)) => Bson::UtcDatetime(*d), + UntaggedValue::Primitive(Primitive::EndOfStream) => Bson::Null, + UntaggedValue::Primitive(Primitive::BeginningOfStream) => Bson::Null, + UntaggedValue::Primitive(Primitive::Decimal(d)) => Bson::FloatingPoint(d.to_f64().unwrap()), + UntaggedValue::Primitive(Primitive::Int(i)) => { Bson::I64(i.tagged(&v.tag).coerce_into("converting to BSON")?) } - Value::Primitive(Primitive::Nothing) => Bson::Null, - Value::Primitive(Primitive::String(s)) => Bson::String(s.clone()), - Value::Primitive(Primitive::ColumnPath(path)) => Bson::Array( + UntaggedValue::Primitive(Primitive::Nothing) => Bson::Null, + UntaggedValue::Primitive(Primitive::String(s)) => Bson::String(s.clone()), + UntaggedValue::Primitive(Primitive::ColumnPath(path)) => Bson::Array( path.iter() - .map(|x| match &x.item { - RawPathMember::String(string) => Ok(Bson::String(string.clone())), - RawPathMember::Int(int) => Ok(Bson::I64( + .map(|x| match &x.unspanned { + UnspannedPathMember::String(string) => Ok(Bson::String(string.clone())), + UnspannedPathMember::Int(int) => Ok(Bson::I64( int.tagged(&v.tag).coerce_into("converting to BSON")?, )), }) .collect::, ShellError>>()?, ), - Value::Primitive(Primitive::Pattern(p)) => Bson::String(p.clone()), - Value::Primitive(Primitive::Path(s)) => Bson::String(s.display().to_string()), - Value::Table(l) => Bson::Array( + UntaggedValue::Primitive(Primitive::Pattern(p)) => Bson::String(p.clone()), + UntaggedValue::Primitive(Primitive::Path(s)) => Bson::String(s.display().to_string()), + UntaggedValue::Table(l) => Bson::Array( l.iter() .map(|x| value_to_bson_value(x)) .collect::>()?, ), - Value::Block(_) => Bson::Null, - Value::Error(e) => return Err(e.clone()), - Value::Primitive(Primitive::Binary(b)) => Bson::Binary(BinarySubtype::Generic, b.clone()), - Value::Row(o) => object_value_to_bson(o)?, + UntaggedValue::Block(_) => Bson::Null, + UntaggedValue::Error(e) => return Err(e.clone()), + UntaggedValue::Primitive(Primitive::Binary(b)) => { + Bson::Binary(BinarySubtype::Generic, b.clone()) + } + UntaggedValue::Row(o) => object_value_to_bson(o)?, }) } @@ -171,9 +173,9 @@ fn object_value_to_bson(o: &Dictionary) -> Result { } } -fn get_binary_subtype<'a>(tagged_value: &'a Tagged) -> Result { - match tagged_value.item() { - Value::Primitive(Primitive::String(s)) => Ok(match s.as_ref() { +fn get_binary_subtype<'a>(tagged_value: &'a Value) -> Result { + match &tagged_value.value { + UntaggedValue::Primitive(Primitive::String(s)) => Ok(match s.as_ref() { "generic" => BinarySubtype::Generic, "function" => BinarySubtype::Function, "binary_old" => BinarySubtype::BinaryOld, @@ -182,7 +184,7 @@ fn get_binary_subtype<'a>(tagged_value: &'a Tagged) -> Result BinarySubtype::Md5, _ => unreachable!(), }), - Value::Primitive(Primitive::Int(i)) => Ok(BinarySubtype::UserDefined( + UntaggedValue::Primitive(Primitive::Int(i)) => Ok(BinarySubtype::UserDefined( i.tagged(&tagged_value.tag) .coerce_into("converting to BSON binary subtype")?, )), @@ -246,12 +248,14 @@ fn bson_value_to_bytes(bson: Bson, tag: Tag) -> Result, ShellError> { fn to_bson(args: CommandArgs, registry: &CommandRegistry) -> Result { let args = args.evaluate_once(registry)?; let name_tag = args.name_tag(); + let name_span = name_tag.span; + let stream = async_stream! { - let input: Vec> = args.input.values.collect().await; + let input: Vec = args.input.values.collect().await; let to_process_input = if input.len() > 1 { let tag = input[0].tag.clone(); - vec![Tagged { item: Value::Table(input), tag } ] + vec![Value { value: UntaggedValue::Table(input), tag } ] } else if input.len() == 1 { input } else { @@ -261,16 +265,18 @@ fn to_bson(args: CommandArgs, registry: &CommandRegistry) -> Result { + let value_span = value.tag.span; + match bson_value_to_bytes(bson_value, name_tag.clone()) { Ok(x) => yield ReturnSuccess::value( - Value::binary(x).tagged(&name_tag), + UntaggedValue::binary(x).into_value(&name_tag), ), _ => yield Err(ShellError::labeled_error_with_secondary( "Expected a table with BSON-compatible structure.tag() from pipeline", "requires BSON-compatible input", - &name_tag, + name_span, "originates from here".to_string(), - value.tag(), + value_span, )), } } diff --git a/src/commands/to_csv.rs b/src/commands/to_csv.rs index e013c6c8e3..03643cc691 100644 --- a/src/commands/to_csv.rs +++ b/src/commands/to_csv.rs @@ -8,7 +8,7 @@ pub struct ToCSV; #[derive(Deserialize)] pub struct ToCSVArgs { headerless: bool, - separator: Option>, + separator: Option, } impl WholeStreamCommand for ToCSV { @@ -44,8 +44,8 @@ fn to_csv( runnable_context: RunnableContext, ) -> Result { let sep = match separator { - Some(Tagged { - item: Value::Primitive(Primitive::String(s)), + Some(Value { + value: UntaggedValue::Primitive(Primitive::String(s)), tag, .. }) => { diff --git a/src/commands/to_delimited_data.rs b/src/commands/to_delimited_data.rs index e5924b12d1..8494ce5377 100644 --- a/src/commands/to_delimited_data.rs +++ b/src/commands/to_delimited_data.rs @@ -2,15 +2,16 @@ use crate::data::{Primitive, Value}; use crate::prelude::*; use csv::WriterBuilder; use indexmap::{indexset, IndexSet}; +use nu_source::Spanned; fn from_value_to_delimited_string( - tagged_value: &Tagged, + tagged_value: &Value, separator: char, ) -> Result { - let v = &tagged_value.item; + let v = &tagged_value.value; match v { - Value::Row(o) => { + UntaggedValue::Row(o) => { let mut wtr = WriterBuilder::new() .delimiter(separator as u8) .from_writer(vec![]); @@ -41,7 +42,7 @@ fn from_value_to_delimited_string( ) })?); } - Value::Table(list) => { + UntaggedValue::Table(list) => { let mut wtr = WriterBuilder::new() .delimiter(separator as u8) .from_writer(vec![]); @@ -54,7 +55,7 @@ fn from_value_to_delimited_string( for l in list { let mut row = vec![]; for desc in &merged_descriptors { - match l.item.get_data_by_key(desc.borrow_spanned()) { + match l.get_data_by_key(desc.borrow_spanned()) { Some(s) => { row.push(to_string_tagged_value(&s)?); } @@ -85,40 +86,56 @@ fn from_value_to_delimited_string( } } -// NOTE: could this be useful more widely and implemented on Tagged ? -pub fn clone_tagged_value(v: &Tagged) -> Tagged { - match &v.item { - Value::Primitive(Primitive::String(s)) => Value::Primitive(Primitive::String(s.clone())), - Value::Primitive(Primitive::Nothing) => Value::Primitive(Primitive::Nothing), - Value::Primitive(Primitive::Boolean(b)) => Value::Primitive(Primitive::Boolean(b.clone())), - Value::Primitive(Primitive::Decimal(f)) => Value::Primitive(Primitive::Decimal(f.clone())), - Value::Primitive(Primitive::Int(i)) => Value::Primitive(Primitive::Int(i.clone())), - Value::Primitive(Primitive::Path(x)) => Value::Primitive(Primitive::Path(x.clone())), - Value::Primitive(Primitive::Bytes(b)) => Value::Primitive(Primitive::Bytes(b.clone())), - Value::Primitive(Primitive::Date(d)) => Value::Primitive(Primitive::Date(d.clone())), - Value::Row(o) => Value::Row(o.clone()), - Value::Table(l) => Value::Table(l.clone()), - Value::Block(_) => Value::Primitive(Primitive::Nothing), - _ => Value::Primitive(Primitive::Nothing), +// NOTE: could this be useful more widely and implemented on Value ? +pub fn clone_tagged_value(v: &Value) -> Value { + match &v.value { + UntaggedValue::Primitive(Primitive::String(s)) => { + UntaggedValue::Primitive(Primitive::String(s.clone())) + } + UntaggedValue::Primitive(Primitive::Nothing) => { + UntaggedValue::Primitive(Primitive::Nothing) + } + UntaggedValue::Primitive(Primitive::Boolean(b)) => { + UntaggedValue::Primitive(Primitive::Boolean(b.clone())) + } + UntaggedValue::Primitive(Primitive::Decimal(f)) => { + UntaggedValue::Primitive(Primitive::Decimal(f.clone())) + } + UntaggedValue::Primitive(Primitive::Int(i)) => { + UntaggedValue::Primitive(Primitive::Int(i.clone())) + } + UntaggedValue::Primitive(Primitive::Path(x)) => { + UntaggedValue::Primitive(Primitive::Path(x.clone())) + } + UntaggedValue::Primitive(Primitive::Bytes(b)) => { + UntaggedValue::Primitive(Primitive::Bytes(b.clone())) + } + UntaggedValue::Primitive(Primitive::Date(d)) => { + UntaggedValue::Primitive(Primitive::Date(d.clone())) + } + UntaggedValue::Row(o) => UntaggedValue::Row(o.clone()), + UntaggedValue::Table(l) => UntaggedValue::Table(l.clone()), + UntaggedValue::Block(_) => UntaggedValue::Primitive(Primitive::Nothing), + _ => UntaggedValue::Primitive(Primitive::Nothing), } - .tagged(v.tag.clone()) + .into_value(v.tag.clone()) } -// NOTE: could this be useful more widely and implemented on Tagged ? -fn to_string_tagged_value(v: &Tagged) -> Result { - match &v.item { - Value::Primitive(Primitive::Date(d)) => Ok(d.to_string()), - Value::Primitive(Primitive::Bytes(b)) => { +// NOTE: could this be useful more widely and implemented on Value ? +fn to_string_tagged_value(v: &Value) -> Result { + match &v.value { + UntaggedValue::Primitive(Primitive::Date(d)) => Ok(d.to_string()), + UntaggedValue::Primitive(Primitive::Bytes(b)) => { let tmp = format!("{}", b); Ok(tmp) } - Value::Primitive(Primitive::Boolean(_)) => Ok(v.as_string()?), - Value::Primitive(Primitive::Decimal(_)) => Ok(v.as_string()?), - Value::Primitive(Primitive::Int(_)) => Ok(v.as_string()?), - Value::Primitive(Primitive::Path(_)) => Ok(v.as_string()?), - Value::Table(_) => return Ok(String::from("[Table]")), - Value::Row(_) => return Ok(String::from("[Row]")), - Value::Primitive(Primitive::String(s)) => return Ok(s.to_string()), + UntaggedValue::Primitive(Primitive::Boolean(_)) => Ok(v.as_string()?), + UntaggedValue::Primitive(Primitive::Decimal(_)) => Ok(v.as_string()?), + UntaggedValue::Primitive(Primitive::Int(_)) => Ok(v.as_string()?), + UntaggedValue::Primitive(Primitive::Path(_)) => Ok(v.as_string()?), + UntaggedValue::Table(_) => return Ok(String::from("[Table]")), + UntaggedValue::Row(_) => return Ok(String::from("[Row]")), + UntaggedValue::Primitive(Primitive::String(s)) => return Ok(s.to_string()), _ => { return Err(ShellError::labeled_error( "Unexpected value", @@ -129,7 +146,7 @@ fn to_string_tagged_value(v: &Tagged) -> Result { } } -fn merge_descriptors(values: &[Tagged]) -> Vec> { +fn merge_descriptors(values: &[Value]) -> Vec> { let mut ret: Vec> = vec![]; let mut seen: IndexSet = indexset! {}; for value in values { @@ -150,13 +167,14 @@ pub fn to_delimited_data( RunnableContext { input, name, .. }: RunnableContext, ) -> Result { let name_tag = name; + let name_span = name_tag.span; let stream = async_stream! { - let input: Vec> = input.values.collect().await; + let input: Vec = input.values.collect().await; let to_process_input = if input.len() > 1 { let tag = input[0].tag.clone(); - vec![Tagged { item: Value::Table(input), tag } ] + vec![Value { value: UntaggedValue::Table(input), tag } ] } else if input.len() == 1 { input } else { @@ -171,7 +189,7 @@ pub fn to_delimited_data( } else { x }; - yield ReturnSuccess::value(Value::Primitive(Primitive::String(converted)).tagged(&name_tag)) + yield ReturnSuccess::value(UntaggedValue::Primitive(Primitive::String(converted)).into_value(&name_tag)) } _ => { let expected = format!("Expected a table with {}-compatible structure.tag() from pipeline", format_name); @@ -179,9 +197,9 @@ pub fn to_delimited_data( yield Err(ShellError::labeled_error_with_secondary( expected, requires, - &name_tag, + name_span, "originates from here".to_string(), - value.tag(), + value.tag.span, )) } } diff --git a/src/commands/to_json.rs b/src/commands/to_json.rs index b100596ab9..b1dba6910b 100644 --- a/src/commands/to_json.rs +++ b/src/commands/to_json.rs @@ -1,7 +1,7 @@ use crate::commands::WholeStreamCommand; -use crate::data::{Primitive, Value}; +use crate::data::base::{Primitive, UntaggedValue, Value}; use crate::prelude::*; -use crate::RawPathMember; +use crate::UnspannedPathMember; pub struct ToJSON; @@ -27,35 +27,40 @@ impl WholeStreamCommand for ToJSON { } } -pub fn value_to_json_value(v: &Tagged) -> Result { - Ok(match v.item() { - Value::Primitive(Primitive::Boolean(b)) => serde_json::Value::Bool(*b), - Value::Primitive(Primitive::Bytes(b)) => serde_json::Value::Number( +pub fn value_to_json_value(v: &Value) -> Result { + Ok(match &v.value { + UntaggedValue::Primitive(Primitive::Boolean(b)) => serde_json::Value::Bool(*b), + UntaggedValue::Primitive(Primitive::Bytes(b)) => serde_json::Value::Number( serde_json::Number::from(b.to_u64().expect("What about really big numbers")), ), - Value::Primitive(Primitive::Duration(secs)) => { + UntaggedValue::Primitive(Primitive::Duration(secs)) => { serde_json::Value::Number(serde_json::Number::from(*secs)) } - Value::Primitive(Primitive::Date(d)) => serde_json::Value::String(d.to_string()), - Value::Primitive(Primitive::EndOfStream) => serde_json::Value::Null, - Value::Primitive(Primitive::BeginningOfStream) => serde_json::Value::Null, - Value::Primitive(Primitive::Decimal(f)) => serde_json::Value::Number( + UntaggedValue::Primitive(Primitive::Date(d)) => serde_json::Value::String(d.to_string()), + UntaggedValue::Primitive(Primitive::EndOfStream) => serde_json::Value::Null, + UntaggedValue::Primitive(Primitive::BeginningOfStream) => serde_json::Value::Null, + UntaggedValue::Primitive(Primitive::Decimal(f)) => serde_json::Value::Number( serde_json::Number::from_f64( f.to_f64().expect("TODO: What about really big decimals?"), ) .unwrap(), ), - Value::Primitive(Primitive::Int(i)) => serde_json::Value::Number(serde_json::Number::from( - CoerceInto::::coerce_into(i.tagged(&v.tag), "converting to JSON number")?, - )), - Value::Primitive(Primitive::Nothing) => serde_json::Value::Null, - Value::Primitive(Primitive::Pattern(s)) => serde_json::Value::String(s.clone()), - Value::Primitive(Primitive::String(s)) => serde_json::Value::String(s.clone()), - Value::Primitive(Primitive::ColumnPath(path)) => serde_json::Value::Array( + UntaggedValue::Primitive(Primitive::Int(i)) => { + serde_json::Value::Number(serde_json::Number::from(CoerceInto::::coerce_into( + i.tagged(&v.tag), + "converting to JSON number", + )?)) + } + 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::ColumnPath(path)) => serde_json::Value::Array( path.iter() - .map(|x| match &x.item { - RawPathMember::String(string) => Ok(serde_json::Value::String(string.clone())), - RawPathMember::Int(int) => Ok(serde_json::Value::Number( + .map(|x| match &x.unspanned { + UnspannedPathMember::String(string) => { + Ok(serde_json::Value::String(string.clone())) + } + UnspannedPathMember::Int(int) => Ok(serde_json::Value::Number( serde_json::Number::from(CoerceInto::::coerce_into( int.tagged(&v.tag), "converting to JSON number", @@ -64,19 +69,21 @@ pub fn value_to_json_value(v: &Tagged) -> Result, ShellError>>()?, ), - Value::Primitive(Primitive::Path(s)) => serde_json::Value::String(s.display().to_string()), + UntaggedValue::Primitive(Primitive::Path(s)) => { + serde_json::Value::String(s.display().to_string()) + } - Value::Table(l) => serde_json::Value::Array(json_list(l)?), - Value::Error(e) => return Err(e.clone()), - Value::Block(_) => serde_json::Value::Null, - Value::Primitive(Primitive::Binary(b)) => serde_json::Value::Array( + UntaggedValue::Table(l) => serde_json::Value::Array(json_list(l)?), + UntaggedValue::Error(e) => return Err(e.clone()), + UntaggedValue::Block(_) => serde_json::Value::Null, + UntaggedValue::Primitive(Primitive::Binary(b)) => serde_json::Value::Array( b.iter() .map(|x| { serde_json::Value::Number(serde_json::Number::from_f64(*x as f64).unwrap()) }) .collect(), ), - Value::Row(o) => { + UntaggedValue::Row(o) => { let mut m = serde_json::Map::new(); for (k, v) in o.entries.iter() { m.insert(k.clone(), value_to_json_value(v)?); @@ -86,7 +93,7 @@ pub fn value_to_json_value(v: &Tagged) -> Result>) -> Result, ShellError> { +fn json_list(input: &Vec) -> Result, ShellError> { let mut out = vec![]; for value in input { @@ -99,12 +106,13 @@ fn json_list(input: &Vec>) -> Result, Shell fn to_json(args: CommandArgs, registry: &CommandRegistry) -> Result { let args = args.evaluate_once(registry)?; let name_tag = args.name_tag(); + let name_span = name_tag.span; let stream = async_stream! { - let input: Vec> = args.input.values.collect().await; + let input: Vec = args.input.values.collect().await; let to_process_input = if input.len() > 1 { let tag = input[0].tag.clone(); - vec![Tagged { item: Value::Table(input), tag } ] + vec![Value { value: UntaggedValue::Table(input), tag } ] } else if input.len() == 1 { input } else { @@ -114,16 +122,18 @@ fn to_json(args: CommandArgs, registry: &CommandRegistry) -> Result { + let value_span = value.tag.span; + match serde_json::to_string(&json_value) { Ok(x) => yield ReturnSuccess::value( - Value::Primitive(Primitive::String(x)).tagged(&name_tag), + UntaggedValue::Primitive(Primitive::String(x)).into_value(&name_tag), ), _ => yield Err(ShellError::labeled_error_with_secondary( "Expected a table with JSON-compatible structure.tag() from pipeline", "requires JSON-compatible input", - &name_tag, + name_span, "originates from here".to_string(), - value.tag(), + value_span, )), } } diff --git a/src/commands/to_sqlite.rs b/src/commands/to_sqlite.rs index e5fcf3e27b..b8a278e74a 100644 --- a/src/commands/to_sqlite.rs +++ b/src/commands/to_sqlite.rs @@ -69,9 +69,9 @@ fn comma_concat(acc: String, current: String) -> String { } } -fn get_columns(rows: &Vec>) -> Result { - match &rows[0].item { - Value::Row(d) => Ok(d +fn get_columns(rows: &Vec) -> Result { + match &rows[0].value { + UntaggedValue::Row(d) => Ok(d .entries .iter() .map(|(k, _v)| k.clone()) @@ -84,8 +84,8 @@ fn get_columns(rows: &Vec>) -> Result { } fn nu_value_to_sqlite_string(v: Value) -> String { - match v { - Value::Primitive(p) => match p { + match &v.value { + UntaggedValue::Primitive(p) => match p { Primitive::Nothing => "NULL".into(), Primitive::Int(i) => format!("{}", i), Primitive::Duration(u) => format!("{}", u), @@ -106,15 +106,15 @@ fn nu_value_to_sqlite_string(v: Value) -> String { } } -fn get_insert_values(rows: Vec>) -> Result { +fn get_insert_values(rows: Vec) -> Result { let values: Result, _> = rows .into_iter() - .map(|value| match value.item { - Value::Row(d) => Ok(format!( + .map(|value| match value.value { + UntaggedValue::Row(d) => Ok(format!( "({})", d.entries .iter() - .map(|(_k, v)| nu_value_to_sqlite_string(v.item.clone())) + .map(|(_k, v)| nu_value_to_sqlite_string(v.clone())) .fold("".to_string(), comma_concat) )), _ => Err(std::io::Error::new( @@ -129,8 +129,8 @@ fn get_insert_values(rows: Vec>) -> Result fn generate_statements(table: Dictionary) -> Result<(String, String), std::io::Error> { let table_name = match table.entries.get("table_name") { - Some(Tagged { - item: Value::Primitive(Primitive::String(table_name)), + Some(Value { + value: UntaggedValue::Primitive(Primitive::String(table_name)), .. }) => table_name, _ => { @@ -141,8 +141,8 @@ fn generate_statements(table: Dictionary) -> Result<(String, String), std::io::E } }; let (columns, insert_values) = match table.entries.get("table_values") { - Some(Tagged { - item: Value::Table(l), + Some(Value { + value: UntaggedValue::Table(l), .. }) => (get_columns(l), get_insert_values(l.to_vec())), _ => { @@ -157,9 +157,7 @@ fn generate_statements(table: Dictionary) -> Result<(String, String), std::io::E Ok((create, insert)) } -fn sqlite_input_stream_to_bytes( - values: Vec>, -) -> Result, std::io::Error> { +fn sqlite_input_stream_to_bytes(values: Vec) -> Result { // FIXME: should probably write a sqlite virtual filesystem // that will allow us to use bytes as a file to avoid this // write out, but this will require C code. Might be @@ -171,8 +169,8 @@ fn sqlite_input_stream_to_bytes( }; let tag = values[0].tag.clone(); for value in values.into_iter() { - match value.item() { - Value::Row(d) => { + match &value.value { + UntaggedValue::Row(d) => { let (create, insert) = generate_statements(d.to_owned())?; match conn .execute(&create, NO_PARAMS) @@ -197,14 +195,14 @@ fn sqlite_input_stream_to_bytes( } let mut out = Vec::new(); tempfile.read_to_end(&mut out)?; - Ok(Value::binary(out).tagged(tag)) + Ok(UntaggedValue::binary(out).into_value(tag)) } fn to_sqlite(args: CommandArgs, registry: &CommandRegistry) -> Result { let args = args.evaluate_once(registry)?; let name_tag = args.name_tag(); let stream = async_stream! { - let input: Vec> = args.input.values.collect().await; + let input: Vec = args.input.values.collect().await; match sqlite_input_stream_to_bytes(input) { Ok(out) => yield ReturnSuccess::value(out), diff --git a/src/commands/to_toml.rs b/src/commands/to_toml.rs index 3ee1562ccf..71ff12ebee 100644 --- a/src/commands/to_toml.rs +++ b/src/commands/to_toml.rs @@ -1,7 +1,7 @@ use crate::commands::WholeStreamCommand; use crate::data::{Primitive, Value}; use crate::prelude::*; -use crate::RawPathMember; +use crate::UnspannedPathMember; pub struct ToTOML; @@ -27,33 +27,37 @@ impl WholeStreamCommand for ToTOML { } } -pub fn value_to_toml_value(v: &Tagged) -> Result { - Ok(match v.item() { - Value::Primitive(Primitive::Boolean(b)) => toml::Value::Boolean(*b), - Value::Primitive(Primitive::Bytes(b)) => toml::Value::Integer(*b as i64), - Value::Primitive(Primitive::Duration(d)) => toml::Value::Integer(*d as i64), - Value::Primitive(Primitive::Date(d)) => toml::Value::String(d.to_string()), - Value::Primitive(Primitive::EndOfStream) => { +pub fn value_to_toml_value(v: &Value) -> Result { + Ok(match &v.value { + UntaggedValue::Primitive(Primitive::Boolean(b)) => toml::Value::Boolean(*b), + UntaggedValue::Primitive(Primitive::Bytes(b)) => toml::Value::Integer(*b as i64), + UntaggedValue::Primitive(Primitive::Duration(d)) => toml::Value::Integer(*d as i64), + UntaggedValue::Primitive(Primitive::Date(d)) => toml::Value::String(d.to_string()), + UntaggedValue::Primitive(Primitive::EndOfStream) => { toml::Value::String("".to_string()) } - Value::Primitive(Primitive::BeginningOfStream) => { + UntaggedValue::Primitive(Primitive::BeginningOfStream) => { toml::Value::String("".to_string()) } - Value::Primitive(Primitive::Decimal(f)) => { + UntaggedValue::Primitive(Primitive::Decimal(f)) => { toml::Value::Float(f.tagged(&v.tag).coerce_into("converting to TOML float")?) } - Value::Primitive(Primitive::Int(i)) => { + UntaggedValue::Primitive(Primitive::Int(i)) => { toml::Value::Integer(i.tagged(&v.tag).coerce_into("converting to TOML integer")?) } - Value::Primitive(Primitive::Nothing) => toml::Value::String("".to_string()), - Value::Primitive(Primitive::Pattern(s)) => toml::Value::String(s.clone()), - Value::Primitive(Primitive::String(s)) => toml::Value::String(s.clone()), - Value::Primitive(Primitive::Path(s)) => toml::Value::String(s.display().to_string()), - Value::Primitive(Primitive::ColumnPath(path)) => toml::Value::Array( + UntaggedValue::Primitive(Primitive::Nothing) => { + toml::Value::String("".to_string()) + } + UntaggedValue::Primitive(Primitive::Pattern(s)) => toml::Value::String(s.clone()), + UntaggedValue::Primitive(Primitive::String(s)) => toml::Value::String(s.clone()), + UntaggedValue::Primitive(Primitive::Path(s)) => { + toml::Value::String(s.display().to_string()) + } + UntaggedValue::Primitive(Primitive::ColumnPath(path)) => toml::Value::Array( path.iter() - .map(|x| match &x.item { - RawPathMember::String(string) => Ok(toml::Value::String(string.clone())), - RawPathMember::Int(int) => Ok(toml::Value::Integer( + .map(|x| match &x.unspanned { + UnspannedPathMember::String(string) => Ok(toml::Value::String(string.clone())), + UnspannedPathMember::Int(int) => Ok(toml::Value::Integer( int.tagged(&v.tag) .coerce_into("converting to TOML integer")?, )), @@ -61,13 +65,13 @@ pub fn value_to_toml_value(v: &Tagged) -> Result .collect::, ShellError>>()?, ), - Value::Table(l) => toml::Value::Array(collect_values(l)?), - Value::Error(e) => return Err(e.clone()), - Value::Block(_) => toml::Value::String("".to_string()), - Value::Primitive(Primitive::Binary(b)) => { + UntaggedValue::Table(l) => toml::Value::Array(collect_values(l)?), + UntaggedValue::Error(e) => return Err(e.clone()), + UntaggedValue::Block(_) => toml::Value::String("".to_string()), + UntaggedValue::Primitive(Primitive::Binary(b)) => { toml::Value::Array(b.iter().map(|x| toml::Value::Integer(*x as i64)).collect()) } - Value::Row(o) => { + UntaggedValue::Row(o) => { let mut m = toml::map::Map::new(); for (k, v) in o.entries.iter() { m.insert(k.clone(), value_to_toml_value(v)?); @@ -77,7 +81,7 @@ pub fn value_to_toml_value(v: &Tagged) -> Result }) } -fn collect_values(input: &Vec>) -> Result, ShellError> { +fn collect_values(input: &Vec) -> Result, ShellError> { let mut out = vec![]; for value in input { @@ -90,12 +94,13 @@ fn collect_values(input: &Vec>) -> Result, ShellE fn to_toml(args: CommandArgs, registry: &CommandRegistry) -> Result { let args = args.evaluate_once(registry)?; let name_tag = args.name_tag(); + let name_span = name_tag.span; let stream = async_stream! { - let input: Vec> = args.input.values.collect().await; + let input: Vec = args.input.values.collect().await; let to_process_input = if input.len() > 1 { let tag = input[0].tag.clone(); - vec![Tagged { item: Value::Table(input), tag } ] + vec![Value { value: UntaggedValue::Table(input), tag } ] } else if input.len() == 1 { input } else { @@ -103,18 +108,19 @@ fn to_toml(args: CommandArgs, registry: &CommandRegistry) -> Result { match toml::to_string(&toml_value) { Ok(x) => yield ReturnSuccess::value( - Value::Primitive(Primitive::String(x)).tagged(&name_tag), + UntaggedValue::Primitive(Primitive::String(x)).into_value(&name_tag), ), _ => yield Err(ShellError::labeled_error_with_secondary( "Expected a table with TOML-compatible structure.tag() from pipeline", "requires TOML-compatible input", - &name_tag, + name_span, "originates from here".to_string(), - value.tag(), + value_span, )), } } diff --git a/src/commands/to_url.rs b/src/commands/to_url.rs index 8dee0a87d5..3cb12ac045 100644 --- a/src/commands/to_url.rs +++ b/src/commands/to_url.rs @@ -32,11 +32,11 @@ fn to_url(args: CommandArgs, registry: &CommandRegistry) -> Result> = input.values.collect().await; + let input: Vec = input.values.collect().await; for value in input { match value { - Tagged { item: Value::Row(row), .. } => { + Value { value: UntaggedValue::Row(row), .. } => { let mut row_vec = vec![]; for (k,v) in row.entries { match v.as_string() { @@ -57,7 +57,7 @@ fn to_url(args: CommandArgs, registry: &CommandRegistry) -> Result { - yield ReturnSuccess::value(Value::string(s).tagged(&tag)); + yield ReturnSuccess::value(UntaggedValue::string(s).into_value(&tag)); } _ => { yield Err(ShellError::labeled_error( @@ -68,13 +68,13 @@ fn to_url(args: CommandArgs, registry: &CommandRegistry) -> Result { + Value { tag: value_tag, .. } => { yield Err(ShellError::labeled_error_with_secondary( "Expected a table from pipeline", "requires table input", &tag, "value originates from here", - value_tag, + value_tag.span, )) } } diff --git a/src/commands/to_yaml.rs b/src/commands/to_yaml.rs index 4c12c30e7d..3b3556726b 100644 --- a/src/commands/to_yaml.rs +++ b/src/commands/to_yaml.rs @@ -1,7 +1,7 @@ use crate::commands::WholeStreamCommand; use crate::data::{Primitive, Value}; use crate::prelude::*; -use crate::RawPathMember; +use crate::UnspannedPathMember; pub struct ToYAML; @@ -27,36 +27,39 @@ impl WholeStreamCommand for ToYAML { } } -pub fn value_to_yaml_value(v: &Tagged) -> Result { - Ok(match v.item() { - Value::Primitive(Primitive::Boolean(b)) => serde_yaml::Value::Bool(*b), - Value::Primitive(Primitive::Bytes(b)) => { +pub fn value_to_yaml_value(v: &Value) -> Result { + Ok(match &v.value { + UntaggedValue::Primitive(Primitive::Boolean(b)) => serde_yaml::Value::Bool(*b), + UntaggedValue::Primitive(Primitive::Bytes(b)) => { serde_yaml::Value::Number(serde_yaml::Number::from(b.to_f64().unwrap())) } - Value::Primitive(Primitive::Duration(secs)) => { + UntaggedValue::Primitive(Primitive::Duration(secs)) => { serde_yaml::Value::Number(serde_yaml::Number::from(secs.to_f64().unwrap())) } - Value::Primitive(Primitive::Date(d)) => serde_yaml::Value::String(d.to_string()), - Value::Primitive(Primitive::EndOfStream) => serde_yaml::Value::Null, - Value::Primitive(Primitive::BeginningOfStream) => serde_yaml::Value::Null, - Value::Primitive(Primitive::Decimal(f)) => { + UntaggedValue::Primitive(Primitive::Date(d)) => serde_yaml::Value::String(d.to_string()), + UntaggedValue::Primitive(Primitive::EndOfStream) => serde_yaml::Value::Null, + UntaggedValue::Primitive(Primitive::BeginningOfStream) => serde_yaml::Value::Null, + UntaggedValue::Primitive(Primitive::Decimal(f)) => { serde_yaml::Value::Number(serde_yaml::Number::from(f.to_f64().unwrap())) } - Value::Primitive(Primitive::Int(i)) => serde_yaml::Value::Number(serde_yaml::Number::from( - CoerceInto::::coerce_into(i.tagged(&v.tag), "converting to YAML number")?, - )), - Value::Primitive(Primitive::Nothing) => serde_yaml::Value::Null, - Value::Primitive(Primitive::Pattern(s)) => serde_yaml::Value::String(s.clone()), - Value::Primitive(Primitive::String(s)) => serde_yaml::Value::String(s.clone()), - Value::Primitive(Primitive::ColumnPath(path)) => { + UntaggedValue::Primitive(Primitive::Int(i)) => { + serde_yaml::Value::Number(serde_yaml::Number::from(CoerceInto::::coerce_into( + i.tagged(&v.tag), + "converting to YAML number", + )?)) + } + 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::ColumnPath(path)) => { let mut out = vec![]; for member in path.iter() { - match &member.item { - RawPathMember::String(string) => { + match &member.unspanned { + UnspannedPathMember::String(string) => { out.push(serde_yaml::Value::String(string.clone())) } - RawPathMember::Int(int) => out.push(serde_yaml::Value::Number( + UnspannedPathMember::Int(int) => out.push(serde_yaml::Value::Number( serde_yaml::Number::from(CoerceInto::::coerce_into( int.tagged(&member.span), "converting to YAML number", @@ -67,9 +70,11 @@ pub fn value_to_yaml_value(v: &Tagged) -> Result serde_yaml::Value::String(s.display().to_string()), + UntaggedValue::Primitive(Primitive::Path(s)) => { + serde_yaml::Value::String(s.display().to_string()) + } - Value::Table(l) => { + UntaggedValue::Table(l) => { let mut out = vec![]; for value in l { @@ -78,14 +83,14 @@ pub fn value_to_yaml_value(v: &Tagged) -> Result return Err(e.clone()), - Value::Block(_) => serde_yaml::Value::Null, - Value::Primitive(Primitive::Binary(b)) => serde_yaml::Value::Sequence( + UntaggedValue::Error(e) => return Err(e.clone()), + UntaggedValue::Block(_) => serde_yaml::Value::Null, + UntaggedValue::Primitive(Primitive::Binary(b)) => serde_yaml::Value::Sequence( b.iter() .map(|x| serde_yaml::Value::Number(serde_yaml::Number::from(*x))) .collect(), ), - Value::Row(o) => { + UntaggedValue::Row(o) => { let mut m = serde_yaml::Mapping::new(); for (k, v) in o.entries.iter() { m.insert( @@ -101,12 +106,14 @@ pub fn value_to_yaml_value(v: &Tagged) -> Result Result { let args = args.evaluate_once(registry)?; let name_tag = args.name_tag(); + let name_span = name_tag.span; + let stream = async_stream! { - let input: Vec> = args.input.values.collect().await; + let input: Vec = args.input.values.collect().await; let to_process_input = if input.len() > 1 { let tag = input[0].tag.clone(); - vec![Tagged { item: Value::Table(input), tag } ] + vec![Value { value: UntaggedValue::Table(input), tag } ] } else if input.len() == 1 { input } else { @@ -114,18 +121,20 @@ fn to_yaml(args: CommandArgs, registry: &CommandRegistry) -> Result { match serde_yaml::to_string(&yaml_value) { Ok(x) => yield ReturnSuccess::value( - Value::Primitive(Primitive::String(x)).tagged(&name_tag), + UntaggedValue::Primitive(Primitive::String(x)).into_value(&name_tag), ), _ => yield Err(ShellError::labeled_error_with_secondary( "Expected a table with YAML-compatible structure.tag() from pipeline", "requires YAML-compatible input", - &name_tag, + name_span, "originates from here".to_string(), - value.tag(), + value_span, )), } } diff --git a/src/commands/trim.rs b/src/commands/trim.rs index 11ed025394..de10249dcf 100644 --- a/src/commands/trim.rs +++ b/src/commands/trim.rs @@ -1,5 +1,5 @@ use crate::commands::WholeStreamCommand; -use crate::data::Value; + use crate::errors::ShellError; use crate::prelude::*; @@ -34,7 +34,7 @@ fn trim(args: CommandArgs, _registry: &CommandRegistry) -> Result Result, + input: Value, ) -> Result { let input_clone = input.clone(); let condition = call_info.args.expect_nth(0)?; let stream = match condition { - Tagged { - item: Value::Block(block), + Value { + value: UntaggedValue::Block(block), .. } => { let result = block.invoke(&input_clone); @@ -49,7 +49,7 @@ impl PerItemCommand for Where { Err(e) => return Err(e), } } - Tagged { tag, .. } => { + Value { tag, .. } => { return Err(ShellError::labeled_error( "Expected a condition", "where needs a condition", diff --git a/src/commands/which_.rs b/src/commands/which_.rs index 405efe7dca..cc68adf59a 100644 --- a/src/commands/which_.rs +++ b/src/commands/which_.rs @@ -42,17 +42,18 @@ pub fn which(args: CommandArgs, registry: &CommandRegistry) -> Result 0 { match &v[0] { - Tagged { - item: Value::Primitive(Primitive::String(s)), + Value { + value: UntaggedValue::Primitive(Primitive::String(s)), tag, } => match which::which(&s) { Ok(ok) => { - which_out - .push_back(Value::Primitive(Primitive::Path(ok)).tagged(tag.clone())); + which_out.push_back( + UntaggedValue::Primitive(Primitive::Path(ok)).into_value(tag.clone()), + ); } _ => {} }, - Tagged { tag, .. } => { + Value { tag, .. } => { return Err(ShellError::labeled_error( "Expected a filename to find", "needs a filename", diff --git a/src/context.rs b/src/context.rs index 80fa536e51..5535e9c1d4 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,19 +1,16 @@ -use crate::commands::{Command, UnevaluatedCallInfo}; +use crate::commands::{command::CommandArgs, Command, UnevaluatedCallInfo}; +use crate::env::host::Host; +use crate::errors::ShellError; use crate::parser::{hir, hir::syntax_shape::ExpandContext}; -use crate::prelude::*; +use crate::shell::shell_manager::ShellManager; +use crate::stream::{InputStream, OutputStream}; use indexmap::IndexMap; -use serde::{Deserialize, Serialize}; +use nu_source::Tag; +use nu_source::Text; use std::error::Error; use std::sync::atomic::AtomicBool; use std::sync::{Arc, Mutex}; -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum AnchorLocation { - Url(String), - File(String), - Source(Text), -} - #[derive(Clone)] pub struct CommandRegistry { registry: Arc>>>, diff --git a/src/data.rs b/src/data.rs index 3b4dcfeb44..a0968e3085 100644 --- a/src/data.rs +++ b/src/data.rs @@ -4,7 +4,6 @@ pub(crate) mod config; pub(crate) mod dict; pub(crate) mod files; pub(crate) mod into; -pub(crate) mod meta; pub(crate) mod types; pub(crate) use base::{Primitive, Value}; diff --git a/src/data/base.rs b/src/data/base.rs index d4fa51e5e4..857416cad8 100644 --- a/src/data/base.rs +++ b/src/data/base.rs @@ -3,19 +3,19 @@ mod property_get; pub(crate) mod shape; use crate::context::CommandRegistry; -use crate::data::base::shape::{InlineShape, TypeShape}; +use crate::data::base::shape::{Column, InlineShape, TypeShape}; use crate::data::TaggedDictBuilder; use crate::errors::ShellError; use crate::evaluate::{evaluate_baseline_expr, Scope}; use crate::parser::hir::path::{ColumnPath, PathMember}; use crate::parser::{hir, Operator}; use crate::prelude::*; -use crate::Text; use chrono::{DateTime, Utc}; use chrono_humanize::Humanize; use derive_new::new; use indexmap::IndexMap; use log::trace; +use nu_source::{AnchorLocation, PrettyDebug, SpannedItem, Tagged, TaggedItem, Text}; use serde::{Deserialize, Serialize}; use std::path::PathBuf; use std::time::SystemTime; @@ -171,12 +171,12 @@ impl Primitive { &members .next() .expect("BUG: column path with zero members") - .to_string(), + .display(), ); for member in members { f.push_str("."); - f.push_str(&member.to_string()) + f.push_str(&member.display()) } f @@ -232,11 +232,11 @@ pub struct Block { } impl Block { - pub fn invoke(&self, value: &Tagged) -> Result, ShellError> { + pub fn invoke(&self, value: &Value) -> Result { let scope = Scope::new(value.clone()); if self.expressions.len() == 0 { - return Ok(Value::nothing().tagged(&self.tag)); + return Ok(UntaggedValue::nothing().into_value(&self.tag)); } let mut last = None; @@ -263,10 +263,10 @@ impl Block { } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Serialize, Deserialize)] -pub enum Value { +pub enum UntaggedValue { Primitive(Primitive), Row(crate::data::Dictionary), - Table(Vec>), + Table(Vec), // Errors are a type of value too Error(ShellError), @@ -274,191 +274,104 @@ pub enum Value { Block(Block), } +#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)] +pub struct Value { + pub value: UntaggedValue, + pub tag: Tag, +} + +impl std::ops::Deref for Value { + type Target = UntaggedValue; + + fn deref(&self) -> &Self::Target { + &self.value + } +} + +impl Into for Value { + fn into(self) -> UntaggedValue { + self.value + } +} + +impl<'a> Into<&'a UntaggedValue> for &'a Value { + fn into(self) -> &'a UntaggedValue { + &self.value + } +} + +impl HasSpan for Value { + fn span(&self) -> Span { + self.tag.span + } +} + impl ShellTypeName for Value { fn type_name(&self) -> &'static str { + ShellTypeName::type_name(&self.value) + } +} + +impl ShellTypeName for UntaggedValue { + fn type_name(&self) -> &'static str { + match &self { + UntaggedValue::Primitive(p) => p.type_name(), + UntaggedValue::Row(_) => "row", + UntaggedValue::Table(_) => "table", + UntaggedValue::Error(_) => "error", + UntaggedValue::Block(_) => "block", + } + } +} + +impl Into for Number { + fn into(self) -> UntaggedValue { match self { - Value::Primitive(p) => p.type_name(), - Value::Row(_) => "row", - Value::Table(_) => "table", - Value::Error(_) => "error", - Value::Block(_) => "block", + Number::Int(int) => UntaggedValue::int(int), + Number::Decimal(decimal) => UntaggedValue::decimal(decimal), } } } -impl Into for Number { - fn into(self) -> Value { +impl Into for &Number { + fn into(self) -> UntaggedValue { match self { - Number::Int(int) => Value::int(int), - Number::Decimal(decimal) => Value::decimal(decimal), - } - } -} - -impl Into for &Number { - fn into(self) -> Value { - match self { - Number::Int(int) => Value::int(int.clone()), - Number::Decimal(decimal) => Value::decimal(decimal.clone()), - } - } -} - -impl Tagged { - pub fn tagged_type_name(&self) -> Tagged { - let name = self.type_name().to_string(); - name.tagged(self.tag()) - } -} - -impl Tagged<&Value> { - pub fn tagged_type_name(&self) -> Tagged { - let name = self.type_name().to_string(); - name.tagged(self.tag()) - } -} - -impl std::convert::TryFrom<&Tagged> for Block { - type Error = ShellError; - - fn try_from(value: &Tagged) -> Result { - match value.item() { - Value::Block(block) => Ok(block.clone()), - v => Err(ShellError::type_error( - "Block", - v.type_name().spanned(value.span()), - )), - } - } -} - -impl std::convert::TryFrom<&Tagged> for i64 { - type Error = ShellError; - - fn try_from(value: &Tagged) -> Result { - match value.item() { - Value::Primitive(Primitive::Int(int)) => { - int.tagged(&value.tag).coerce_into("converting to i64") - } - v => Err(ShellError::type_error( - "Integer", - v.type_name().spanned(value.span()), - )), - } - } -} - -impl std::convert::TryFrom<&Tagged> for String { - type Error = ShellError; - - fn try_from(value: &Tagged) -> Result { - match value.item() { - Value::Primitive(Primitive::String(s)) => Ok(s.clone()), - v => Err(ShellError::type_error( - "String", - v.type_name().spanned(value.span()), - )), - } - } -} - -impl std::convert::TryFrom<&Tagged> for Vec { - type Error = ShellError; - - fn try_from(value: &Tagged) -> Result, ShellError> { - match value.item() { - Value::Primitive(Primitive::Binary(b)) => Ok(b.clone()), - v => Err(ShellError::type_error( - "Binary", - v.type_name().spanned(value.span()), - )), - } - } -} - -impl<'a> std::convert::TryFrom<&'a Tagged> for &'a crate::data::Dictionary { - type Error = ShellError; - - fn try_from(value: &'a Tagged) -> Result<&'a crate::data::Dictionary, ShellError> { - match value.item() { - Value::Row(d) => Ok(d), - v => Err(ShellError::type_error( - "Dictionary", - v.type_name().spanned(value.span()), - )), - } - } -} - -#[derive(Serialize, Deserialize)] -pub enum Switch { - Present, - Absent, -} - -impl std::convert::TryFrom>> for Switch { - type Error = ShellError; - - fn try_from(value: Option<&Tagged>) -> Result { - match value { - None => Ok(Switch::Absent), - Some(value) => match value.item() { - Value::Primitive(Primitive::Boolean(true)) => Ok(Switch::Present), - v => Err(ShellError::type_error( - "Boolean", - v.type_name().spanned(value.span()), - )), - }, + Number::Int(int) => UntaggedValue::int(int.clone()), + Number::Decimal(decimal) => UntaggedValue::decimal(decimal.clone()), } } } impl Value { - pub fn data_descriptors(&self) -> Vec { - match self { - Value::Primitive(_) => vec![], - Value::Row(columns) => columns - .entries - .keys() - .into_iter() - .map(|x| x.to_string()) - .collect(), - Value::Block(_) => vec![], - Value::Table(_) => vec![], - Value::Error(_) => vec![], + pub fn anchor(&self) -> Option { + self.tag.anchor() + } + + pub fn anchor_name(&self) -> Option { + self.tag.anchor_name() + } + + pub fn tag(&self) -> Tag { + self.tag.clone() + } + + pub fn into_parts(self) -> (UntaggedValue, Tag) { + (self.value, self.tag) + } + + pub(crate) fn as_path(&self) -> Result { + match &self.value { + UntaggedValue::Primitive(Primitive::Path(path)) => Ok(path.clone()), + UntaggedValue::Primitive(Primitive::String(path_str)) => { + Ok(PathBuf::from(&path_str).clone()) + } + _ => Err(ShellError::type_error("Path", self.spanned_type_name())), } } - pub fn get_data(&self, desc: &String) -> MaybeOwned<'_, Value> { - match self { - p @ Value::Primitive(_) => MaybeOwned::Borrowed(p), - Value::Row(o) => o.get_data(desc), - Value::Block(_) => MaybeOwned::Owned(Value::nothing()), - Value::Table(_) => MaybeOwned::Owned(Value::nothing()), - Value::Error(_) => MaybeOwned::Owned(Value::nothing()), - } - } - - #[allow(unused)] - pub(crate) fn format_type(&self, width: usize) -> String { - TypeShape::from_value(self).colored_string(width) - } - - pub(crate) fn format_leaf(&self) -> DebugDocBuilder { - InlineShape::from_value(self).format().pretty_debug() - } - - // pub(crate) fn format_for_column(&self, column: impl Into) -> DebugDocBuilder { - // InlineShape::from_value(self) - // .format_for_column(column) - // .pretty_debug() - // } - - pub(crate) fn style_leaf(&self) -> &'static str { - match self { - Value::Primitive(p) => p.style(), - _ => "", - } + pub fn tagged_type_name(&self) -> Tagged { + let name = self.type_name().to_string(); + name.tagged(self.tag.clone()) } pub(crate) fn compare( @@ -490,10 +403,174 @@ impl Value { } } } +} + +impl PrettyDebug for &Value { + fn pretty(&self) -> DebugDocBuilder { + PrettyDebug::pretty(*self) + } +} + +impl PrettyDebug for Value { + fn pretty(&self) -> DebugDocBuilder { + match &self.value { + UntaggedValue::Primitive(p) => p.pretty(), + UntaggedValue::Row(row) => row.pretty_builder().nest(1).group().into(), + UntaggedValue::Table(table) => { + b::delimit("[", b::intersperse(table, b::space()), "]").nest() + } + UntaggedValue::Error(_) => b::error("error"), + UntaggedValue::Block(_) => b::opaque("block"), + } + } +} + +impl std::convert::TryFrom<&Value> for Block { + type Error = ShellError; + + fn try_from(value: &Value) -> Result { + match &value.value { + UntaggedValue::Block(block) => Ok(block.clone()), + _ => Err(ShellError::type_error( + "Block", + value.type_name().spanned(value.tag.span), + )), + } + } +} + +impl std::convert::TryFrom<&Value> for i64 { + type Error = ShellError; + + fn try_from(value: &Value) -> Result { + match &value.value { + UntaggedValue::Primitive(Primitive::Int(int)) => { + int.tagged(&value.tag).coerce_into("converting to i64") + } + _ => Err(ShellError::type_error("Integer", value.spanned_type_name())), + } + } +} + +impl std::convert::TryFrom<&Value> for String { + type Error = ShellError; + + fn try_from(value: &Value) -> Result { + match &value.value { + UntaggedValue::Primitive(Primitive::String(s)) => Ok(s.clone()), + _ => Err(ShellError::type_error("String", value.spanned_type_name())), + } + } +} + +impl std::convert::TryFrom<&Value> for Vec { + type Error = ShellError; + + fn try_from(value: &Value) -> Result, ShellError> { + match &value.value { + UntaggedValue::Primitive(Primitive::Binary(b)) => Ok(b.clone()), + _ => Err(ShellError::type_error("Binary", value.spanned_type_name())), + } + } +} + +impl<'a> std::convert::TryFrom<&'a Value> for &'a crate::data::Dictionary { + type Error = ShellError; + + fn try_from(value: &'a Value) -> Result<&'a crate::data::Dictionary, ShellError> { + match &value.value { + UntaggedValue::Row(d) => Ok(d), + _ => Err(ShellError::type_error( + "Dictionary", + value.spanned_type_name(), + )), + } + } +} + +#[derive(Serialize, Deserialize)] +pub enum Switch { + Present, + Absent, +} + +impl std::convert::TryFrom> for Switch { + type Error = ShellError; + + fn try_from(value: Option<&Value>) -> Result { + match value { + None => Ok(Switch::Absent), + Some(value) => match &value.value { + UntaggedValue::Primitive(Primitive::Boolean(true)) => Ok(Switch::Present), + _ => Err(ShellError::type_error("Boolean", value.spanned_type_name())), + }, + } + } +} + +impl UntaggedValue { + pub fn into_value(self, tag: impl Into) -> Value { + Value { + value: self, + tag: tag.into(), + } + } + + pub fn into_untagged_value(self) -> Value { + Value { + value: self, + tag: Tag::unknown(), + } + } + + pub fn retag(self, tag: impl Into) -> Value { + Value { + value: self, + tag: tag.into(), + } + } + + pub fn data_descriptors(&self) -> Vec { + match self { + UntaggedValue::Primitive(_) => vec![], + UntaggedValue::Row(columns) => columns + .entries + .keys() + .into_iter() + .map(|x| x.to_string()) + .collect(), + UntaggedValue::Block(_) => vec![], + UntaggedValue::Table(_) => vec![], + UntaggedValue::Error(_) => vec![], + } + } + + #[allow(unused)] + pub(crate) fn format_type(&self, width: usize) -> String { + TypeShape::from_value(self).colored_string(width) + } + + pub(crate) fn format_leaf(&self) -> DebugDocBuilder { + InlineShape::from_value(self).format().pretty() + } + + #[allow(unused)] + pub(crate) fn format_for_column(&self, column: impl Into) -> DebugDocBuilder { + InlineShape::from_value(self) + .format_for_column(column) + .pretty() + } + + pub(crate) fn style_leaf(&self) -> &'static str { + match self { + UntaggedValue::Primitive(p) => p.style(), + _ => "", + } + } pub(crate) fn is_true(&self) -> bool { match self { - Value::Primitive(Primitive::Boolean(true)) => true, + UntaggedValue::Primitive(Primitive::Boolean(true)) => true, _ => false, } } @@ -504,90 +581,97 @@ impl Value { pub(crate) fn is_none(&self) -> bool { match self { - Value::Primitive(Primitive::Nothing) => true, + UntaggedValue::Primitive(Primitive::Nothing) => true, _ => false, } } pub(crate) fn is_error(&self) -> bool { match self { - Value::Error(_err) => true, + UntaggedValue::Error(_err) => true, _ => false, } } pub(crate) fn expect_error(&self) -> ShellError { match self { - Value::Error(err) => err.clone(), + UntaggedValue::Error(err) => err.clone(), _ => panic!("Don't call expect_error without first calling is_error"), } } + pub fn expect_string(&self) -> &str { + match self { + UntaggedValue::Primitive(Primitive::String(string)) => &string[..], + _ => panic!("expect_string assumes that the value must be a string"), + } + } + #[allow(unused)] - pub fn row(entries: IndexMap>) -> Value { - Value::Row(entries.into()) + pub fn row(entries: IndexMap) -> UntaggedValue { + UntaggedValue::Row(entries.into()) } - pub fn table(list: &Vec>) -> Value { - Value::Table(list.to_vec()) + pub fn table(list: &Vec) -> UntaggedValue { + UntaggedValue::Table(list.to_vec()) } - pub fn string(s: impl Into) -> Value { - Value::Primitive(Primitive::String(s.into())) + pub fn string(s: impl Into) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::String(s.into())) } - pub fn column_path(s: Vec>) -> Value { - Value::Primitive(Primitive::ColumnPath(ColumnPath::new( + pub fn column_path(s: Vec>) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::ColumnPath(ColumnPath::new( s.into_iter().map(|p| p.into()).collect(), ))) } - pub fn int(i: impl Into) -> Value { - Value::Primitive(Primitive::Int(i.into())) + pub fn int(i: impl Into) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::Int(i.into())) } - pub fn pattern(s: impl Into) -> Value { - Value::Primitive(Primitive::String(s.into())) + pub fn pattern(s: impl Into) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::String(s.into())) } - pub fn path(s: impl Into) -> Value { - Value::Primitive(Primitive::Path(s.into())) + pub fn path(s: impl Into) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::Path(s.into())) } - pub fn bytes(s: impl Into) -> Value { - Value::Primitive(Primitive::Bytes(s.into())) + pub fn bytes(s: impl Into) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::Bytes(s.into())) } - pub fn decimal(s: impl Into) -> Value { - Value::Primitive(Primitive::Decimal(s.into())) + pub fn decimal(s: impl Into) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::Decimal(s.into())) } - pub fn binary(binary: Vec) -> Value { - Value::Primitive(Primitive::Binary(binary)) + pub fn binary(binary: Vec) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::Binary(binary)) } - pub fn number(s: impl Into) -> Value { + pub fn number(s: impl Into) -> UntaggedValue { let num = s.into(); match num { - Number::Int(int) => Value::int(int), - Number::Decimal(decimal) => Value::decimal(decimal), + Number::Int(int) => UntaggedValue::int(int), + Number::Decimal(decimal) => UntaggedValue::decimal(decimal), } } - pub fn boolean(s: impl Into) -> Value { - Value::Primitive(Primitive::Boolean(s.into())) + pub fn boolean(s: impl Into) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::Boolean(s.into())) } - pub fn duration(secs: u64) -> Value { - Value::Primitive(Primitive::Duration(secs)) + pub fn duration(secs: u64) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::Duration(secs)) } - pub fn system_date(s: SystemTime) -> Value { - Value::Primitive(Primitive::Date(s.into())) + pub fn system_date(s: SystemTime) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::Date(s.into())) } - pub fn date_from_str(s: Tagged<&str>) -> Result { + pub fn date_from_str(s: Tagged<&str>) -> Result { let date = DateTime::parse_from_rfc3339(s.item).map_err(|err| { ShellError::labeled_error( &format!("Date parse error: {}", err), @@ -598,43 +682,30 @@ impl Value { let date = date.with_timezone(&chrono::offset::Utc); - Ok(Value::Primitive(Primitive::Date(date))) + Ok(UntaggedValue::Primitive(Primitive::Date(date))) } - pub fn nothing() -> Value { - Value::Primitive(Primitive::Nothing) + pub fn nothing() -> UntaggedValue { + UntaggedValue::Primitive(Primitive::Nothing) } } -impl Tagged { - pub(crate) fn as_path(&self) -> Result { - match self.item() { - Value::Primitive(Primitive::Path(path)) => Ok(path.clone()), - Value::Primitive(Primitive::String(path_str)) => Ok(PathBuf::from(&path_str).clone()), - other => Err(ShellError::type_error( - "Path", - other.type_name().spanned(self.span()), - )), - } - } -} - -pub(crate) fn select_fields(obj: &Value, fields: &[String], tag: impl Into) -> Tagged { +pub(crate) fn select_fields(obj: &Value, fields: &[String], tag: impl Into) -> Value { let mut out = TaggedDictBuilder::new(tag); let descs = obj.data_descriptors(); for field in fields { match descs.iter().find(|d| *d == field) { - None => out.insert(field, Value::nothing()), - Some(desc) => out.insert(desc.clone(), obj.get_data(desc).borrow().clone()), + None => out.insert_untagged(field, UntaggedValue::nothing()), + Some(desc) => out.insert_value(desc.clone(), obj.get_data(desc).borrow().clone()), } } - out.into_tagged_value() + out.into_value() } -pub(crate) fn reject_fields(obj: &Value, fields: &[String], tag: impl Into) -> Tagged { +pub(crate) fn reject_fields(obj: &Value, fields: &[String], tag: impl Into) -> Value { let mut out = TaggedDictBuilder::new(tag); let descs = obj.data_descriptors(); @@ -643,11 +714,11 @@ pub(crate) fn reject_fields(obj: &Value, fields: &[String], tag: impl Into) if fields.iter().any(|field| *field == desc) { continue; } else { - out.insert(desc.clone(), obj.get_data(&desc).borrow().clone()) + out.insert_value(desc.clone(), obj.get_data(&desc).borrow().clone()) } } - out.into_tagged_value() + out.into_value() } enum CompareValues { @@ -680,8 +751,10 @@ fn coerce_compare( left: &Value, right: &Value, ) -> Result { - match (left, right) { - (Value::Primitive(left), Value::Primitive(right)) => coerce_compare_primitive(left, right), + match (&left.value, &right.value) { + (UntaggedValue::Primitive(left), UntaggedValue::Primitive(right)) => { + coerce_compare_primitive(left, right) + } _ => Err((left.type_name(), right.type_name())), } @@ -719,28 +792,29 @@ fn coerce_compare_primitive( #[cfg(test)] mod tests { - use crate::data::meta::*; + use super::UntaggedValue; use crate::parser::hir::path::PathMember; use crate::ColumnPath as ColumnPathValue; use crate::ShellError; use crate::Value; use indexmap::IndexMap; + use nu_source::*; use num_bigint::BigInt; - fn string(input: impl Into) -> Tagged { - Value::string(input.into()).tagged_unknown() + fn string(input: impl Into) -> Value { + UntaggedValue::string(input.into()).into_untagged_value() } - fn int(input: impl Into) -> Tagged { - Value::int(input.into()).tagged_unknown() + fn int(input: impl Into) -> Value { + UntaggedValue::int(input.into()).into_untagged_value() } - fn row(entries: IndexMap>) -> Tagged { - Value::row(entries).tagged_unknown() + fn row(entries: IndexMap) -> Value { + UntaggedValue::row(entries).into_untagged_value() } - fn table(list: &Vec>) -> Tagged { - Value::table(list).tagged_unknown() + fn table(list: &Vec) -> Value { + UntaggedValue::table(list).into_untagged_value() } fn error_callback( @@ -749,7 +823,7 @@ mod tests { move |(_obj_source, _column_path_tried, _err)| ShellError::unimplemented(reason) } - fn column_path(paths: &Vec>) -> Tagged { + fn column_path(paths: &Vec) -> Tagged { table(&paths.iter().cloned().collect()) .as_column_path() .unwrap() @@ -757,9 +831,10 @@ mod tests { #[test] fn gets_matching_field_from_a_row() { - let row = Value::row(indexmap! { + let row = UntaggedValue::row(indexmap! { "amigos".into() => table(&vec![string("andres"),string("jonathan"),string("yehuda")]) - }); + }) + .into_untagged_value(); assert_eq!( row.get_data_by_key("amigos".spanned_unknown()).unwrap(), @@ -777,7 +852,7 @@ mod tests { let (version, tag) = string("0.4.0").into_parts(); - let value = Value::row(indexmap! { + let value = UntaggedValue::row(indexmap! { "package".into() => row(indexmap! { "name".into() => string("nu"), @@ -787,7 +862,7 @@ mod tests { assert_eq!( *value - .tagged(tag) + .into_value(tag) .get_data_by_column_path(&field_path, Box::new(error_callback("package.version"))) .unwrap(), version @@ -800,7 +875,7 @@ mod tests { let (_, tag) = string("Andrés N. Robalino").into_parts(); - let value = Value::row(indexmap! { + let value = UntaggedValue::row(indexmap! { "package".into() => row(indexmap! { "name".into() => string("nu"), "version".into() => string("0.4.0"), @@ -814,7 +889,7 @@ mod tests { assert_eq!( value - .tagged(tag) + .into_value(tag) .get_data_by_column_path( &field_path, Box::new(error_callback("package.authors.name")) @@ -834,7 +909,7 @@ mod tests { let (_, tag) = string("Andrés N. Robalino").into_parts(); - let value = Value::row(indexmap! { + let value = UntaggedValue::row(indexmap! { "package".into() => row(indexmap! { "name".into() => string("nu"), "version".into() => string("0.4.0"), @@ -848,10 +923,10 @@ mod tests { assert_eq!( *value - .tagged(tag) + .into_value(tag) .get_data_by_column_path(&field_path, Box::new(error_callback("package.authors.0"))) .unwrap(), - Value::row(indexmap! { + UntaggedValue::row(indexmap! { "name".into() => string("Andrés N. Robalino") }) ); @@ -863,7 +938,7 @@ mod tests { let (_, tag) = string("Andrés N. Robalino").into_parts(); - let value = Value::row(indexmap! { + let value = UntaggedValue::row(indexmap! { "package".into() => row(indexmap! { "name".into() => string("nu"), "version".into() => string("0.4.0"), @@ -877,13 +952,13 @@ mod tests { assert_eq!( *value - .tagged(tag) + .into_value(tag) .get_data_by_column_path( &field_path, Box::new(error_callback("package.authors.\"0\"")) ) .unwrap(), - Value::row(indexmap! { + UntaggedValue::row(indexmap! { "name".into() => string("Andrés N. Robalino") }) ); @@ -893,7 +968,7 @@ mod tests { fn replaces_matching_field_from_a_row() { let field_path = column_path(&vec![string("amigos")]); - let sample = Value::row(indexmap! { + let sample = UntaggedValue::row(indexmap! { "amigos".into() => table(&vec![ string("andres"), string("jonathan"), @@ -901,10 +976,10 @@ mod tests { ]), }); - let (replacement, tag) = string("jonas").into_parts(); + let replacement = string("jonas"); let actual = sample - .tagged(tag) + .into_untagged_value() .replace_data_at_column_path(&field_path, replacement) .unwrap(); @@ -919,7 +994,7 @@ mod tests { string("los.3.caballeros"), ]); - let sample = Value::row(indexmap! { + let sample = UntaggedValue::row(indexmap! { "package".into() => row(indexmap! { "authors".into() => row(indexmap! { "los.3.mosqueteros".into() => table(&vec![string("andres::yehuda::jonathan")]), @@ -929,22 +1004,23 @@ mod tests { }) }); - let (replacement, tag) = table(&vec![string("yehuda::jonathan::andres")]).into_parts(); + let replacement = table(&vec![string("yehuda::jonathan::andres")]); + let tag = replacement.tag.clone(); let actual = sample - .tagged(tag.clone()) + .into_value(tag.clone()) .replace_data_at_column_path(&field_path, replacement.clone()) .unwrap(); assert_eq!( actual, - Value::row(indexmap! { + UntaggedValue::row(indexmap! { "package".into() => row(indexmap! { "authors".into() => row(indexmap! { "los.3.mosqueteros".into() => table(&vec![string("andres::yehuda::jonathan")]), "los.3.amigos".into() => table(&vec![string("andres::yehuda::jonathan")]), - "los.3.caballeros".into() => replacement.tagged(&tag)})})}) - .tagged(tag) + "los.3.caballeros".into() => replacement.clone()})})}) + .into_value(tag) ); } #[test] @@ -955,7 +1031,7 @@ mod tests { string("nu.version.arepa"), ]); - let sample = Value::row(indexmap! { + let sample = UntaggedValue::row(indexmap! { "shell_policy".into() => row(indexmap! { "releases".into() => table(&vec![ row(indexmap! { @@ -977,24 +1053,24 @@ mod tests { }) }); - let (replacement, tag) = row(indexmap! { + let replacement = row(indexmap! { "code".into() => string("0.5.0"), "tag_line".into() => string("CABALLEROS") - }) - .into_parts(); + }); + let tag = replacement.tag.clone(); let actual = sample - .tagged(tag.clone()) + .into_value(tag.clone()) .replace_data_at_column_path(&field_path, replacement.clone()) .unwrap(); assert_eq!( actual, - Value::row(indexmap! { + UntaggedValue::row(indexmap! { "shell_policy".into() => row(indexmap! { "releases".into() => table(&vec![ row(indexmap! { - "nu.version.arepa".into() => replacement.tagged(&tag) + "nu.version.arepa".into() => replacement }), row(indexmap! { "nu.version.taco".into() => row(indexmap! { @@ -1008,7 +1084,7 @@ mod tests { }) ]) }) - }).tagged(&tag) + }).into_value(&tag) ); } } diff --git a/src/data/base/debug.rs b/src/data/base/debug.rs index ccac2eef91..05b8b911bd 100644 --- a/src/data/base/debug.rs +++ b/src/data/base/debug.rs @@ -1,54 +1,6 @@ use crate::data::base::Primitive; -use crate::prelude::*; -use crate::traits::DebugDocBuilder as b; -use pretty::{BoxAllocator, DocAllocator}; -use std::fmt; - -impl FormatDebug for Tagged { - fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result { - match &self.item { - Value::Primitive(p) => p.fmt_debug(f, source), - Value::Row(row) => f.say_dict( - "row", - row.entries() - .iter() - .map(|(key, value)| (&key[..], format!("{}", value.debug(source)))) - .collect(), - ), - Value::Table(table) => f.say_list( - "table", - table, - |f| write!(f, "["), - |f, item| write!(f, "{}", item.debug(source)), - |f| write!(f, " "), - |f| write!(f, "]"), - ), - Value::Error(_) => f.say_simple("error"), - Value::Block(_) => f.say_simple("block"), - } - } -} - -impl FormatDebug for Primitive { - fn fmt_debug(&self, f: &mut DebugFormatter, _source: &str) -> fmt::Result { - match self { - Primitive::Nothing => write!(f, "Nothing"), - Primitive::BeginningOfStream => write!(f, "BeginningOfStream"), - Primitive::EndOfStream => write!(f, "EndOfStream"), - Primitive::Int(int) => write!(f, "{}", int), - Primitive::Duration(duration) => write!(f, "{} seconds", *duration), - Primitive::Path(path) => write!(f, "{}", path.display()), - Primitive::Decimal(decimal) => write!(f, "{}", decimal), - Primitive::Bytes(bytes) => write!(f, "{}", bytes), - Primitive::Pattern(string) => write!(f, "{:?}", string), - Primitive::String(string) => write!(f, "{:?}", string), - Primitive::ColumnPath(path) => write!(f, "{:?}", path), - Primitive::Boolean(boolean) => write!(f, "{}", boolean), - Primitive::Date(date) => write!(f, "{}", date), - Primitive::Binary(binary) => write!(f, "{:?}", binary), - } - } -} +use crate::traits::PrettyType; +use nu_source::{b, DebugDocBuilder, PrettyDebug}; impl PrettyType for Primitive { fn pretty_type(&self) -> DebugDocBuilder { @@ -72,14 +24,14 @@ impl PrettyType for Primitive { } impl PrettyDebug for Primitive { - fn pretty_debug(&self) -> DebugDocBuilder { + fn pretty(&self) -> DebugDocBuilder { match self { Primitive::Nothing => b::primitive("nothing"), Primitive::Int(int) => prim(format_args!("{}", int)), Primitive::Decimal(decimal) => prim(format_args!("{}", decimal)), Primitive::Bytes(bytes) => primitive_doc(bytes, "bytesize"), Primitive::String(string) => prim(string), - Primitive::ColumnPath(path) => path.pretty_debug(), + Primitive::ColumnPath(path) => path.pretty(), Primitive::Pattern(pattern) => primitive_doc(pattern, "pattern"), Primitive::Boolean(boolean) => match boolean { true => b::primitive("$yes"), @@ -95,27 +47,6 @@ impl PrettyDebug for Primitive { } } -impl PrettyDebug for Value { - fn pretty_debug(&self) -> DebugDocBuilder { - match self { - Value::Primitive(p) => p.pretty_debug(), - Value::Row(row) => row.pretty_builder().nest(1).group().into(), - Value::Table(table) => BoxAllocator - .text("[") - .append( - BoxAllocator - .intersperse(table.iter().map(|v| v.item.to_doc()), BoxAllocator.space()) - .nest(1) - .group(), - ) - .append(BoxAllocator.text("]")) - .into(), - Value::Error(_) => b::error("error"), - Value::Block(_) => b::opaque("block"), - } - } -} - fn prim(name: impl std::fmt::Debug) -> DebugDocBuilder { b::primitive(format!("{:?}", name)) } diff --git a/src/data/base/property_get.rs b/src/data/base/property_get.rs index 587a2f474c..81589a11b3 100644 --- a/src/data/base/property_get.rs +++ b/src/data/base/property_get.rs @@ -1,19 +1,17 @@ use crate::errors::ExpectedRange; -use crate::parser::hir::path::{PathMember, RawPathMember}; +use crate::parser::hir::path::{PathMember, UnspannedPathMember}; use crate::prelude::*; use crate::ColumnPath; use crate::SpannedTypeName; +use nu_source::{Spanned, SpannedItem, Tagged}; -impl Tagged { - pub(crate) fn get_data_by_member( - &self, - name: &PathMember, - ) -> Result, ShellError> { - match &self.item { +impl Value { + pub(crate) fn get_data_by_member(&self, name: &PathMember) -> Result { + match &self.value { // If the value is a row, the member is a column name - Value::Row(o) => match &name.item { + UntaggedValue::Row(o) => match &name.unspanned { // If the member is a string, get the data - RawPathMember::String(string) => o + UnspannedPathMember::String(string) => o .get_data_by_key(string[..].spanned(name.span)) .ok_or_else(|| { ShellError::missing_property( @@ -23,62 +21,65 @@ impl Tagged { }), // If the member is a number, it's an error - RawPathMember::Int(_) => Err(ShellError::invalid_integer_index( + UnspannedPathMember::Int(_) => Err(ShellError::invalid_integer_index( "row".spanned(self.tag.span), name.span, )), }, // If the value is a table - Value::Table(l) => match &name.item { - // If the member is a string, map over the member - RawPathMember::String(string) => { - let mut out = vec![]; + UntaggedValue::Table(l) => { + match &name.unspanned { + // If the member is a string, map over the member + UnspannedPathMember::String(string) => { + let mut out = vec![]; - for item in l { - match item { - Tagged { - item: Value::Row(o), - .. - } => match o.get_data_by_key(string[..].spanned(name.span)) { - Some(v) => out.push(v), - None => {} - }, - _ => {} + for item in l { + match item { + Value { + value: UntaggedValue::Row(o), + .. + } => match o.get_data_by_key(string[..].spanned(name.span)) { + Some(v) => out.push(v), + None => {} + }, + _ => {} + } + } + + if out.len() == 0 { + Err(ShellError::missing_property( + "table".spanned(self.tag.span), + string.spanned(name.span), + )) + } else { + Ok(UntaggedValue::Table(out) + .into_value(Tag::new(self.anchor(), name.span))) } } + UnspannedPathMember::Int(int) => { + let index = int.to_usize().ok_or_else(|| { + ShellError::range_error( + ExpectedRange::Usize, + &"massive integer".spanned(name.span), + "indexing", + ) + })?; - if out.len() == 0 { - Err(ShellError::missing_property( - "table".spanned(self.tag.span), - string.spanned(name.span), - )) - } else { - Ok(Value::Table(out).tagged(Tag::new(self.anchor(), name.span))) + match self.get_data_by_index(index.spanned(self.tag.span)) { + Some(v) => Ok(v.clone()), + None => Err(ShellError::range_error( + 0..(l.len()), + &int.spanned(name.span), + "indexing", + )), + } } } - RawPathMember::Int(int) => { - let index = int.to_usize().ok_or_else(|| { - ShellError::range_error( - ExpectedRange::Usize, - &"massive integer".tagged(name.span), - "indexing", - ) - })?; - - match self.get_data_by_index(index.spanned(self.tag.span)) { - Some(v) => Ok(v.clone()), - None => Err(ShellError::range_error( - 0..(l.len()), - &int.tagged(name.span), - "indexing", - )), - } - } - }, + } other => Err(ShellError::type_error( "row or table", - other.spanned(self.tag.span).spanned_type_name(), + other.type_name().spanned(self.tag.span), )), } } @@ -87,7 +88,7 @@ impl Tagged { &self, path: &ColumnPath, callback: Box ShellError>, - ) -> Result, ShellError> { + ) -> Result { let mut current = self.clone(); for p in path.iter() { @@ -102,19 +103,20 @@ impl Tagged { Ok(current) } - pub fn insert_data_at_path(&self, path: &str, new_value: Value) -> Option> { + pub fn insert_data_at_path(&self, path: &str, new_value: Value) -> Option { let mut new_obj = self.clone(); let split_path: Vec<_> = path.split(".").collect(); - if let Value::Row(ref mut o) = new_obj.item { + if let UntaggedValue::Row(ref mut o) = new_obj.value { let mut current = o; if split_path.len() == 1 { // Special case for inserting at the top level - current - .entries - .insert(path.to_string(), new_value.tagged(&self.tag)); + current.entries.insert( + path.to_string(), + new_value.value.clone().into_value(&self.tag), + ); return Some(new_obj); } @@ -122,11 +124,11 @@ impl Tagged { match current.entries.get_mut(split_path[idx]) { Some(next) => { if idx == (split_path.len() - 2) { - match &mut next.item { - Value::Row(o) => { + match &mut next.value { + UntaggedValue::Row(o) => { o.entries.insert( split_path[idx + 1].to_string(), - new_value.tagged(&self.tag), + new_value.value.clone().into_value(&self.tag), ); } _ => {} @@ -134,8 +136,8 @@ impl Tagged { return Some(new_obj.clone()); } else { - match next.item { - Value::Row(ref mut o) => { + match next.value { + UntaggedValue::Row(ref mut o) => { current = o; } _ => return None, @@ -153,28 +155,28 @@ impl Tagged { pub fn insert_data_at_member( &mut self, member: &PathMember, - new_value: Tagged, + new_value: Value, ) -> Result<(), ShellError> { - match &mut self.item { - Value::Row(dict) => match &member.item { - RawPathMember::String(key) => Ok({ + match &mut self.value { + UntaggedValue::Row(dict) => match &member.unspanned { + UnspannedPathMember::String(key) => Ok({ dict.insert_data_at_key(key, new_value); }), - RawPathMember::Int(_) => Err(ShellError::type_error( + UnspannedPathMember::Int(_) => Err(ShellError::type_error( "column name", "integer".spanned(member.span), )), }, - Value::Table(array) => match &member.item { - RawPathMember::String(_) => Err(ShellError::type_error( + UntaggedValue::Table(array) => match &member.unspanned { + UnspannedPathMember::String(_) => Err(ShellError::type_error( "list index", "string".spanned(member.span), )), - RawPathMember::Int(int) => Ok({ + UnspannedPathMember::Int(int) => Ok({ let int = int.to_usize().ok_or_else(|| { ShellError::range_error( ExpectedRange::Usize, - &"bigger number".tagged(member.span), + &"bigger number".spanned(member.span), "inserting into a list", ) })?; @@ -182,12 +184,12 @@ impl Tagged { insert_data_at_index(array, int.tagged(member.span), new_value.clone())?; }), }, - other => match &member.item { - RawPathMember::String(_) => Err(ShellError::type_error( + other => match &member.unspanned { + UnspannedPathMember::String(_) => Err(ShellError::type_error( "row", other.type_name().spanned(self.span()), )), - RawPathMember::Int(_) => Err(ShellError::type_error( + UnspannedPathMember::Int(_) => Err(ShellError::type_error( "table", other.type_name().spanned(self.span()), )), @@ -198,25 +200,22 @@ impl Tagged { pub fn insert_data_at_column_path( &self, split_path: &ColumnPath, - new_value: Tagged, - ) -> Result, ShellError> { + new_value: Value, + ) -> Result { let (last, front) = split_path.split_last(); let mut original = self.clone(); - let mut current: &mut Tagged = &mut original; + let mut current: &mut Value = &mut original; for member in front { let type_name = current.spanned_type_name(); - current = current - .item - .get_mut_data_by_member(&member) - .ok_or_else(|| { - ShellError::missing_property( - member.plain_string(std::usize::MAX).spanned(member.span), - type_name, - ) - })? + current = current.get_mut_data_by_member(&member).ok_or_else(|| { + ShellError::missing_property( + member.plain_string(std::usize::MAX).spanned(member.span), + type_name, + ) + })? } current.insert_data_at_member(&last, new_value)?; @@ -228,16 +227,16 @@ impl Tagged { &self, split_path: &ColumnPath, replaced_value: Value, - ) -> Option> { - let mut new_obj: Tagged = self.clone(); + ) -> Option { + let mut new_obj: Value = self.clone(); let mut current = &mut new_obj; let split_path = split_path.members(); for idx in 0..split_path.len() { - match current.item.get_mut_data_by_member(&split_path[idx]) { + match current.get_mut_data_by_member(&split_path[idx]) { Some(next) => { if idx == (split_path.len() - 1) { - *next = replaced_value.tagged(&self.tag); + *next = replaced_value.value.into_value(&self.tag); return Some(new_obj); } else { current = next; @@ -253,8 +252,8 @@ impl Tagged { } pub fn as_column_path(&self) -> Result, ShellError> { - match &self.item { - Value::Table(table) => { + match &self.value { + UntaggedValue::Table(table) => { let mut out: Vec = vec![]; for item in table { @@ -264,7 +263,7 @@ impl Tagged { Ok(ColumnPath::new(out).tagged(&self.tag)) } - Value::Primitive(Primitive::ColumnPath(path)) => { + UntaggedValue::Primitive(Primitive::ColumnPath(path)) => { Ok(path.clone().tagged(self.tag.clone())) } @@ -276,8 +275,8 @@ impl Tagged { } pub fn as_path_member(&self) -> Result { - match &self.item { - Value::Primitive(primitive) => match primitive { + match &self.value { + UntaggedValue::Primitive(primitive) => match primitive { Primitive::Int(int) => Ok(PathMember::int(int.clone(), self.tag.span)), Primitive::String(string) => Ok(PathMember::string(string, self.tag.span)), other => Err(ShellError::type_error( @@ -293,13 +292,13 @@ impl Tagged { } pub fn as_string(&self) -> Result { - match &self.item { - Value::Primitive(Primitive::String(s)) => Ok(s.clone()), - Value::Primitive(Primitive::Boolean(x)) => Ok(format!("{}", x)), - Value::Primitive(Primitive::Decimal(x)) => Ok(format!("{}", x)), - Value::Primitive(Primitive::Int(x)) => Ok(format!("{}", x)), - Value::Primitive(Primitive::Bytes(x)) => Ok(format!("{}", x)), - Value::Primitive(Primitive::Path(x)) => Ok(format!("{}", x.display())), + match &self.value { + UntaggedValue::Primitive(Primitive::String(s)) => Ok(s.clone()), + UntaggedValue::Primitive(Primitive::Boolean(x)) => Ok(format!("{}", x)), + UntaggedValue::Primitive(Primitive::Decimal(x)) => Ok(format!("{}", x)), + UntaggedValue::Primitive(Primitive::Int(x)) => Ok(format!("{}", x)), + UntaggedValue::Primitive(Primitive::Bytes(x)) => Ok(format!("{}", x)), + UntaggedValue::Primitive(Primitive::Path(x)) => Ok(format!("{}", x.display())), // TODO: this should definitely be more general with better errors other => Err(ShellError::labeled_error( "Expected string", @@ -311,14 +310,14 @@ impl Tagged { } fn insert_data_at_index( - list: &mut Vec>, + list: &mut Vec, index: Tagged, - new_value: Tagged, + new_value: Value, ) -> Result<(), ShellError> { if list.len() >= index.item { Err(ShellError::range_error( 0..(list.len()), - &format_args!("{}", index.item).tagged(index.tag.clone()), + &format_args!("{}", index.item).spanned(index.tag.span), "insert at index", )) } else { @@ -328,41 +327,51 @@ fn insert_data_at_index( } impl Value { - pub(crate) fn get_data_by_index(&self, idx: Spanned) -> Option> { - match self { - Value::Table(value_set) => { + pub fn get_data(&self, desc: &String) -> MaybeOwned<'_, Value> { + match &self.value { + UntaggedValue::Primitive(_) => MaybeOwned::Borrowed(self), + UntaggedValue::Row(o) => o.get_data(desc), + UntaggedValue::Block(_) | UntaggedValue::Table(_) | UntaggedValue::Error(_) => { + MaybeOwned::Owned(UntaggedValue::nothing().into_untagged_value()) + } + } + } + + pub(crate) fn get_data_by_index(&self, idx: Spanned) -> Option { + match &self.value { + UntaggedValue::Table(value_set) => { let value = value_set.get(idx.item)?; Some( value - .item + .value .clone() - .tagged(Tag::new(value.anchor(), idx.span)), + .into_value(Tag::new(value.anchor(), idx.span)), ) } _ => None, } } - pub(crate) fn get_data_by_key(&self, name: Spanned<&str>) -> Option> { - match self { - Value::Row(o) => o.get_data_by_key(name), - Value::Table(l) => { + pub(crate) fn get_data_by_key(&self, name: Spanned<&str>) -> Option { + match &self.value { + UntaggedValue::Row(o) => o.get_data_by_key(name), + UntaggedValue::Table(l) => { let mut out = vec![]; for item in l { match item { - Tagged { - item: Value::Row(o), + Value { + value: UntaggedValue::Row(o), .. } => match o.get_data_by_key(name) { Some(v) => out.push(v), - None => out.push(Value::nothing().tagged_unknown()), + None => out.push(UntaggedValue::nothing().into_untagged_value()), }, - _ => out.push(Value::nothing().tagged_unknown()), + _ => out.push(UntaggedValue::nothing().into_untagged_value()), } } if out.len() > 0 { - Some(Value::Table(out).tagged(name.span)) + Some(UntaggedValue::Table(out).into_value(name.span)) } else { None } @@ -371,21 +380,18 @@ impl Value { } } - pub(crate) fn get_mut_data_by_member( - &mut self, - name: &PathMember, - ) -> Option<&mut Tagged> { - match self { - Value::Row(o) => match &name.item { - RawPathMember::String(string) => o.get_mut_data_by_key(&string), - RawPathMember::Int(_) => None, + pub(crate) fn get_mut_data_by_member(&mut self, name: &PathMember) -> Option<&mut Value> { + match &mut self.value { + UntaggedValue::Row(o) => match &name.unspanned { + UnspannedPathMember::String(string) => o.get_mut_data_by_key(&string), + UnspannedPathMember::Int(_) => None, }, - Value::Table(l) => match &name.item { - RawPathMember::String(string) => { + UntaggedValue::Table(l) => match &name.unspanned { + UnspannedPathMember::String(string) => { for item in l { match item { - Tagged { - item: Value::Row(o), + Value { + value: UntaggedValue::Row(o), .. } => match o.get_mut_data_by_key(&string) { Some(v) => return Some(v), @@ -396,7 +402,7 @@ impl Value { } None } - RawPathMember::Int(int) => { + UnspannedPathMember::Int(int) => { let index = int.to_usize()?; l.get_mut(index) } diff --git a/src/data/base/shape.rs b/src/data/base/shape.rs index fb651cf69a..74c53407ed 100644 --- a/src/data/base/shape.rs +++ b/src/data/base/shape.rs @@ -1,11 +1,12 @@ use crate::data::base::{Block, ColumnPath}; use crate::data::dict::Dictionary; use crate::prelude::*; -use crate::traits::{DebugDocBuilder as b, PrettyDebug}; use chrono::{DateTime, Utc}; use chrono_humanize::Humanize; use derive_new::new; use indexmap::IndexMap; +use nu_source::DebugDoc; +use nu_source::{b, PrettyDebug}; use std::collections::BTreeMap; use std::fmt::Debug; use std::hash::Hash; @@ -76,7 +77,7 @@ impl TypeShape { for (key, value) in dictionary.entries.iter() { let column = Column::String(key.clone()); - map.insert(column, TypeShape::from_value(&value.item)); + map.insert(column, TypeShape::from_value(value)); } TypeShape::Row(map) @@ -92,19 +93,19 @@ impl TypeShape { TypeShape::Table(vec) } - pub fn from_value(value: &Value) -> TypeShape { - match value { - Value::Primitive(p) => TypeShape::from_primitive(p), - Value::Row(row) => TypeShape::from_dictionary(row), - Value::Table(table) => TypeShape::from_table(table.iter().map(|i| &i.item)), - Value::Error(_) => TypeShape::Error, - Value::Block(_) => TypeShape::Block, + pub fn from_value<'a>(value: impl Into<&'a UntaggedValue>) -> TypeShape { + match value.into() { + UntaggedValue::Primitive(p) => TypeShape::from_primitive(p), + UntaggedValue::Row(row) => TypeShape::from_dictionary(row), + UntaggedValue::Table(table) => TypeShape::from_table(table.iter()), + UntaggedValue::Error(_) => TypeShape::Error, + UntaggedValue::Block(_) => TypeShape::Block, } } } impl PrettyDebug for TypeShape { - fn pretty_debug(&self) -> DebugDocBuilder { + fn pretty(&self) -> DebugDocBuilder { match self { TypeShape::Nothing => ty("nothing"), TypeShape::Int => ty("integer"), @@ -128,7 +129,7 @@ impl PrettyDebug for TypeShape { (b::key(match key { Column::String(string) => string.clone(), Column::Value => "".to_string(), - }) + b::delimit("(", ty.pretty_debug(), ")").as_kind()) + }) + b::delimit("(", ty.pretty(), ")").as_kind()) .nest() }), b::space(), @@ -186,11 +187,11 @@ struct DebugEntry<'a> { } impl<'a> PrettyDebug for DebugEntry<'a> { - fn pretty_debug(&self) -> DebugDocBuilder { + fn pretty(&self) -> DebugDocBuilder { (b::key(match self.key { Column::String(string) => string.clone(), Column::Value => format!(""), - }) + b::delimit("(", self.value.pretty_debug(), ")").as_kind()) + }) + b::delimit("(", self.value.pretty(), ")").as_kind()) } } @@ -256,7 +257,7 @@ impl InlineShape { for (key, value) in dictionary.entries.iter() { let column = Column::String(key.clone()); - map.insert(column, InlineShape::from_value(&value.item)); + map.insert(column, InlineShape::from_value(value)); } InlineShape::Row(map) @@ -272,22 +273,23 @@ impl InlineShape { InlineShape::Table(vec) } - pub fn from_value(value: &Value) -> InlineShape { - match value { - Value::Primitive(p) => InlineShape::from_primitive(p), - Value::Row(row) => InlineShape::from_dictionary(row), - Value::Table(table) => InlineShape::from_table(table.iter().map(|i| &i.item)), - Value::Error(_) => InlineShape::Error, - Value::Block(_) => InlineShape::Block, + pub fn from_value<'a>(value: impl Into<&'a UntaggedValue>) -> InlineShape { + match value.into() { + UntaggedValue::Primitive(p) => InlineShape::from_primitive(p), + UntaggedValue::Row(row) => InlineShape::from_dictionary(row), + UntaggedValue::Table(table) => InlineShape::from_table(table.iter()), + UntaggedValue::Error(_) => InlineShape::Error, + UntaggedValue::Block(_) => InlineShape::Block, } } - // pub fn format_for_column(self, column: impl Into) -> FormatInlineShape { - // FormatInlineShape { - // shape: self, - // column: Some(column.into()), - // } - // } + #[allow(unused)] + pub fn format_for_column(self, column: impl Into) -> FormatInlineShape { + FormatInlineShape { + shape: self, + column: Some(column.into()), + } + } pub fn format(self) -> FormatInlineShape { FormatInlineShape { @@ -298,7 +300,7 @@ impl InlineShape { } impl PrettyDebug for FormatInlineShape { - fn pretty_debug(&self) -> DebugDocBuilder { + fn pretty(&self) -> DebugDocBuilder { let column = &self.column; match &self.shape { @@ -323,10 +325,9 @@ impl PrettyDebug for FormatInlineShape { } } InlineShape::String(string) => b::primitive(format!("{}", string)), - InlineShape::ColumnPath(path) => b::intersperse( - path.iter().map(|member| member.pretty_debug()), - b::keyword("."), - ), + InlineShape::ColumnPath(path) => { + b::intersperse(path.iter().map(|member| member.pretty()), b::keyword(".")) + } InlineShape::Pattern(pattern) => b::primitive(pattern), InlineShape::Boolean(boolean) => b::primitive(match (boolean, column) { (true, None) => format!("Yes"), @@ -485,15 +486,15 @@ impl Value { impl Shape { pub fn for_value(value: &Value) -> Shape { - match value { - Value::Primitive(p) => Shape::Primitive(p.type_name()), - Value::Row(row) => Shape::for_dict(row), - Value::Table(table) => Shape::Table { + match &value.value { + UntaggedValue::Primitive(p) => Shape::Primitive(p.type_name()), + UntaggedValue::Row(row) => Shape::for_dict(row), + UntaggedValue::Table(table) => Shape::Table { from: 0, to: table.len(), }, - Value::Error(error) => Shape::Error(error.clone()), - Value::Block(block) => Shape::Block(block.clone()), + UntaggedValue::Error(error) => Shape::Error(error.clone()), + UntaggedValue::Block(block) => Shape::Block(block.clone()), } } @@ -558,7 +559,7 @@ impl Shape { .expect("Writing into a Vec can't fail"); let string = String::from_utf8_lossy(&out); - Value::string(string) + UntaggedValue::string(string).into_untagged_value() } } @@ -582,13 +583,13 @@ impl Shapes { .or_insert_with(|| vec![row]); } - pub fn to_values(&self) -> Vec> { + pub fn to_values(&self) -> Vec { if self.shapes.len() == 1 { let shape = self.shapes.keys().nth(0).unwrap(); vec![dict! { "type" => shape.to_value(), - "rows" => Value::string("all") + "rows" => UntaggedValue::string("all") }] } else { self.shapes @@ -598,7 +599,7 @@ impl Shapes { dict! { "type" => shape.to_value(), - "rows" => Value::string(format!("[ {} ]", rows)) + "rows" => UntaggedValue::string(format!("[ {} ]", rows)) } }) .collect() diff --git a/src/data/command.rs b/src/data/command.rs index 5993dda6f5..d47bc26e4c 100644 --- a/src/data/command.rs +++ b/src/data/command.rs @@ -4,43 +4,43 @@ use crate::parser::registry::{NamedType, PositionalType, Signature}; use crate::prelude::*; use std::ops::Deref; -pub(crate) fn command_dict(command: Arc, tag: impl Into) -> Tagged { +pub(crate) fn command_dict(command: Arc, tag: impl Into) -> Value { let tag = tag.into(); let mut cmd_dict = TaggedDictBuilder::new(&tag); - cmd_dict.insert("name", Value::string(command.name())); + cmd_dict.insert_untagged("name", UntaggedValue::string(command.name())); - cmd_dict.insert( + cmd_dict.insert_untagged( "type", - Value::string(match command.deref() { + UntaggedValue::string(match command.deref() { Command::WholeStream(_) => "Command", Command::PerItem(_) => "Filter", }), ); - cmd_dict.insert_tagged("signature", signature_dict(command.signature(), tag)); - cmd_dict.insert("usage", Value::string(command.usage())); + cmd_dict.insert_value("signature", signature_dict(command.signature(), tag)); + cmd_dict.insert_untagged("usage", UntaggedValue::string(command.usage())); - cmd_dict.into_tagged_value() + cmd_dict.into_value() } -fn for_spec(name: &str, ty: &str, required: bool, tag: impl Into) -> Tagged { +fn for_spec(name: &str, ty: &str, required: bool, tag: impl Into) -> Value { let tag = tag.into(); let mut spec = TaggedDictBuilder::new(tag); - spec.insert("name", Value::string(name)); - spec.insert("type", Value::string(ty)); - spec.insert( + spec.insert_untagged("name", UntaggedValue::string(name)); + spec.insert_untagged("type", UntaggedValue::string(ty)); + spec.insert_untagged( "required", - Value::string(if required { "yes" } else { "no" }), + UntaggedValue::string(if required { "yes" } else { "no" }), ); - spec.into_tagged_value() + spec.into_value() } -fn signature_dict(signature: Signature, tag: impl Into) -> Tagged { +fn signature_dict(signature: Signature, tag: impl Into) -> Value { let tag = tag.into(); let mut sig = TaggedListBuilder::new(&tag); @@ -50,21 +50,21 @@ fn signature_dict(signature: Signature, tag: impl Into) -> Tagged { PositionalType::Optional(_, _) => false, }; - sig.insert_tagged(for_spec(arg.0.name(), "argument", is_required, &tag)); + sig.push_value(for_spec(arg.0.name(), "argument", is_required, &tag)); } if let Some(_) = signature.rest_positional { let is_required = false; - sig.insert_tagged(for_spec("rest", "argument", is_required, &tag)); + sig.push_value(for_spec("rest", "argument", is_required, &tag)); } for (name, ty) in signature.named.iter() { match ty.0 { - NamedType::Mandatory(_) => sig.insert_tagged(for_spec(name, "flag", true, &tag)), - NamedType::Optional(_) => sig.insert_tagged(for_spec(name, "flag", false, &tag)), - NamedType::Switch => sig.insert_tagged(for_spec(name, "switch", false, &tag)), + NamedType::Mandatory(_) => sig.push_value(for_spec(name, "flag", true, &tag)), + NamedType::Optional(_) => sig.push_value(for_spec(name, "flag", false, &tag)), + NamedType::Switch => sig.push_value(for_spec(name, "switch", false, &tag)), } } - sig.into_tagged_value() + sig.into_value() } diff --git a/src/data/config.rs b/src/data/config.rs index 6ff26efcf7..8f74e7ff21 100644 --- a/src/data/config.rs +++ b/src/data/config.rs @@ -14,7 +14,7 @@ use std::path::{Path, PathBuf}; #[derive(Deserialize, Serialize)] struct Config { #[serde(flatten)] - extra: IndexMap>, + extra: IndexMap, } pub const APP_INFO: AppInfo = AppInfo { @@ -61,7 +61,7 @@ pub fn app_path(app_data_type: AppDataType, display: &str) -> Result, at: &Option, -) -> Result>, ShellError> { +) -> Result, ShellError> { let filename = default_path()?; let filename = match at { @@ -94,8 +94,8 @@ pub fn read( let value = convert_toml_value_to_nu_value(&parsed, tag); let tag = value.tag(); - match value.item { - Value::Row(Dictionary { entries }) => Ok(entries), + match value.value { + UntaggedValue::Row(Dictionary { entries }) => Ok(entries), other => Err(ShellError::type_error( "Dictionary", other.type_name().spanned(tag.span), @@ -103,14 +103,11 @@ pub fn read( } } -pub(crate) fn config(tag: impl Into) -> Result>, ShellError> { +pub(crate) fn config(tag: impl Into) -> Result, ShellError> { read(tag, &None) } -pub fn write( - config: &IndexMap>, - at: &Option, -) -> Result<(), ShellError> { +pub fn write(config: &IndexMap, at: &Option) -> Result<(), ShellError> { let filename = &mut default_path()?; let filename = match at { None => filename, @@ -121,8 +118,9 @@ pub fn write( } }; - let contents = - value_to_toml_value(&Value::Row(Dictionary::new(config.clone())).tagged_unknown())?; + let contents = value_to_toml_value( + &UntaggedValue::Row(Dictionary::new(config.clone())).into_untagged_value(), + )?; let contents = toml::to_string(&contents)?; diff --git a/src/data/dict.rs b/src/data/dict.rs index 9cdc070830..5f48a9a4b7 100644 --- a/src/data/dict.rs +++ b/src/data/dict.rs @@ -1,9 +1,10 @@ -use crate::data::{Primitive, Value}; +use crate::data::base::{Primitive, UntaggedValue, Value}; use crate::prelude::*; -use crate::traits::{DebugDocBuilder as b, PrettyDebug}; use derive_new::new; use getset::Getters; use indexmap::IndexMap; +use nu_source::Spanned; +use nu_source::{b, PrettyDebug}; use pretty::{BoxAllocator, DocAllocator}; use serde::{Deserialize, Serialize}; use std::cmp::{Ordering, PartialOrd}; @@ -11,41 +12,23 @@ use std::cmp::{Ordering, PartialOrd}; #[derive(Debug, Default, Eq, PartialEq, Serialize, Deserialize, Clone, Getters, new)] pub struct Dictionary { #[get = "pub"] - pub entries: IndexMap>, + pub entries: IndexMap, } #[derive(Debug, new)] struct DebugEntry<'a> { key: &'a str, - value: &'a Tagged, + value: &'a Value, } impl<'a> PrettyDebug for DebugEntry<'a> { - fn pretty_debug(&self) -> DebugDocBuilder { - (b::key(self.key.to_string()) + b::equals() + self.value.item.pretty_debug().as_value()) - .group() - // BoxAllocator - // .text(self.key.to_string()) - // .annotate(ShellAnnotation::style("key")) - // .append( - // BoxAllocator - // .text("=") - // .annotate(ShellAnnotation::style("equals")), - // ) - // .append({ - // self.value - // .item - // .pretty_debug() - // .inner - // .annotate(ShellAnnotation::style("value")) - // }) - // .group() - // .into() + fn pretty(&self) -> DebugDocBuilder { + (b::key(self.key.to_string()) + b::equals() + self.value.pretty().as_value()).group() } } impl PrettyDebug for Dictionary { - fn pretty_debug(&self) -> DebugDocBuilder { + fn pretty(&self) -> DebugDocBuilder { BoxAllocator .text("(") .append( @@ -73,15 +56,15 @@ impl PartialOrd for Dictionary { return this.partial_cmp(&that); } - let this: Vec<&Value> = self.entries.values().map(|v| v.item()).collect(); - let that: Vec<&Value> = self.entries.values().map(|v| v.item()).collect(); + let this: Vec<&Value> = self.entries.values().collect(); + let that: Vec<&Value> = self.entries.values().collect(); this.partial_cmp(&that) } } -impl From>> for Dictionary { - fn from(input: IndexMap>) -> Dictionary { +impl From> for Dictionary { + fn from(input: IndexMap) -> Dictionary { let mut out = IndexMap::default(); for (key, value) in input { @@ -101,8 +84,8 @@ impl Ord for Dictionary { return this.cmp(&that); } - let this: Vec<&Value> = self.entries.values().map(|v| v.item()).collect(); - let that: Vec<&Value> = self.entries.values().map(|v| v.item()).collect(); + let this: Vec<&Value> = self.entries.values().collect(); + let that: Vec<&Value> = self.entries.values().collect(); this.cmp(&that) } @@ -116,8 +99,8 @@ impl PartialOrd for Dictionary { impl PartialEq for Dictionary { fn eq(&self, other: &Value) -> bool { - match other { - Value::Row(d) => self == d, + match &other.value { + UntaggedValue::Row(d) => self == d, _ => false, } } @@ -127,7 +110,9 @@ impl Dictionary { pub fn get_data(&self, desc: &String) -> MaybeOwned<'_, Value> { match self.entries.get(desc) { Some(v) => MaybeOwned::Borrowed(v), - None => MaybeOwned::Owned(Value::Primitive(Primitive::Nothing)), + None => MaybeOwned::Owned( + UntaggedValue::Primitive(Primitive::Nothing).into_untagged_value(), + ), } } @@ -135,7 +120,7 @@ impl Dictionary { self.entries.keys() } - pub(crate) fn get_data_by_key(&self, name: Spanned<&str>) -> Option> { + pub(crate) fn get_data_by_key(&self, name: Spanned<&str>) -> Option { let result = self .entries .iter() @@ -144,13 +129,13 @@ impl Dictionary { Some( result - .item + .value .clone() - .tagged(Tag::new(result.anchor(), name.span)), + .into_value(Tag::new(result.anchor(), name.span)), ) } - pub(crate) fn get_mut_data_by_key(&mut self, name: &str) -> Option<&mut Tagged> { + pub(crate) fn get_mut_data_by_key(&mut self, name: &str) -> Option<&mut Value> { match self .entries .iter_mut() @@ -161,7 +146,7 @@ impl Dictionary { } } - pub(crate) fn insert_data_at_key(&mut self, name: &str, value: Tagged) { + pub(crate) fn insert_data_at_key(&mut self, name: &str, value: Value) { self.entries.insert(name.to_string(), value); } } @@ -169,7 +154,7 @@ impl Dictionary { #[derive(Debug)] pub struct TaggedListBuilder { tag: Tag, - pub list: Vec>, + pub list: Vec, } impl TaggedListBuilder { @@ -180,29 +165,33 @@ impl TaggedListBuilder { } } - pub fn push(&mut self, value: impl Into) { - self.list.push(value.into().tagged(&self.tag)); - } - - pub fn insert_tagged(&mut self, value: impl Into>) { + pub fn push_value(&mut self, value: impl Into) { self.list.push(value.into()); } - pub fn into_tagged_value(self) -> Tagged { - Value::Table(self.list).tagged(self.tag) + pub fn push_untagged(&mut self, value: impl Into) { + self.list.push(value.into().into_value(self.tag.clone())); + } + + pub fn into_value(self) -> Value { + UntaggedValue::Table(self.list).into_value(self.tag) + } + + pub fn into_untagged_value(self) -> UntaggedValue { + UntaggedValue::Table(self.list).into_value(self.tag).value } } -impl From for Tagged { - fn from(input: TaggedListBuilder) -> Tagged { - input.into_tagged_value() +impl From for Value { + fn from(input: TaggedListBuilder) -> Value { + input.into_value() } } #[derive(Debug)] pub struct TaggedDictBuilder { tag: Tag, - dict: IndexMap>, + dict: IndexMap, } impl TaggedDictBuilder { @@ -213,10 +202,10 @@ impl TaggedDictBuilder { } } - pub fn build(tag: impl Into, block: impl FnOnce(&mut TaggedDictBuilder)) -> Tagged { + pub fn build(tag: impl Into, block: impl FnOnce(&mut TaggedDictBuilder)) -> Value { let mut builder = TaggedDictBuilder::new(tag); block(&mut builder); - builder.into_tagged_value() + builder.into_value() } pub fn with_capacity(tag: impl Into, n: usize) -> TaggedDictBuilder { @@ -226,20 +215,22 @@ impl TaggedDictBuilder { } } - pub fn insert(&mut self, key: impl Into, value: impl Into) { - self.dict.insert(key.into(), value.into().tagged(&self.tag)); + pub fn insert_untagged(&mut self, key: impl Into, value: impl Into) { + self.dict + .insert(key.into(), value.into().into_value(&self.tag)); } - pub fn insert_tagged(&mut self, key: impl Into, value: impl Into>) { + pub fn insert_value(&mut self, key: impl Into, value: impl Into) { self.dict.insert(key.into(), value.into()); } - pub fn into_tagged_value(self) -> Tagged { - self.into_tagged_dict().map(Value::Row) + pub fn into_value(self) -> Value { + let tag = self.tag.clone(); + self.into_untagged_value().into_value(tag) } - pub fn into_tagged_dict(self) -> Tagged { - Dictionary { entries: self.dict }.tagged(self.tag) + pub fn into_untagged_value(self) -> UntaggedValue { + UntaggedValue::Row(Dictionary { entries: self.dict }) } pub fn is_empty(&self) -> bool { @@ -247,8 +238,8 @@ impl TaggedDictBuilder { } } -impl From for Tagged { - fn from(input: TaggedDictBuilder) -> Tagged { - input.into_tagged_value() +impl From for Value { + fn from(input: TaggedDictBuilder) -> Value { + input.into_value() } } diff --git a/src/data/files.rs b/src/data/files.rs index d89887463c..d7ae1ace7e 100644 --- a/src/data/files.rs +++ b/src/data/files.rs @@ -14,9 +14,9 @@ pub(crate) fn dir_entry_dict( metadata: &std::fs::Metadata, tag: impl Into, full: bool, -) -> Result, ShellError> { +) -> Result { let mut dict = TaggedDictBuilder::new(tag); - dict.insert("name", Value::string(filename.to_string_lossy())); + dict.insert_untagged("name", UntaggedValue::string(filename.to_string_lossy())); let kind = if metadata.is_dir() { FileType::Directory @@ -26,38 +26,41 @@ pub(crate) fn dir_entry_dict( FileType::Symlink }; - dict.insert("type", Value::string(format!("{:?}", kind))); + dict.insert_untagged("type", UntaggedValue::string(format!("{:?}", kind))); if full { - dict.insert( + dict.insert_untagged( "readonly", - Value::boolean(metadata.permissions().readonly()), + UntaggedValue::boolean(metadata.permissions().readonly()), ); #[cfg(unix)] { use std::os::unix::fs::PermissionsExt; let mode = metadata.permissions().mode(); - dict.insert("mode", Value::string(umask::Mode::from(mode).to_string())); + dict.insert( + "mode", + UntaggedValue::string(umask::Mode::from(mode).to_string()), + ); } } - dict.insert("size", Value::bytes(metadata.len() as u64)); + dict.insert_untagged("size", UntaggedValue::bytes(metadata.len() as u64)); match metadata.created() { - Ok(c) => dict.insert("created", Value::system_date(c)), + Ok(c) => dict.insert_untagged("created", UntaggedValue::system_date(c)), Err(_) => {} } match metadata.accessed() { - Ok(a) => dict.insert("accessed", Value::system_date(a)), + Ok(a) => dict.insert_untagged("accessed", UntaggedValue::system_date(a)), Err(_) => {} } match metadata.modified() { - Ok(m) => dict.insert("modified", Value::system_date(m)), + Ok(m) => dict.insert_untagged("modified", UntaggedValue::system_date(m)), Err(_) => {} } - Ok(dict.into_tagged_value()) + Ok(dict.into_value()) } diff --git a/src/data/into.rs b/src/data/into.rs index 3d764fa0c1..1fe6c52cfd 100644 --- a/src/data/into.rs +++ b/src/data/into.rs @@ -1,22 +1,13 @@ -use crate::data::{Primitive, Value}; -use crate::prelude::*; +use crate::data::base::{Primitive, UntaggedValue}; -impl From for Value { - fn from(input: Primitive) -> Value { - Value::Primitive(input) +impl From for UntaggedValue { + fn from(input: Primitive) -> UntaggedValue { + UntaggedValue::Primitive(input) } } -impl From for Value { - fn from(input: String) -> Value { - Value::Primitive(Primitive::String(input)) - } -} - -impl> Tagged { - pub fn into_tagged_value(self) -> Tagged { - let value_tag = self.tag(); - let value = self.item.into(); - value.tagged(value_tag) +impl From for UntaggedValue { + fn from(input: String) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::String(input)) } } diff --git a/src/data/process.rs b/src/data/process.rs index cf6a2fb148..0e166d2f90 100644 --- a/src/data/process.rs +++ b/src/data/process.rs @@ -3,27 +3,27 @@ use crate::prelude::*; use itertools::join; use sysinfo::ProcessExt; -pub(crate) fn process_dict(proc: &sysinfo::Process, tag: impl Into) -> Tagged { +pub(crate) fn process_dict(proc: &sysinfo::Process, tag: impl Into) -> Value { let mut dict = TaggedDictBuilder::new(tag); let cmd = proc.cmd(); let cmd_value = if cmd.len() == 0 { - Value::nothing() + UntaggedValue::nothing() } else { - Value::string(join(cmd, "")) + UntaggedValue::string(join(cmd, "")) }; - dict.insert("pid", Value::int(proc.pid() as i64)); - dict.insert("status", Value::string(proc.status().to_string())); - dict.insert("cpu", Value::number(proc.cpu_usage())); + dict.insert("pid", UntaggedValue::int(proc.pid() as i64)); + dict.insert("status", UntaggedValue::string(proc.status().to_string())); + dict.insert("cpu", UntaggedValue::number(proc.cpu_usage())); match cmd_value { - Value::Primitive(Primitive::Nothing) => { - dict.insert("name", Value::string(proc.name())); + UntaggedValue::Primitive(Primitive::Nothing) => { + dict.insert("name", UntaggedValue::string(proc.name())); } _ => dict.insert("name", cmd_value), } - dict.into_tagged_value() + dict.into_value() } diff --git a/src/data/types.rs b/src/data/types.rs index 9ac4fc139e..ce5684d4eb 100644 --- a/src/data/types.rs +++ b/src/data/types.rs @@ -1,12 +1,13 @@ use crate::prelude::*; use log::trace; +use nu_source::Tagged; pub trait ExtractType: Sized { - fn extract(value: &Tagged) -> Result; + fn extract(value: &Value) -> Result; } impl ExtractType for Tagged { - fn extract(value: &Tagged) -> Result, ShellError> { + fn extract(value: &Value) -> Result, ShellError> { let name = std::any::type_name::(); trace!(" Extracting {:?} for Tagged<{}>", value, name); @@ -15,16 +16,16 @@ impl ExtractType for Tagged { } impl ExtractType for bool { - fn extract(value: &Tagged) -> Result { + fn extract(value: &Value) -> Result { trace!("Extracting {:?} for bool", value); match &value { - Tagged { - item: Value::Primitive(Primitive::Boolean(b)), + Value { + value: UntaggedValue::Primitive(Primitive::Boolean(b)), .. } => Ok(*b), - Tagged { - item: Value::Primitive(Primitive::Nothing), + Value { + value: UntaggedValue::Primitive(Primitive::Nothing), .. } => Ok(false), other => Err(ShellError::type_error( @@ -36,12 +37,12 @@ impl ExtractType for bool { } impl ExtractType for std::path::PathBuf { - fn extract(value: &Tagged) -> Result { + fn extract(value: &Value) -> Result { trace!("Extracting {:?} for PathBuf", value); match &value { - Tagged { - item: Value::Primitive(Primitive::Path(p)), + Value { + value: UntaggedValue::Primitive(Primitive::Path(p)), .. } => Ok(p.clone()), other => Err(ShellError::type_error( @@ -53,12 +54,12 @@ impl ExtractType for std::path::PathBuf { } impl ExtractType for i64 { - fn extract(value: &Tagged) -> Result { + fn extract(value: &Value) -> Result { trace!("Extracting {:?} for i64", value); match &value { - &Tagged { - item: Value::Primitive(Primitive::Int(int)), + &Value { + value: UntaggedValue::Primitive(Primitive::Int(int)), .. } => Ok(int.tagged(&value.tag).coerce_into("converting to i64")?), other => Err(ShellError::type_error( @@ -70,12 +71,12 @@ impl ExtractType for i64 { } impl ExtractType for u64 { - fn extract(value: &Tagged) -> Result { + fn extract(value: &Value) -> Result { trace!("Extracting {:?} for u64", value); match &value { - &Tagged { - item: Value::Primitive(Primitive::Int(int)), + &Value { + value: UntaggedValue::Primitive(Primitive::Int(int)), .. } => Ok(int.tagged(&value.tag).coerce_into("converting to u64")?), other => Err(ShellError::type_error( @@ -87,12 +88,12 @@ impl ExtractType for u64 { } impl ExtractType for String { - fn extract(value: &Tagged) -> Result { + fn extract(value: &Value) -> Result { trace!("Extracting {:?} for String", value); match value { - Tagged { - item: Value::Primitive(Primitive::String(string)), + Value { + value: UntaggedValue::Primitive(Primitive::String(string)), .. } => Ok(string.clone()), other => Err(ShellError::type_error( diff --git a/src/errors.rs b/src/errors.rs index 99e6bef726..ad2d199f5b 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,29 +1,29 @@ use crate::prelude::*; -use crate::parser::parse::parser::TracableContext; use ansi_term::Color; use derive_new::new; use language_reporting::{Diagnostic, Label, Severity}; +use nu_source::{Spanned, TracableContext}; use serde::{Deserialize, Serialize}; use std::fmt; use std::ops::Range; +// TODO: Spanned -> HasSpanAndItem ? + #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash, Serialize, Deserialize)] pub enum Description { Source(Spanned), Synthetic(String), } -impl> Into for Spanned { - fn into(self) -> Description { - Description::Source(self.map(|s| s.into())) - } -} - impl Description { + fn from_spanned(item: Spanned>) -> Description { + Description::Source(item.map(|s| s.into())) + } + fn into_label(self) -> Result, String> { match self { - Description::Source(s) => Ok(Label::new_primary(s.span()).with_message(s.item)), + Description::Source(s) => Ok(Label::new_primary(s.span).with_message(s.item)), Description::Synthetic(s) => Err(s), } } @@ -106,12 +106,6 @@ pub struct ShellError { cause: Option>, } -impl FormatDebug for ShellError { - fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result { - self.error.fmt_debug(f, source) - } -} - impl serde::de::Error for ShellError { fn custom(msg: T) -> Self where @@ -138,8 +132,8 @@ impl ShellError { expr: Spanned>, ) -> ShellError { ProximateShellError::MissingProperty { - subpath: subpath.into(), - expr: expr.into(), + subpath: Description::from_spanned(subpath), + expr: Description::from_spanned(expr), } .start() } @@ -149,7 +143,7 @@ impl ShellError { integer: impl Into, ) -> ShellError { ProximateShellError::InvalidIntegerIndex { - subpath: subpath.into(), + subpath: Description::from_spanned(subpath), integer: integer.into(), } .start() @@ -172,12 +166,12 @@ impl ShellError { pub(crate) fn range_error( expected: impl Into, - actual: &Tagged, + actual: &Spanned, operation: impl Into, ) -> ShellError { ProximateShellError::RangeError { kind: expected.into(), - actual_kind: format!("{:?}", actual.item).spanned(actual.span()), + actual_kind: format!("{:?}", actual.item).spanned(actual.span), operation: operation.into(), } .start() @@ -201,14 +195,6 @@ impl ShellError { .start() } - pub(crate) fn missing_value(span: Option, reason: impl Into) -> ShellError { - ProximateShellError::MissingValue { - span, - reason: reason.into(), - } - .start() - } - pub(crate) fn argument_error( command: Spanned>, kind: ArgumentError, @@ -404,28 +390,28 @@ impl ShellError { pub fn labeled_error( msg: impl Into, label: impl Into, - tag: impl Into, + span: impl Into, ) -> ShellError { ShellError::diagnostic( Diagnostic::new(Severity::Error, msg.into()) - .with_label(Label::new_primary(tag.into().span).with_message(label.into())), + .with_label(Label::new_primary(span.into()).with_message(label.into())), ) } pub fn labeled_error_with_secondary( msg: impl Into, primary_label: impl Into, - primary_span: impl Into, + primary_span: impl Into, secondary_label: impl Into, - secondary_span: impl Into, + secondary_span: impl Into, ) -> ShellError { ShellError::diagnostic( Diagnostic::new_error(msg.into()) .with_label( - Label::new_primary(primary_span.into().span).with_message(primary_label.into()), + Label::new_primary(primary_span.into()).with_message(primary_label.into()), ) .with_label( - Label::new_secondary(secondary_span.into().span) + Label::new_secondary(secondary_span.into()) .with_message(secondary_label.into()), ), ) @@ -573,13 +559,6 @@ impl ProximateShellError { // } } -impl FormatDebug for ProximateShellError { - fn fmt_debug(&self, f: &mut DebugFormatter, _source: &str) -> fmt::Result { - // TODO: Custom debug for inner spans - write!(f, "{:?}", self) - } -} - #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ShellDiagnostic { pub(crate) diagnostic: Diagnostic, @@ -690,18 +669,6 @@ impl std::convert::From> for ShellError } } -pub trait ShellErrorUtils { - fn unwrap_error(self, desc: impl Into) -> Result; -} - -impl ShellErrorUtils> for Option> { - fn unwrap_error(self, desc: impl Into) -> Result, ShellError> { - match self { - Some(value) => Ok(value), - None => Err(ShellError::missing_value(None, desc.into())), - } - } -} pub trait CoerceInto { fn coerce_into(self, operation: impl Into) -> Result; } @@ -718,26 +685,26 @@ macro_rules! ranged_int { } } - impl CoerceInto<$ty> for Tagged { + impl CoerceInto<$ty> for nu_source::Tagged { fn coerce_into(self, operation: impl Into) -> Result<$ty, ShellError> { match self.$op() { Some(v) => Ok(v), None => Err(ShellError::range_error( $ty::to_expected_range(), - &self, + &self.item.spanned(self.tag.span), operation.into(), )), } } } - impl CoerceInto<$ty> for Tagged<&BigInt> { + impl CoerceInto<$ty> for nu_source::Tagged<&BigInt> { fn coerce_into(self, operation: impl Into) -> Result<$ty, ShellError> { match self.$op() { Some(v) => Ok(v), None => Err(ShellError::range_error( $ty::to_expected_range(), - &self, + &self.item.spanned(self.tag.span), operation.into(), )), } @@ -763,26 +730,26 @@ macro_rules! ranged_decimal { } } - impl CoerceInto<$ty> for Tagged { + impl CoerceInto<$ty> for nu_source::Tagged { fn coerce_into(self, operation: impl Into) -> Result<$ty, ShellError> { match self.$op() { Some(v) => Ok(v), None => Err(ShellError::range_error( $ty::to_expected_range(), - &self, + &self.item.spanned(self.tag.span), operation.into(), )), } } } - impl CoerceInto<$ty> for Tagged<&BigDecimal> { + impl CoerceInto<$ty> for nu_source::Tagged<&BigDecimal> { fn coerce_into(self, operation: impl Into) -> Result<$ty, ShellError> { match self.$op() { Some(v) => Ok(v), None => Err(ShellError::range_error( $ty::to_expected_range(), - &self, + &self.item.spanned(self.tag.span), operation.into(), )), } diff --git a/src/evaluate/evaluator.rs b/src/evaluate/evaluator.rs index 1930b64c82..af7cc5350f 100644 --- a/src/evaluate/evaluator.rs +++ b/src/evaluate/evaluator.rs @@ -1,23 +1,24 @@ use crate::data::base::Block; use crate::errors::ArgumentError; -use crate::parser::hir::path::{ColumnPath, RawPathMember}; +use crate::parser::hir::path::{ColumnPath, UnspannedPathMember}; use crate::parser::{ hir::{self, Expression, RawExpression}, - CommandRegistry, Text, + CommandRegistry, }; use crate::prelude::*; use crate::TaggedDictBuilder; use indexmap::IndexMap; use log::trace; +use nu_source::Text; use std::fmt; pub struct Scope { - it: Tagged, - vars: IndexMap>, + it: Value, + vars: IndexMap, } impl Scope { - pub fn new(it: Tagged) -> Scope { + pub fn new(it: Value) -> Scope { Scope { it, vars: IndexMap::new(), @@ -28,8 +29,8 @@ impl Scope { impl fmt::Display for Scope { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_map() - .entry(&"$it", &format!("{:?}", self.it.item)) - .entries(self.vars.iter().map(|(k, v)| (k, &v.item))) + .entry(&"$it", &format!("{:?}", self.it.value)) + .entries(self.vars.iter().map(|(k, v)| (k, &v.value))) .finish() } } @@ -37,12 +38,12 @@ impl fmt::Display for Scope { impl Scope { pub(crate) fn empty() -> Scope { Scope { - it: Value::nothing().tagged_unknown(), + it: UntaggedValue::nothing().into_untagged_value(), vars: IndexMap::new(), } } - pub(crate) fn it_value(value: Tagged) -> Scope { + pub(crate) fn it_value(value: Value) -> Scope { Scope { it: value, vars: IndexMap::new(), @@ -55,20 +56,20 @@ pub(crate) fn evaluate_baseline_expr( registry: &CommandRegistry, scope: &Scope, source: &Text, -) -> Result, ShellError> { +) -> Result { let tag = Tag { span: expr.span, anchor: None, }; - match &expr.item { - RawExpression::Literal(literal) => Ok(evaluate_literal(literal.tagged(tag), source)), + match &expr.expr { + RawExpression::Literal(literal) => Ok(evaluate_literal(literal, source)), RawExpression::ExternalWord => Err(ShellError::argument_error( "Invalid external word".spanned(tag.span), ArgumentError::InvalidExternalWord, )), - RawExpression::FilePath(path) => Ok(Value::path(path.clone()).tagged(tag)), + RawExpression::FilePath(path) => Ok(UntaggedValue::path(path.clone()).into_value(tag)), RawExpression::Synthetic(hir::Synthetic::String(s)) => { - Ok(Value::string(s).tagged_unknown()) + Ok(UntaggedValue::string(s).into_untagged_value()) } RawExpression::Variable(var) => evaluate_reference(var, scope, source, tag), RawExpression::Command(_) => evaluate_command(tag, scope, source), @@ -77,10 +78,10 @@ pub(crate) fn evaluate_baseline_expr( let left = evaluate_baseline_expr(binary.left(), registry, scope, source)?; let right = evaluate_baseline_expr(binary.right(), registry, scope, source)?; - trace!("left={:?} right={:?}", left.item, right.item); + trace!("left={:?} right={:?}", left.value, right.value); - match left.compare(binary.op(), &*right) { - Ok(result) => Ok(Value::boolean(result).tagged(tag)), + match left.compare(binary.op(), &right) { + Ok(result) => Ok(UntaggedValue::boolean(result).into_value(tag)), Err((left_type, right_type)) => Err(ShellError::coerce_error( left_type.spanned(binary.left().span), right_type.spanned(binary.right().span), @@ -95,10 +96,13 @@ pub(crate) fn evaluate_baseline_expr( exprs.push(expr); } - Ok(Value::Table(exprs).tagged(tag)) + Ok(UntaggedValue::Table(exprs).into_value(tag)) } RawExpression::Block(block) => { - Ok(Value::Block(Block::new(block.clone(), source.clone(), tag.clone())).tagged(&tag)) + Ok( + UntaggedValue::Block(Block::new(block.clone(), source.clone(), tag.clone())) + .into_value(&tag), + ) } RawExpression::Path(path) => { let value = evaluate_baseline_expr(path.head(), registry, scope, source)?; @@ -111,7 +115,7 @@ pub(crate) fn evaluate_baseline_expr( Err(err) => { let possibilities = item.data_descriptors(); - if let RawPathMember::String(name) = &member.item { + if let UnspannedPathMember::String(name) = &member.unspanned { let mut possible_matches: Vec<_> = possibilities .iter() .map(|x| (natural::distance::levenshtein_distance(x, &name), x)) @@ -131,35 +135,40 @@ pub(crate) fn evaluate_baseline_expr( } } Ok(next) => { - item = next.clone().item.tagged(&tag); + item = next.clone().value.into_value(&tag); } }; } - Ok(item.item().clone().tagged(tag)) + Ok(item.value.clone().into_value(tag)) } RawExpression::Boolean(_boolean) => unimplemented!(), } } -fn evaluate_literal(literal: Tagged<&hir::Literal>, source: &Text) -> Tagged { - let result = match literal.item { - hir::Literal::ColumnPath(path) => { +fn evaluate_literal(literal: &hir::Literal, source: &Text) -> Value { + match &literal.literal { + hir::RawLiteral::ColumnPath(path) => { let members = path .iter() .map(|member| member.to_path_member(source)) .collect(); - Value::Primitive(Primitive::ColumnPath(ColumnPath::new(members))) + UntaggedValue::Primitive(Primitive::ColumnPath(ColumnPath::new(members))) + .into_value(&literal.span) } - hir::Literal::Number(int) => int.into(), - hir::Literal::Size(int, unit) => unit.compute(int), - hir::Literal::String(tag) => Value::string(tag.slice(source)), - hir::Literal::GlobPattern(pattern) => Value::pattern(pattern), - hir::Literal::Bare => Value::string(literal.tag().slice(source)), - }; - - literal.map(|_| result) + hir::RawLiteral::Number(int) => UntaggedValue::number(int.clone()).into_value(literal.span), + hir::RawLiteral::Size(int, unit) => unit.compute(&int).into_value(literal.span), + hir::RawLiteral::String(tag) => { + UntaggedValue::string(tag.slice(source)).into_value(literal.span) + } + hir::RawLiteral::GlobPattern(pattern) => { + UntaggedValue::pattern(pattern).into_value(literal.span) + } + hir::RawLiteral::Bare => { + UntaggedValue::string(literal.span.slice(source)).into_value(literal.span) + } + } } fn evaluate_reference( @@ -167,41 +176,41 @@ fn evaluate_reference( scope: &Scope, source: &Text, tag: Tag, -) -> Result, ShellError> { +) -> Result { trace!("Evaluating {} with Scope {}", name, scope); match name { - hir::Variable::It(_) => Ok(scope.it.item.clone().tagged(tag)), + hir::Variable::It(_) => Ok(scope.it.value.clone().into_value(tag)), hir::Variable::Other(inner) => match inner.slice(source) { x if x == "nu:env" => { let mut dict = TaggedDictBuilder::new(&tag); for v in std::env::vars() { if v.0 != "PATH" && v.0 != "Path" { - dict.insert(v.0, Value::string(v.1)); + dict.insert_untagged(v.0, UntaggedValue::string(v.1)); } } - Ok(dict.into_tagged_value()) + Ok(dict.into_value()) } x if x == "nu:config" => { let config = crate::data::config::read(tag.clone(), &None)?; - Ok(Value::row(config).tagged(tag)) + Ok(UntaggedValue::row(config).into_value(tag)) } x if x == "nu:path" => { let mut table = vec![]; match std::env::var_os("PATH") { Some(paths) => { for path in std::env::split_paths(&paths) { - table.push(Value::path(path).tagged(&tag)); + table.push(UntaggedValue::path(path).into_value(&tag)); } } _ => {} } - Ok(Value::table(&table).tagged(tag)) + Ok(UntaggedValue::table(&table).into_value(tag)) } x => Ok(scope .vars .get(x) .map(|v| v.clone()) - .unwrap_or_else(|| Value::nothing().tagged(tag))), + .unwrap_or_else(|| UntaggedValue::nothing().into_value(tag))), }, } } @@ -210,13 +219,13 @@ fn evaluate_external( external: &hir::ExternalCommand, _scope: &Scope, _source: &Text, -) -> Result, ShellError> { +) -> Result { Err(ShellError::syntax_error( "Unexpected external command".spanned(*external.name()), )) } -fn evaluate_command(tag: Tag, _scope: &Scope, _source: &Text) -> Result, ShellError> { +fn evaluate_command(tag: Tag, _scope: &Scope, _source: &Text) -> Result { Err(ShellError::syntax_error( "Unexpected command".spanned(tag.span), )) diff --git a/src/format/generic.rs b/src/format/generic.rs index d9dc8ead20..3379325113 100644 --- a/src/format/generic.rs +++ b/src/format/generic.rs @@ -11,9 +11,10 @@ pub struct GenericView<'value> { impl RenderView for GenericView<'_> { fn render_view(&self, host: &mut dyn Host) -> Result<(), ShellError> { - match self.value { - Value::Primitive(p) => Ok(host.stdout(&p.format(None))), - Value::Table(l) => { + let tag = &self.value.tag; + match &self.value.value { + UntaggedValue::Primitive(p) => Ok(host.stdout(&p.format(None))), + UntaggedValue::Table(l) => { let view = TableView::from_list(l, 0); if let Some(view) = view { @@ -23,20 +24,20 @@ impl RenderView for GenericView<'_> { Ok(()) } - o @ Value::Row(_) => { - let view = EntriesView::from_value(o); + o @ UntaggedValue::Row(_) => { + let view = EntriesView::from_value(&o.clone().into_value(tag)); view.render_view(host)?; Ok(()) } - b @ Value::Block(_) => { + b @ UntaggedValue::Block(_) => { let printed = b.format_leaf().plain_string(host.width()); - let view = EntriesView::from_value(&Value::string(printed)); + let view = EntriesView::from_value(&UntaggedValue::string(printed).into_value(tag)); view.render_view(host)?; Ok(()) } - Value::Error(e) => Err(e.clone()), + UntaggedValue::Error(e) => Err(e.clone()), } } } diff --git a/src/format/table.rs b/src/format/table.rs index 2d337260c8..e956f171ec 100644 --- a/src/format/table.rs +++ b/src/format/table.rs @@ -1,8 +1,8 @@ use crate::data::Value; use crate::format::RenderView; use crate::prelude::*; -use crate::traits::PrettyDebug; use derive_new::new; +use nu_source::PrettyDebug; use textwrap::fill; use prettytable::format::{FormatBuilder, LinePosition, LineSeparator}; @@ -23,7 +23,7 @@ enum TableMode { } impl TableView { - fn merge_descriptors(values: &[Tagged]) -> Vec { + fn merge_descriptors(values: &[Value]) -> Vec { let mut ret: Vec = vec![]; let value_column = "".to_string(); for value in values { @@ -44,7 +44,7 @@ impl TableView { ret } - pub fn from_list(values: &[Tagged], starting_idx: usize) -> Option { + pub fn from_list(values: &[Value], starting_idx: usize) -> Option { if values.len() == 0 { return None; } @@ -63,42 +63,30 @@ impl TableView { .map(|d| { if d == "" { match value { - Tagged { - item: Value::Row(..), + Value { + value: UntaggedValue::Row(..), .. } => ( - Value::nothing() - .format_leaf() - .pretty_debug() - .plain_string(100000), - Value::nothing().style_leaf(), - ), - _ => ( - value.format_leaf().pretty_debug().plain_string(100000), - value.style_leaf(), + UntaggedValue::nothing().format_leaf().plain_string(100000), + UntaggedValue::nothing().style_leaf(), ), + _ => (value.format_leaf().plain_string(100000), value.style_leaf()), } } else { match value { - Tagged { - item: Value::Row(..), + Value { + value: UntaggedValue::Row(..), .. } => { let data = value.get_data(d); ( - data.borrow() - .format_leaf() - .pretty_debug() - .plain_string(100000), + data.borrow().format_leaf().plain_string(100000), data.borrow().style_leaf(), ) } _ => ( - Value::nothing() - .format_leaf() - .pretty_debug() - .plain_string(100000), - Value::nothing().style_leaf(), + UntaggedValue::nothing().format_leaf().plain_string(100000), + UntaggedValue::nothing().style_leaf(), ), } } diff --git a/src/lib.rs b/src/lib.rs index 13366dbd18..6da0736934 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,23 +24,17 @@ mod traits; mod utils; pub use crate::commands::command::{CallInfo, ReturnSuccess, ReturnValue}; -pub use crate::context::AnchorLocation; pub use crate::env::host::BasicHost; -pub use crate::parser::hir::path::{ColumnPath, PathMember, RawPathMember}; +pub use crate::parser::hir::path::{ColumnPath, PathMember, UnspannedPathMember}; pub use crate::parser::hir::SyntaxShape; pub use crate::parser::parse::token_tree_builder::TokenTreeBuilder; pub use crate::plugin::{serve_plugin, Plugin}; -pub use crate::traits::{DebugFormatter, FormatDebug, ShellTypeName, SpannedTypeName, ToDebug}; +pub use crate::traits::{ShellTypeName, SpannedTypeName}; pub use crate::utils::{did_you_mean, AbsoluteFile, AbsolutePath, RelativePath}; pub use cli::cli; -pub use data::base::{Primitive, Value}; +pub use data::base::{Primitive, UntaggedValue, Value}; pub use data::config::{config_path, APP_INFO}; pub use data::dict::{Dictionary, TaggedDictBuilder, TaggedListBuilder}; -pub use data::meta::{ - span_for_spanned_list, tag_for_tagged_list, HasFallibleSpan, HasSpan, Span, Spanned, - SpannedItem, Tag, Tagged, TaggedItem, -}; pub use errors::{CoerceInto, ShellError}; pub use num_traits::cast::ToPrimitive; -pub use parser::parse::text::Text; pub use parser::registry::{EvaluatedArgs, NamedType, PositionalType, Signature}; diff --git a/src/parser.rs b/src/parser.rs index 003b8426c0..597c069a1c 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -14,13 +14,14 @@ pub(crate) use parse::call_node::CallNode; pub(crate) use parse::files::Files; pub(crate) use parse::flag::{Flag, FlagKind}; pub(crate) use parse::operator::Operator; -pub(crate) use parse::parser::{nom_input, pipeline}; -pub(crate) use parse::text::Text; +pub(crate) use parse::parser::pipeline; pub(crate) use parse::token_tree::{DelimitedNode, Delimiter, TokenNode}; -pub(crate) use parse::tokens::{RawNumber, RawToken}; +pub(crate) use parse::tokens::{RawNumber, UnspannedToken}; pub(crate) use parse::unit::Unit; pub(crate) use registry::CommandRegistry; +use nu_source::nom_input; + pub fn parse(input: &str) -> Result { let _ = pretty_env_logger::try_init(); diff --git a/src/parser/debug.rs b/src/parser/debug.rs index 739d2264db..cf6770c6f9 100644 --- a/src/parser/debug.rs +++ b/src/parser/debug.rs @@ -1,4 +1,4 @@ -use crate::traits::ShellAnnotation; +use nu_source::ShellAnnotation; use pretty::{Render, RenderAnnotated}; use std::io; use termcolor::WriteColor; diff --git a/src/parser/deserializer.rs b/src/parser/deserializer.rs index 0c027c7097..5121e08d70 100644 --- a/src/parser/deserializer.rs +++ b/src/parser/deserializer.rs @@ -1,13 +1,15 @@ +use crate::data::base::Block; use crate::prelude::*; use crate::ColumnPath; use log::trace; +use nu_source::Tagged; use serde::de; use std::path::PathBuf; #[derive(Debug)] pub struct DeserializerItem<'de> { key_struct_field: Option<(String, &'de str)>, - val: Tagged, + val: Value, } pub struct ConfigDeserializer<'de> { @@ -27,7 +29,7 @@ impl<'de> ConfigDeserializer<'de> { } } - pub fn push_val(&mut self, val: Tagged) { + pub fn push_val(&mut self, val: Value) { self.stack.push(DeserializerItem { key_struct_field: None, val, @@ -35,10 +37,10 @@ impl<'de> ConfigDeserializer<'de> { } pub fn push(&mut self, name: &'static str) -> Result<(), ShellError> { - let value: Option> = if name == "rest" { + let value: Option = if name == "rest" { let positional = self.call.args.slice_from(self.position); self.position += positional.len(); - Some(Value::Table(positional).tagged_unknown()) // TODO: correct tag + Some(UntaggedValue::Table(positional).into_untagged_value()) // TODO: correct tag } else { if self.call.args.has(name) { self.call.args.get(name).map(|x| x.clone()) @@ -53,7 +55,7 @@ impl<'de> ConfigDeserializer<'de> { self.stack.push(DeserializerItem { key_struct_field: Some((name.to_string(), name)), - val: value.unwrap_or_else(|| Value::nothing().tagged(&self.call.name_tag)), + val: value.unwrap_or_else(|| UntaggedValue::nothing().into_value(&self.call.name_tag)), }); Ok(()) @@ -90,12 +92,12 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut ConfigDeserializer<'de> { trace!("Extracting {:?} for bool", value.val); match &value.val { - Tagged { - item: Value::Primitive(Primitive::Boolean(b)), + Value { + value: UntaggedValue::Primitive(Primitive::Boolean(b)), .. } => visitor.visit_bool(*b), - Tagged { - item: Value::Primitive(Primitive::Nothing), + Value { + value: UntaggedValue::Primitive(Primitive::Nothing), .. } => visitor.visit_bool(false), other => Err(ShellError::type_error( @@ -202,8 +204,8 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut ConfigDeserializer<'de> { let value = self.top(); let name = std::any::type_name::(); trace!("