mirror of
https://github.com/nushell/nushell.git
synced 2024-11-25 01:43:47 +01:00
Extract nu_source into a crate
This commit extracts Tag, Span, Text, as well as source-related debug facilities into a new crate called nu_source. This change is much bigger than one might have expected because the previous code relied heavily on implementing inherent methods on `Tagged<T>` and `Spanned<T>`, which is no longer possible. As a result, this change creates more concrete types instead of using `Tagged<T>`. One notable example: Tagged<Value> became Value, and Value became UntaggedValue. This change clarifies the intent of the code in many places, but it does make it a big change.
This commit is contained in:
parent
fe53c37654
commit
f70c6d5d48
15
Cargo.lock
generated
15
Cargo.lock
generated
@ -1704,6 +1704,7 @@ dependencies = [
|
|||||||
"nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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-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)",
|
"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-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)",
|
"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)",
|
"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)",
|
"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]]
|
[[package]]
|
||||||
name = "num-bigint"
|
name = "num-bigint"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
|
@ -11,9 +11,15 @@ repository = "https://github.com/nushell/nushell"
|
|||||||
homepage = "https://www.nushell.sh"
|
homepage = "https://www.nushell.sh"
|
||||||
documentation = "https://book.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
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
nu-source = { path = "./crates/nu-source" }
|
||||||
|
|
||||||
rustyline = "5.0.4"
|
rustyline = "5.0.4"
|
||||||
chrono = { version = "0.4.9", features = ["serde"] }
|
chrono = { version = "0.4.9", features = ["serde"] }
|
||||||
derive-new = "0.5.8"
|
derive-new = "0.5.8"
|
||||||
@ -80,7 +86,7 @@ strip-ansi-escapes = "0.1.0"
|
|||||||
calamine = "0.16"
|
calamine = "0.16"
|
||||||
umask = "0.1"
|
umask = "0.1"
|
||||||
futures-util = "0.3.0"
|
futures-util = "0.3.0"
|
||||||
pretty = { version = "0.5.2" }
|
pretty = "0.5.2"
|
||||||
termcolor = "1.0.5"
|
termcolor = "1.0.5"
|
||||||
console = "0.9.1"
|
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 }
|
image = { version = "0.22.2", default_features = false, features = ["png_codec", "jpeg"], optional = true }
|
||||||
starship = { version = "0.26.4", optional = true}
|
starship = { version = "0.26.4", optional = true}
|
||||||
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["textview", "sys", "ps"]
|
default = ["textview", "sys", "ps"]
|
||||||
raw-key = ["rawkey", "neso"]
|
raw-key = ["rawkey", "neso"]
|
||||||
|
50
TODO.md
Normal file
50
TODO.md
Normal file
@ -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<Value> = input.values.collect().await;
|
||||||
|
|
||||||
|
let mut concat_string = String::new();
|
||||||
|
let mut latest_tag: Option<Tag> = 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
|
18
crates/nu-source/Cargo.toml
Normal file
18
crates/nu-source/Cargo.toml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
[package]
|
||||||
|
name = "nu-source"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Yehuda Katz <wycats@gmail.com>"]
|
||||||
|
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"
|
15
crates/nu-source/src/lib.rs
Normal file
15
crates/nu-source/src/lib.rs
Normal file
@ -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};
|
@ -1,13 +1,24 @@
|
|||||||
use crate::context::AnchorLocation;
|
use crate::pretty::{b, DebugDocBuilder, PrettyDebugWithSource};
|
||||||
use crate::parser::parse::parser::TracableContext;
|
use crate::text::Text;
|
||||||
use crate::prelude::*;
|
use crate::tracable::TracableContext;
|
||||||
|
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use getset::Getters;
|
use getset::Getters;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::fmt;
|
|
||||||
use std::path::{Path, PathBuf};
|
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)]
|
#[derive(new, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)]
|
||||||
pub struct Spanned<T> {
|
pub struct Spanned<T> {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
@ -62,6 +73,7 @@ impl<T> std::ops::Deref for Spanned<T> {
|
|||||||
&self.item
|
&self.item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(new, Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)]
|
#[derive(new, Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)]
|
||||||
pub struct Tagged<T> {
|
pub struct Tagged<T> {
|
||||||
pub tag: Tag,
|
pub tag: Tag,
|
||||||
@ -79,6 +91,12 @@ impl Tagged<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> Tagged<Vec<T>> {
|
||||||
|
pub fn items(&self) -> impl Iterator<Item = &T> {
|
||||||
|
self.item.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> HasTag for Tagged<T> {
|
impl<T> HasTag for Tagged<T> {
|
||||||
fn tag(&self) -> Tag {
|
fn tag(&self) -> Tag {
|
||||||
self.tag.clone()
|
self.tag.clone()
|
||||||
@ -184,14 +202,8 @@ impl From<&Tag> for Tag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<nom_locate::LocatedSpanEx<&str, TracableContext>> for Span {
|
impl<T> From<nom_locate::LocatedSpanEx<&str, T>> for Span {
|
||||||
fn from(input: nom_locate::LocatedSpanEx<&str, TracableContext>) -> Span {
|
fn from(input: nom_locate::LocatedSpanEx<&str, T>) -> Span {
|
||||||
Span::new(input.offset, input.offset + input.fragment.len())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<nom_locate::LocatedSpanEx<&str, u64>> for Span {
|
|
||||||
fn from(input: nom_locate::LocatedSpanEx<&str, u64>) -> Span {
|
|
||||||
Span::new(input.offset, input.offset + input.fragment.len())
|
Span::new(input.offset, input.offset + input.fragment.len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -330,6 +342,10 @@ impl Tag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn anchor(&self) -> Option<AnchorLocation> {
|
||||||
|
self.anchor.clone()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn until(&self, other: impl Into<Tag>) -> Tag {
|
pub fn until(&self, other: impl Into<Tag>) -> Tag {
|
||||||
let other = other.into();
|
let other = other.into();
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
@ -376,6 +392,14 @@ impl Tag {
|
|||||||
pub fn tagged_string<'a>(&self, source: &'a str) -> Tagged<String> {
|
pub fn tagged_string<'a>(&self, source: &'a str) -> Tagged<String> {
|
||||||
self.span.slice(source).to_string().tagged(self)
|
self.span.slice(source).to_string().tagged(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn anchor_name(&self) -> Option<String> {
|
||||||
|
match self.anchor {
|
||||||
|
Some(AnchorLocation::File(ref file)) => Some(file.clone()),
|
||||||
|
Some(AnchorLocation::Url(ref url)) => Some(url.clone()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
@ -418,6 +442,12 @@ pub struct Span {
|
|||||||
end: usize,
|
end: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&Span> for Span {
|
||||||
|
fn from(span: &Span) -> Span {
|
||||||
|
*span
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Option<Span>> for Span {
|
impl From<Option<Span>> for Span {
|
||||||
fn from(input: Option<Span>) -> Span {
|
fn from(input: Option<Span>) -> Span {
|
||||||
match input {
|
match input {
|
||||||
@ -514,11 +544,11 @@ impl language_reporting::ReportingSpan for Span {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait HasSpan: ToDebug {
|
pub trait HasSpan: PrettyDebugWithSource {
|
||||||
fn span(&self) -> Span;
|
fn span(&self) -> Span;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait HasFallibleSpan: ToDebug {
|
pub trait HasFallibleSpan: PrettyDebugWithSource {
|
||||||
fn maybe_span(&self) -> Option<Span>;
|
fn maybe_span(&self) -> Option<Span>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -530,31 +560,34 @@ impl<T: HasSpan> HasFallibleSpan for T {
|
|||||||
|
|
||||||
impl<T> HasSpan for Spanned<T>
|
impl<T> HasSpan for Spanned<T>
|
||||||
where
|
where
|
||||||
Spanned<T>: ToDebug,
|
Spanned<T>: PrettyDebugWithSource,
|
||||||
{
|
{
|
||||||
fn span(&self) -> Span {
|
fn span(&self) -> Span {
|
||||||
self.span
|
self.span
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PrettyDebugWithSource for Option<Span> {
|
||||||
|
fn pretty_debug(&self, source: &str) -> DebugDocBuilder {
|
||||||
|
match self {
|
||||||
|
None => b::description("no span"),
|
||||||
|
Some(span) => span.pretty_debug(source),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl HasFallibleSpan for Option<Span> {
|
impl HasFallibleSpan for Option<Span> {
|
||||||
fn maybe_span(&self) -> Option<Span> {
|
fn maybe_span(&self) -> Option<Span> {
|
||||||
*self
|
*self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FormatDebug for Option<Span> {
|
impl PrettyDebugWithSource for Span {
|
||||||
fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result {
|
fn pretty_debug(&self, source: &str) -> DebugDocBuilder {
|
||||||
match self {
|
b::typed(
|
||||||
Option::None => write!(f, "no span"),
|
"spanned",
|
||||||
Option::Some(span) => FormatDebug::fmt_debug(span, f, source),
|
b::keyword("for") + b::space() + b::description(format!("{:?}", source)),
|
||||||
}
|
)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FormatDebug for Span {
|
|
||||||
fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result {
|
|
||||||
write!(f, "{:?}", self.slice(source))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -564,21 +597,21 @@ impl HasSpan for Span {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> FormatDebug for Option<Spanned<T>>
|
impl<T> PrettyDebugWithSource for Option<Spanned<T>>
|
||||||
where
|
where
|
||||||
Spanned<T>: ToDebug,
|
Spanned<T>: PrettyDebugWithSource,
|
||||||
{
|
{
|
||||||
fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result {
|
fn pretty_debug(&self, source: &str) -> DebugDocBuilder {
|
||||||
match self {
|
match self {
|
||||||
Option::None => write!(f, "nothing"),
|
None => b::description("nothing"),
|
||||||
Option::Some(spanned) => FormatDebug::fmt_debug(spanned, f, source),
|
Some(v) => v.pretty_debug(source),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> HasFallibleSpan for Option<Spanned<T>>
|
impl<T> HasFallibleSpan for Option<Spanned<T>>
|
||||||
where
|
where
|
||||||
Spanned<T>: ToDebug,
|
Spanned<T>: PrettyDebugWithSource,
|
||||||
{
|
{
|
||||||
fn maybe_span(&self) -> Option<Span> {
|
fn maybe_span(&self) -> Option<Span> {
|
||||||
match self {
|
match self {
|
||||||
@ -588,21 +621,21 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> FormatDebug for Option<Tagged<T>>
|
impl<T> PrettyDebugWithSource for Option<Tagged<T>>
|
||||||
where
|
where
|
||||||
Tagged<T>: ToDebug,
|
Tagged<T>: PrettyDebugWithSource,
|
||||||
{
|
{
|
||||||
fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result {
|
fn pretty_debug(&self, source: &str) -> DebugDocBuilder {
|
||||||
match self {
|
match self {
|
||||||
Option::None => write!(f, "nothing"),
|
None => b::description("nothing"),
|
||||||
Option::Some(item) => FormatDebug::fmt_debug(item, f, source),
|
Some(d) => d.pretty_debug(source),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> HasFallibleSpan for Option<Tagged<T>>
|
impl<T> HasFallibleSpan for Option<Tagged<T>>
|
||||||
where
|
where
|
||||||
Tagged<T>: ToDebug,
|
Tagged<T>: PrettyDebugWithSource,
|
||||||
{
|
{
|
||||||
fn maybe_span(&self) -> Option<Span> {
|
fn maybe_span(&self) -> Option<Span> {
|
||||||
match self {
|
match self {
|
||||||
@ -614,33 +647,9 @@ where
|
|||||||
|
|
||||||
impl<T> HasSpan for Tagged<T>
|
impl<T> HasSpan for Tagged<T>
|
||||||
where
|
where
|
||||||
Tagged<T>: ToDebug,
|
Tagged<T>: PrettyDebugWithSource,
|
||||||
{
|
{
|
||||||
fn span(&self) -> Span {
|
fn span(&self) -> Span {
|
||||||
self.tag.span
|
self.tag.span
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ToDebug> FormatDebug for Vec<T> {
|
|
||||||
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<String> {
|
|
||||||
fn fmt_debug(&self, f: &mut DebugFormatter, _source: &str) -> fmt::Result {
|
|
||||||
write!(f, "{}", self.item)
|
|
||||||
}
|
|
||||||
}
|
|
495
crates/nu-source/src/pretty.rs
Normal file
495
crates/nu-source/src/pretty.rs
Normal file
@ -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<ShellAnnotation> 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<ShellStyle>) -> 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<DebugDocBuilder>,
|
||||||
|
builder: Option<DebugDocBuilder>,
|
||||||
|
after: Option<DebugDocBuilder>,
|
||||||
|
) -> DebugDocBuilder {
|
||||||
|
match builder {
|
||||||
|
None => DebugDocBuilder::blank(),
|
||||||
|
Some(b) => b::option(before) + b + b::option(after),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn preceded_option(
|
||||||
|
before: Option<DebugDocBuilder>,
|
||||||
|
builder: Option<DebugDocBuilder>,
|
||||||
|
) -> DebugDocBuilder {
|
||||||
|
DebugDocBuilder::surrounded_option(before, builder, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn option(builder: Option<DebugDocBuilder>) -> 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<Item = &'a T>,
|
||||||
|
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<T: PrettyDebug>(
|
||||||
|
list: impl IntoIterator<Item = T>,
|
||||||
|
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<Item = DebugDocBuilder>) -> 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<Text>) -> String
|
||||||
|
where
|
||||||
|
Self: Clone,
|
||||||
|
{
|
||||||
|
self.clone().debuggable(source).display()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn debuggable(self, source: impl Into<Text>) -> DebuggableWithSource<Self> {
|
||||||
|
DebuggableWithSource {
|
||||||
|
inner: self,
|
||||||
|
source: source.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PrettyDebug> PrettyDebugWithSource for T {
|
||||||
|
fn pretty_debug(&self, _source: &str) -> DebugDocBuilder {
|
||||||
|
self.pretty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DebuggableWithSource<T: PrettyDebugWithSource> {
|
||||||
|
inner: T,
|
||||||
|
source: Text,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> PrettyDebug for DebuggableWithSource<T>
|
||||||
|
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<DebugDocBuilder> 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<DebugDoc> for PrettyDebugDoc {
|
||||||
|
fn from(input: DebugDoc) -> PrettyDebugDoc {
|
||||||
|
input.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<PrettyDebugDoc> for DebugDocBuilder {
|
||||||
|
fn into(self) -> PrettyDebugDoc {
|
||||||
|
self.inner.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hash_doc<H: std::hash::Hasher>(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<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
hash_doc(&self.inner, state);
|
||||||
|
}
|
||||||
|
}
|
51
crates/nu-source/src/term_colored.rs
Normal file
51
crates/nu-source/src/term_colored.rs
Normal file
@ -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<ShellAnnotation>,
|
||||||
|
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<usize> {
|
||||||
|
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<ShellAnnotation> 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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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<str> for Text {
|
impl std::borrow::Borrow<str> for Text {
|
||||||
fn borrow(&self) -> &str {
|
fn borrow(&self) -> &str {
|
||||||
&*self
|
&*self
|
32
crates/nu-source/src/tracable.rs
Normal file
32
crates/nu-source/src/tracable.rs
Normal file
@ -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()))
|
||||||
|
}
|
59
src/cli.rs
59
src/cli.rs
@ -1,13 +1,15 @@
|
|||||||
use crate::commands::classified::{
|
use crate::commands::classified::{
|
||||||
ClassifiedCommand, ClassifiedInputStream, ClassifiedPipeline, ExternalCommand, InternalCommand,
|
ClassifiedCommand, ClassifiedInputStream, ClassifiedPipeline, ExternalArg, ExternalArgs,
|
||||||
StreamNext,
|
ExternalCommand, InternalCommand, StreamNext,
|
||||||
};
|
};
|
||||||
use crate::commands::plugin::JsonRpc;
|
use crate::commands::plugin::JsonRpc;
|
||||||
use crate::commands::plugin::{PluginCommand, PluginSink};
|
use crate::commands::plugin::{PluginCommand, PluginSink};
|
||||||
use crate::commands::whole_stream_command;
|
use crate::commands::whole_stream_command;
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::data::config;
|
use crate::data::{
|
||||||
use crate::data::Value;
|
base::{UntaggedValue, Value},
|
||||||
|
config,
|
||||||
|
};
|
||||||
pub(crate) use crate::errors::ShellError;
|
pub(crate) use crate::errors::ShellError;
|
||||||
#[cfg(not(feature = "starship-prompt"))]
|
#[cfg(not(feature = "starship-prompt"))]
|
||||||
use crate::git::current_branch;
|
use crate::git::current_branch;
|
||||||
@ -19,6 +21,7 @@ use crate::parser::{
|
|||||||
TokenNode,
|
TokenNode,
|
||||||
};
|
};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_source::{Spanned, Tagged};
|
||||||
|
|
||||||
use log::{debug, log_enabled, trace};
|
use log::{debug, log_enabled, trace};
|
||||||
use rustyline::error::ReadlineError;
|
use rustyline::error::ReadlineError;
|
||||||
@ -381,7 +384,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
|||||||
|
|
||||||
let edit_mode = config::config(Tag::unknown())?
|
let edit_mode = config::config(Tag::unknown())?
|
||||||
.get("edit_mode")
|
.get("edit_mode")
|
||||||
.map(|s| match s.as_string().unwrap().as_ref() {
|
.map(|s| match s.value.expect_string() {
|
||||||
"vi" => EditMode::Vi,
|
"vi" => EditMode::Vi,
|
||||||
"emacs" => EditMode::Emacs,
|
"emacs" => EditMode::Emacs,
|
||||||
_ => EditMode::Emacs,
|
_ => EditMode::Emacs,
|
||||||
@ -448,7 +451,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
|||||||
LineResult::CtrlC => {
|
LineResult::CtrlC => {
|
||||||
let config_ctrlc_exit = config::config(Tag::unknown())?
|
let config_ctrlc_exit = config::config(Tag::unknown())?
|
||||||
.get("ctrlc_exit")
|
.get("ctrlc_exit")
|
||||||
.map(|s| match s.as_string().unwrap().as_ref() {
|
.map(|s| match s.value.expect_string() {
|
||||||
"true" => true,
|
"true" => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
})
|
})
|
||||||
@ -501,8 +504,8 @@ fn set_env_from_config() {
|
|||||||
let value = config.get("env");
|
let value = config.get("env");
|
||||||
|
|
||||||
match value {
|
match value {
|
||||||
Some(Tagged {
|
Some(Value {
|
||||||
item: Value::Row(r),
|
value: UntaggedValue::Row(r),
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
for (k, v) in &r.entries {
|
for (k, v) in &r.entries {
|
||||||
@ -524,8 +527,8 @@ fn set_env_from_config() {
|
|||||||
|
|
||||||
match value {
|
match value {
|
||||||
Some(value) => match value {
|
Some(value) => match value {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Table(table),
|
value: UntaggedValue::Table(table),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let mut paths = vec![];
|
let mut paths = vec![];
|
||||||
@ -583,11 +586,11 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
|
|||||||
Err(err) => return LineResult::Error(line.to_string(), err),
|
Err(err) => return LineResult::Error(line.to_string(), err),
|
||||||
};
|
};
|
||||||
|
|
||||||
match pipeline.commands.last() {
|
match pipeline.commands.list.last() {
|
||||||
Some(ClassifiedCommand::External(_)) => {}
|
Some(ClassifiedCommand::External(_)) => {}
|
||||||
_ => pipeline
|
_ => pipeline
|
||||||
.commands
|
.commands
|
||||||
.item
|
.list
|
||||||
.push(ClassifiedCommand::Internal(InternalCommand {
|
.push(ClassifiedCommand::Internal(InternalCommand {
|
||||||
name: "autoview".to_string(),
|
name: "autoview".to_string(),
|
||||||
name_tag: Tag::unknown(),
|
name_tag: Tag::unknown(),
|
||||||
@ -595,13 +598,13 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
|
|||||||
Box::new(hir::Expression::synthetic_string("autoview")),
|
Box::new(hir::Expression::synthetic_string("autoview")),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
)
|
Span::unknown(),
|
||||||
.spanned_unknown(),
|
),
|
||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut input = ClassifiedInputStream::new();
|
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
|
// 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
|
// 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<String, ReadlineError>, ctx: &mut Context
|
|||||||
let mut output_stream: OutputStream = val.into();
|
let mut output_stream: OutputStream = val.into();
|
||||||
loop {
|
loop {
|
||||||
match output_stream.try_next().await {
|
match output_stream.try_next().await {
|
||||||
Ok(Some(ReturnSuccess::Value(Tagged {
|
Ok(Some(ReturnSuccess::Value(Value {
|
||||||
item: Value::Error(e),
|
value: UntaggedValue::Error(e),
|
||||||
..
|
..
|
||||||
}))) => {
|
}))) => {
|
||||||
return LineResult::Error(line.to_string(), e);
|
return LineResult::Error(line.to_string(), e);
|
||||||
@ -723,7 +726,7 @@ fn classify_pipeline(
|
|||||||
source: &Text,
|
source: &Text,
|
||||||
) -> Result<ClassifiedPipeline, ShellError> {
|
) -> Result<ClassifiedPipeline, ShellError> {
|
||||||
let mut pipeline_list = vec![pipeline.clone()];
|
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(
|
let result = expand_syntax(
|
||||||
&PipelineShape,
|
&PipelineShape,
|
||||||
@ -749,19 +752,21 @@ pub(crate) fn external_command(
|
|||||||
context: &ExpandContext,
|
context: &ExpandContext,
|
||||||
name: Tagged<&str>,
|
name: Tagged<&str>,
|
||||||
) -> Result<ClassifiedCommand, ParseError> {
|
) -> Result<ClassifiedCommand, ParseError> {
|
||||||
let Spanned { item, span } = expand_syntax(&ExternalTokensShape, tokens, context)?;
|
let Spanned { item, span } = expand_syntax(&ExternalTokensShape, tokens, context)?.tokens;
|
||||||
|
|
||||||
Ok(ClassifiedCommand::External(ExternalCommand {
|
Ok(ClassifiedCommand::External(ExternalCommand {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
name_tag: name.tag(),
|
name_tag: name.tag(),
|
||||||
args: item
|
args: ExternalArgs {
|
||||||
.iter()
|
list: item
|
||||||
.map(|x| Tagged {
|
.iter()
|
||||||
tag: x.span.into(),
|
.map(|x| ExternalArg {
|
||||||
item: x.item.clone(),
|
tag: x.span.into(),
|
||||||
})
|
arg: x.item.clone(),
|
||||||
.collect::<Vec<_>>()
|
})
|
||||||
.spanned(span),
|
.collect(),
|
||||||
|
span,
|
||||||
|
},
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct AppendArgs {
|
struct AppendArgs {
|
||||||
row: Tagged<Value>,
|
row: Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Append;
|
pub struct Append;
|
||||||
@ -40,7 +40,7 @@ fn append(
|
|||||||
AppendArgs { row }: AppendArgs,
|
AppendArgs { row }: AppendArgs,
|
||||||
RunnableContext { input, .. }: RunnableContext,
|
RunnableContext { input, .. }: RunnableContext,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let mut after: VecDeque<Tagged<Value>> = VecDeque::new();
|
let mut after: VecDeque<Value> = VecDeque::new();
|
||||||
after.push_back(row);
|
after.push_back(row);
|
||||||
|
|
||||||
Ok(OutputStream::from_input(input.values.chain(after)))
|
Ok(OutputStream::from_input(input.values.chain(after)))
|
||||||
|
@ -93,9 +93,9 @@ pub fn autoview(
|
|||||||
|
|
||||||
let raw = raw.clone();
|
let raw = raw.clone();
|
||||||
|
|
||||||
let input: Vec<Tagged<Value>> = new_input.into();
|
let input: Vec<Value> = 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 first = &input[0];
|
||||||
|
|
||||||
let mut host = context.host.clone();
|
let mut host = context.host.clone();
|
||||||
@ -107,7 +107,7 @@ pub fn autoview(
|
|||||||
Ok(val) => val
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,30 +131,30 @@ pub fn autoview(
|
|||||||
_ => {
|
_ => {
|
||||||
if let ReturnSuccess::Value(x) = x {
|
if let ReturnSuccess::Value(x) = x {
|
||||||
match x {
|
match x {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Primitive(Primitive::String(ref s)),
|
value: UntaggedValue::Primitive(Primitive::String(ref s)),
|
||||||
tag: Tag { anchor, span },
|
tag: Tag { anchor, span },
|
||||||
} if anchor.is_some() => {
|
} if anchor.is_some() => {
|
||||||
if let Some(text) = text {
|
if let Some(text) = text {
|
||||||
let mut stream = VecDeque::new();
|
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);
|
let result = text.run(raw.with_input(stream.into()), &context.commands);
|
||||||
result.collect::<Vec<_>>().await;
|
result.collect::<Vec<_>>().await;
|
||||||
} else {
|
} else {
|
||||||
outln!("{}", s);
|
outln!("{}", s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Primitive(Primitive::String(s)),
|
value: UntaggedValue::Primitive(Primitive::String(s)),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
outln!("{}", s);
|
outln!("{}", s);
|
||||||
}
|
}
|
||||||
|
|
||||||
Tagged { item: Value::Primitive(Primitive::Binary(ref b)), .. } => {
|
Value { value: UntaggedValue::Primitive(Primitive::Binary(ref b)), .. } => {
|
||||||
if let Some(binary) = binary {
|
if let Some(binary) = binary {
|
||||||
let mut stream = VecDeque::new();
|
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);
|
let result = binary.run(raw.with_input(stream.into()), &context.commands);
|
||||||
result.collect::<Vec<_>>().await;
|
result.collect::<Vec<_>>().await;
|
||||||
} else {
|
} else {
|
||||||
@ -163,13 +163,13 @@ pub fn autoview(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Tagged { item: Value::Error(e), .. } => {
|
Value { value: UntaggedValue::Error(e), .. } => {
|
||||||
yield Err(e);
|
yield Err(e);
|
||||||
}
|
}
|
||||||
Tagged { item: ref item, .. } => {
|
Value { value: ref item, .. } => {
|
||||||
if let Some(table) = table {
|
if let Some(table) = table {
|
||||||
let mut stream = VecDeque::new();
|
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);
|
let result = table.run(raw.with_input(stream.into()), &context.commands);
|
||||||
result.collect::<Vec<_>>().await;
|
result.collect::<Vec<_>>().await;
|
||||||
} else {
|
} else {
|
||||||
@ -188,7 +188,7 @@ pub fn autoview(
|
|||||||
|
|
||||||
// Needed for async_stream to type check
|
// Needed for async_stream to type check
|
||||||
if false {
|
if false {
|
||||||
yield ReturnSuccess::value(Value::nothing().tagged_unknown());
|
yield ReturnSuccess::value(UntaggedValue::nothing().into_untagged_value());
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,8 @@ use bytes::{BufMut, BytesMut};
|
|||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use futures::stream::StreamExt;
|
use futures::stream::StreamExt;
|
||||||
use futures_codec::{Decoder, Encoder, Framed};
|
use futures_codec::{Decoder, Encoder, Framed};
|
||||||
use itertools::Itertools;
|
|
||||||
use log::{log_enabled, trace};
|
use log::{log_enabled, trace};
|
||||||
use std::fmt;
|
use nu_source::PrettyDebug;
|
||||||
use std::io::{Error, ErrorKind};
|
use std::io::{Error, ErrorKind};
|
||||||
use subprocess::Exec;
|
use subprocess::Exec;
|
||||||
|
|
||||||
@ -54,7 +53,7 @@ pub(crate) struct ClassifiedInputStream {
|
|||||||
impl ClassifiedInputStream {
|
impl ClassifiedInputStream {
|
||||||
pub(crate) fn new() -> ClassifiedInputStream {
|
pub(crate) fn new() -> ClassifiedInputStream {
|
||||||
ClassifiedInputStream {
|
ClassifiedInputStream {
|
||||||
objects: vec![Value::nothing().tagged(Tag::unknown())].into(),
|
objects: vec![UntaggedValue::nothing().into_value(Tag::unknown())].into(),
|
||||||
stdin: None,
|
stdin: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -75,16 +74,42 @@ impl ClassifiedInputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct ClassifiedPipeline {
|
pub struct Commands {
|
||||||
pub(crate) commands: Spanned<Vec<ClassifiedCommand>>,
|
pub list: Vec<ClassifiedCommand>,
|
||||||
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FormatDebug for ClassifiedPipeline {
|
impl std::ops::Deref for Commands {
|
||||||
fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result {
|
type Target = [ClassifiedCommand];
|
||||||
f.say_str(
|
|
||||||
"classified pipeline",
|
fn deref(&self) -> &Self::Target {
|
||||||
self.commands.iter().map(|c| c.debug(source)).join(" | "),
|
&self.list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) struct ClassifiedPipeline {
|
||||||
|
pub commands: Commands,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClassifiedPipeline {
|
||||||
|
pub fn commands(list: Vec<ClassifiedCommand>, span: impl Into<Span>) -> 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)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub(crate) enum ClassifiedCommand {
|
pub enum ClassifiedCommand {
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
Expr(TokenNode),
|
Expr(TokenNode),
|
||||||
Internal(InternalCommand),
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
Dynamic(Spanned<hir::Call>),
|
Dynamic(hir::Call),
|
||||||
|
Internal(InternalCommand),
|
||||||
External(ExternalCommand),
|
External(ExternalCommand),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FormatDebug for ClassifiedCommand {
|
impl PrettyDebugWithSource for ClassifiedCommand {
|
||||||
fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result {
|
fn pretty_debug(&self, source: &str) -> DebugDocBuilder {
|
||||||
match self {
|
match self {
|
||||||
ClassifiedCommand::Expr(expr) => expr.fmt_debug(f, source),
|
ClassifiedCommand::Expr(token) => b::typed("command", token.pretty_debug(source)),
|
||||||
ClassifiedCommand::Internal(internal) => internal.fmt_debug(f, source),
|
ClassifiedCommand::Dynamic(call) => b::typed("command", call.pretty_debug(source)),
|
||||||
ClassifiedCommand::Dynamic(dynamic) => dynamic.fmt_debug(f, source),
|
ClassifiedCommand::Internal(internal) => internal.pretty_debug(source),
|
||||||
ClassifiedCommand::External(external) => external.fmt_debug(f, source),
|
ClassifiedCommand::External(external) => external.pretty_debug(source),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,10 +152,19 @@ impl HasSpan for ClassifiedCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(new, Debug, Clone, Eq, PartialEq)]
|
#[derive(new, Debug, Clone, Eq, PartialEq)]
|
||||||
pub(crate) struct InternalCommand {
|
pub struct InternalCommand {
|
||||||
pub(crate) name: String,
|
pub(crate) name: String,
|
||||||
pub(crate) name_tag: Tag,
|
pub(crate) name_tag: Tag,
|
||||||
pub(crate) args: Spanned<hir::Call>,
|
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 {
|
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)]
|
#[derive(new, Debug, Eq, PartialEq)]
|
||||||
pub(crate) struct DynamicCommand {
|
pub(crate) struct DynamicCommand {
|
||||||
pub(crate) args: hir::Call,
|
pub(crate) args: hir::Call,
|
||||||
@ -165,21 +193,15 @@ impl InternalCommand {
|
|||||||
trace!(target: "nu::run::internal", "{}", self.args.debug(&source));
|
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 command = context.expect_command(&self.name);
|
||||||
|
|
||||||
let result = {
|
let result =
|
||||||
context.run_command(
|
{ context.run_command(command, self.name_tag.clone(), self.args, &source, objects) };
|
||||||
command,
|
|
||||||
self.name_tag.clone(),
|
|
||||||
self.args.item,
|
|
||||||
&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 result = result.values;
|
||||||
let mut context = context.clone();
|
let mut context = context.clone();
|
||||||
|
|
||||||
@ -200,13 +222,13 @@ impl InternalCommand {
|
|||||||
}
|
}
|
||||||
CommandAction::EnterHelpShell(value) => {
|
CommandAction::EnterHelpShell(value) => {
|
||||||
match value {
|
match value {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Primitive(Primitive::String(cmd)),
|
value: UntaggedValue::Primitive(Primitive::String(cmd)),
|
||||||
tag,
|
tag,
|
||||||
} => {
|
} => {
|
||||||
context.shell_manager.insert_at_current(Box::new(
|
context.shell_manager.insert_at_current(Box::new(
|
||||||
HelpShell::for_command(
|
HelpShell::for_command(
|
||||||
Value::string(cmd).tagged(tag),
|
UntaggedValue::string(cmd).into_value(tag),
|
||||||
&context.registry(),
|
&context.registry(),
|
||||||
).unwrap(),
|
).unwrap(),
|
||||||
));
|
));
|
||||||
@ -250,7 +272,7 @@ impl InternalCommand {
|
|||||||
Ok(ReturnSuccess::DebugValue(v)) => {
|
Ok(ReturnSuccess::DebugValue(v)) => {
|
||||||
yielded = true;
|
yielded = true;
|
||||||
|
|
||||||
let doc = v.item.pretty_doc();
|
let doc = PrettyDebug::pretty_doc(&v);
|
||||||
let mut buffer = termcolor::Buffer::ansi();
|
let mut buffer = termcolor::Buffer::ansi();
|
||||||
|
|
||||||
doc.render_raw(
|
doc.render_raw(
|
||||||
@ -260,7 +282,7 @@ impl InternalCommand {
|
|||||||
|
|
||||||
let value = String::from_utf8_lossy(buffer.as_slice());
|
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) => {
|
Err(err) => {
|
||||||
@ -276,23 +298,60 @@ impl InternalCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[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<ExternalArg>,
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExternalArgs {
|
||||||
|
pub fn iter(&self) -> impl Iterator<Item = &ExternalArg> {
|
||||||
|
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: String,
|
||||||
|
|
||||||
pub(crate) name_tag: Tag,
|
pub(crate) name_tag: Tag,
|
||||||
pub(crate) args: Spanned<Vec<Tagged<String>>>,
|
pub(crate) args: ExternalArgs,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FormatDebug for ExternalCommand {
|
impl PrettyDebug for ExternalCommand {
|
||||||
fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result {
|
fn pretty(&self) -> DebugDocBuilder {
|
||||||
write!(f, "{}", self.name)?;
|
b::typed(
|
||||||
|
"external command",
|
||||||
if self.args.item.len() > 0 {
|
b::description(&self.name)
|
||||||
write!(f, " ")?;
|
+ b::preceded(
|
||||||
write!(f, "{}", self.args.iter().map(|i| i.debug(source)).join(" "))?;
|
b::space(),
|
||||||
}
|
b::intersperse(
|
||||||
|
self.args.iter().map(|a| b::primitive(format!("{}", a.arg))),
|
||||||
Ok(())
|
b::space(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,13 +376,13 @@ impl ExternalCommand {
|
|||||||
stream_next: StreamNext,
|
stream_next: StreamNext,
|
||||||
) -> Result<ClassifiedInputStream, ShellError> {
|
) -> Result<ClassifiedInputStream, ShellError> {
|
||||||
let stdin = input.stdin;
|
let stdin = input.stdin;
|
||||||
let inputs: Vec<Tagged<Value>> = input.objects.into_vec().await;
|
let inputs: Vec<Value> = input.objects.into_vec().await;
|
||||||
|
|
||||||
trace!(target: "nu::run::external", "-> {}", self.name);
|
trace!(target: "nu::run::external", "-> {}", self.name);
|
||||||
trace!(target: "nu::run::external", "inputs = {:?}", inputs);
|
trace!(target: "nu::run::external", "inputs = {:?}", inputs);
|
||||||
|
|
||||||
let mut arg_string = format!("{}", self.name);
|
let mut arg_string = format!("{}", self.name);
|
||||||
for arg in &self.args.item {
|
for arg in self.args.iter() {
|
||||||
arg_string.push_str(&arg);
|
arg_string.push_str(&arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,13 +393,13 @@ impl ExternalCommand {
|
|||||||
let input_strings = inputs
|
let input_strings = inputs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
i.as_string().map_err(|_| {
|
i.as_string().map(|s| s.to_string()).map_err(|_| {
|
||||||
let arg = self.args.iter().find(|arg| arg.item.contains("$it"));
|
let arg = self.args.iter().find(|arg| arg.contains("$it"));
|
||||||
if let Some(arg) = arg {
|
if let Some(arg) = arg {
|
||||||
ShellError::labeled_error(
|
ShellError::labeled_error(
|
||||||
"External $it needs string data",
|
"External $it needs string data",
|
||||||
"given row instead of string data",
|
"given row instead of string data",
|
||||||
arg.tag(),
|
&arg.tag,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
ShellError::labeled_error(
|
ShellError::labeled_error(
|
||||||
@ -368,7 +427,7 @@ impl ExternalCommand {
|
|||||||
process = Exec::shell(itertools::join(commands, " && "))
|
process = Exec::shell(itertools::join(commands, " && "))
|
||||||
} else {
|
} else {
|
||||||
process = Exec::cmd(&self.name);
|
process = Exec::cmd(&self.name);
|
||||||
for arg in &self.args.item {
|
for arg in self.args.iter() {
|
||||||
let arg_chars: Vec<_> = arg.chars().collect();
|
let arg_chars: Vec<_> = arg.chars().collect();
|
||||||
if arg_chars.len() > 1
|
if arg_chars.len() > 1
|
||||||
&& arg_chars[0] == '"'
|
&& arg_chars[0] == '"'
|
||||||
@ -378,7 +437,7 @@ impl ExternalCommand {
|
|||||||
let new_arg: String = arg_chars[1..arg_chars.len() - 1].iter().collect();
|
let new_arg: String = arg_chars[1..arg_chars.len() - 1].iter().collect();
|
||||||
process = process.arg(new_arg);
|
process = process.arg(new_arg);
|
||||||
} else {
|
} 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 stdout = popen.stdout.take().unwrap();
|
||||||
let file = futures::io::AllowStdIo::new(stdout);
|
let file = futures::io::AllowStdIo::new(stdout);
|
||||||
let stream = Framed::new(file, LinesCodec {});
|
let stream = Framed::new(file, LinesCodec {});
|
||||||
let stream =
|
let stream = stream.map(move |line| {
|
||||||
stream.map(move |line| Value::string(line.unwrap()).tagged(&name_tag));
|
UntaggedValue::string(line.unwrap()).into_value(&name_tag)
|
||||||
|
});
|
||||||
Ok(ClassifiedInputStream::from_input_stream(
|
Ok(ClassifiedInputStream::from_input_stream(
|
||||||
stream.boxed() as BoxStream<'static, Tagged<Value>>
|
stream.boxed() as BoxStream<'static, Value>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ pub mod clipboard {
|
|||||||
RunnableContext { input, name, .. }: RunnableContext,
|
RunnableContext { input, name, .. }: RunnableContext,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let values: Vec<Tagged<Value>> = input.values.collect().await;
|
let values: Vec<Value> = input.values.collect().await;
|
||||||
|
|
||||||
let mut clip_stream = inner_clip(values, name).await;
|
let mut clip_stream = inner_clip(values, name).await;
|
||||||
while let Some(value) = clip_stream.next().await {
|
while let Some(value) = clip_stream.next().await {
|
||||||
@ -53,7 +53,7 @@ pub mod clipboard {
|
|||||||
Ok(OutputStream::from(stream))
|
Ok(OutputStream::from(stream))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn inner_clip(input: Vec<Tagged<Value>>, name: Tag) -> OutputStream {
|
async fn inner_clip(input: Vec<Value>, name: Tag) -> OutputStream {
|
||||||
let mut clip_context: ClipboardContext = ClipboardProvider::new().unwrap();
|
let mut clip_context: ClipboardContext = ClipboardProvider::new().unwrap();
|
||||||
let mut new_copy_data = String::new();
|
let mut new_copy_data = String::new();
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ use crate::prelude::*;
|
|||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use getset::Getters;
|
use getset::Getters;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
@ -19,12 +18,6 @@ pub struct UnevaluatedCallInfo {
|
|||||||
pub name_tag: Tag,
|
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 {
|
impl UnevaluatedCallInfo {
|
||||||
pub fn evaluate(
|
pub fn evaluate(
|
||||||
self,
|
self,
|
||||||
@ -85,7 +78,7 @@ pub struct RawCommandArgs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RawCommandArgs {
|
impl RawCommandArgs {
|
||||||
pub fn with_input(self, input: Vec<Tagged<Value>>) -> CommandArgs {
|
pub fn with_input(self, input: Vec<Value>) -> CommandArgs {
|
||||||
CommandArgs {
|
CommandArgs {
|
||||||
host: self.host,
|
host: self.host,
|
||||||
ctrl_c: self.ctrl_c,
|
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 {
|
impl CommandArgs {
|
||||||
pub fn evaluate_once(
|
pub fn evaluate_once(
|
||||||
self,
|
self,
|
||||||
@ -366,11 +353,11 @@ impl EvaluatedCommandArgs {
|
|||||||
&self.call_info.args
|
&self.call_info.args
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn nth(&self, pos: usize) -> Option<&Tagged<Value>> {
|
pub fn nth(&self, pos: usize) -> Option<&Value> {
|
||||||
self.call_info.args.nth(pos)
|
self.call_info.args.nth(pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_nth(&self, pos: usize) -> Result<&Tagged<Value>, ShellError> {
|
pub fn expect_nth(&self, pos: usize) -> Result<&Value, ShellError> {
|
||||||
self.call_info.args.expect_nth(pos)
|
self.call_info.args.expect_nth(pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,11 +365,11 @@ impl EvaluatedCommandArgs {
|
|||||||
self.call_info.args.len()
|
self.call_info.args.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, name: &str) -> Option<&Tagged<Value>> {
|
pub fn get(&self, name: &str) -> Option<&Value> {
|
||||||
self.call_info.args.get(name)
|
self.call_info.args.get(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn slice_from(&self, from: usize) -> Vec<Tagged<Value>> {
|
pub fn slice_from(&self, from: usize) -> Vec<Value> {
|
||||||
let positional = &self.call_info.args.positional;
|
let positional = &self.call_info.args.positional;
|
||||||
|
|
||||||
match positional {
|
match positional {
|
||||||
@ -402,55 +389,50 @@ pub enum CommandAction {
|
|||||||
Exit,
|
Exit,
|
||||||
Error(ShellError),
|
Error(ShellError),
|
||||||
EnterShell(String),
|
EnterShell(String),
|
||||||
EnterValueShell(Tagged<Value>),
|
EnterValueShell(Value),
|
||||||
EnterHelpShell(Tagged<Value>),
|
EnterHelpShell(Value),
|
||||||
PreviousShell,
|
PreviousShell,
|
||||||
NextShell,
|
NextShell,
|
||||||
LeaveShell,
|
LeaveShell,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FormatDebug for CommandAction {
|
impl PrettyDebug for CommandAction {
|
||||||
fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result {
|
fn pretty(&self) -> DebugDocBuilder {
|
||||||
match self {
|
match self {
|
||||||
CommandAction::ChangePath(s) => write!(f, "action:change-path={}", s),
|
CommandAction::ChangePath(path) => b::typed("change path", b::description(path)),
|
||||||
CommandAction::Exit => write!(f, "action:exit"),
|
CommandAction::Exit => b::description("exit"),
|
||||||
CommandAction::Error(_) => write!(f, "action:error"),
|
CommandAction::Error(_) => b::error("error"),
|
||||||
CommandAction::EnterShell(s) => write!(f, "action:enter-shell={}", s),
|
CommandAction::EnterShell(s) => b::typed("enter shell", b::description(s)),
|
||||||
CommandAction::EnterValueShell(t) => {
|
CommandAction::EnterValueShell(v) => b::typed("enter value shell", v.pretty()),
|
||||||
write!(f, "action:enter-value-shell={}", t.debug(source))
|
CommandAction::EnterHelpShell(v) => b::typed("enter help shell", v.pretty()),
|
||||||
}
|
CommandAction::PreviousShell => b::description("previous shell"),
|
||||||
CommandAction::EnterHelpShell(t) => {
|
CommandAction::NextShell => b::description("next shell"),
|
||||||
write!(f, "action:enter-help-shell={}", t.debug(source))
|
CommandAction::LeaveShell => b::description("leave shell"),
|
||||||
}
|
|
||||||
CommandAction::PreviousShell => write!(f, "action:previous-shell"),
|
|
||||||
CommandAction::NextShell => write!(f, "action:next-shell"),
|
|
||||||
CommandAction::LeaveShell => write!(f, "action:leave-shell"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub enum ReturnSuccess {
|
pub enum ReturnSuccess {
|
||||||
Value(Tagged<Value>),
|
Value(Value),
|
||||||
DebugValue(Tagged<Value>),
|
DebugValue(Value),
|
||||||
Action(CommandAction),
|
Action(CommandAction),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ReturnValue = Result<ReturnSuccess, ShellError>;
|
impl PrettyDebug for ReturnSuccess {
|
||||||
|
fn pretty(&self) -> DebugDocBuilder {
|
||||||
impl FormatDebug for ReturnValue {
|
|
||||||
fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result {
|
|
||||||
match self {
|
match self {
|
||||||
Err(err) => write!(f, "{}", err.debug(source)),
|
ReturnSuccess::Value(value) => b::typed("value", value.pretty()),
|
||||||
Ok(ReturnSuccess::Value(v)) => write!(f, "{}", v.debug(source)),
|
ReturnSuccess::DebugValue(value) => b::typed("debug value", value.pretty()),
|
||||||
Ok(ReturnSuccess::DebugValue(v)) => v.fmt_debug(f, source),
|
ReturnSuccess::Action(action) => b::typed("action", action.pretty()),
|
||||||
Ok(ReturnSuccess::Action(a)) => write!(f, "{}", a.debug(source)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Tagged<Value>> for ReturnValue {
|
pub type ReturnValue = Result<ReturnSuccess, ShellError>;
|
||||||
fn from(input: Tagged<Value>) -> ReturnValue {
|
|
||||||
|
impl From<Value> for ReturnValue {
|
||||||
|
fn from(input: Value) -> ReturnValue {
|
||||||
Ok(ReturnSuccess::Value(input))
|
Ok(ReturnSuccess::Value(input))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -460,11 +442,11 @@ impl ReturnSuccess {
|
|||||||
Ok(ReturnSuccess::Action(CommandAction::ChangePath(path)))
|
Ok(ReturnSuccess::Action(CommandAction::ChangePath(path)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value(input: impl Into<Tagged<Value>>) -> ReturnValue {
|
pub fn value(input: impl Into<Value>) -> ReturnValue {
|
||||||
Ok(ReturnSuccess::Value(input.into()))
|
Ok(ReturnSuccess::Value(input.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debug_value(input: impl Into<Tagged<Value>>) -> ReturnValue {
|
pub fn debug_value(input: impl Into<Value>) -> ReturnValue {
|
||||||
Ok(ReturnSuccess::DebugValue(input.into()))
|
Ok(ReturnSuccess::DebugValue(input.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -521,7 +503,7 @@ pub trait PerItemCommand: Send + Sync {
|
|||||||
call_info: &CallInfo,
|
call_info: &CallInfo,
|
||||||
registry: &CommandRegistry,
|
registry: &CommandRegistry,
|
||||||
raw_args: &RawCommandArgs,
|
raw_args: &RawCommandArgs,
|
||||||
input: Tagged<Value>,
|
input: Value,
|
||||||
) -> Result<OutputStream, ShellError>;
|
) -> Result<OutputStream, ShellError>;
|
||||||
|
|
||||||
fn is_binary(&self) -> bool {
|
fn is_binary(&self) -> bool {
|
||||||
@ -534,6 +516,29 @@ pub enum Command {
|
|||||||
PerItem(Arc<dyn PerItemCommand>),
|
PerItem(Arc<dyn PerItemCommand>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
impl std::fmt::Debug for Command {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
use crate::commands::WholeStreamCommand;
|
||||||
|
use crate::data::base::UntaggedValue;
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::parser::registry::{CommandRegistry, Signature};
|
use crate::parser::registry::{CommandRegistry, Signature};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use futures::stream::StreamExt;
|
use futures::stream::StreamExt;
|
||||||
|
use nu_source::Tagged;
|
||||||
|
|
||||||
pub struct Compact;
|
pub struct Compact;
|
||||||
|
|
||||||
@ -42,8 +44,8 @@ pub fn compact(
|
|||||||
item.is_some()
|
item.is_some()
|
||||||
} else {
|
} else {
|
||||||
match item {
|
match item {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Row(ref r),
|
value: UntaggedValue::Row(ref r),
|
||||||
..
|
..
|
||||||
} => columns
|
} => columns
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -4,6 +4,7 @@ use crate::errors::ShellError;
|
|||||||
use crate::parser::hir::SyntaxShape;
|
use crate::parser::hir::SyntaxShape;
|
||||||
use crate::parser::registry::{self};
|
use crate::parser::registry::{self};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_source::Tagged;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub struct Config;
|
pub struct Config;
|
||||||
@ -11,7 +12,7 @@ pub struct Config;
|
|||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct ConfigArgs {
|
pub struct ConfigArgs {
|
||||||
load: Option<Tagged<PathBuf>>,
|
load: Option<Tagged<PathBuf>>,
|
||||||
set: Option<(Tagged<String>, Tagged<Value>)>,
|
set: Option<(Tagged<String>, Value)>,
|
||||||
set_into: Option<Tagged<String>>,
|
set_into: Option<Tagged<String>>,
|
||||||
get: Option<Tagged<String>>,
|
get: Option<Tagged<String>>,
|
||||||
clear: Tagged<bool>,
|
clear: Tagged<bool>,
|
||||||
@ -90,11 +91,12 @@ pub fn config(
|
|||||||
.ok_or_else(|| ShellError::labeled_error("Missing key in config", "key", v.tag()))?;
|
.ok_or_else(|| ShellError::labeled_error("Missing key in config", "key", v.tag()))?;
|
||||||
|
|
||||||
match value {
|
match value {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Table(list),
|
value: UntaggedValue::Table(list),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
for l in list {
|
for l in list {
|
||||||
|
let value = l.clone();
|
||||||
yield ReturnSuccess::value(l.clone());
|
yield ReturnSuccess::value(l.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -106,10 +108,10 @@ pub fn config(
|
|||||||
|
|
||||||
config::write(&result, &configuration)?;
|
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 {
|
else if let Some(v) = set_into {
|
||||||
let rows: Vec<Tagged<Value>> = input.values.collect().await;
|
let rows: Vec<Value> = input.values.collect().await;
|
||||||
let key = v.to_string();
|
let key = v.to_string();
|
||||||
|
|
||||||
if rows.len() == 0 {
|
if rows.len() == 0 {
|
||||||
@ -122,16 +124,16 @@ pub fn config(
|
|||||||
|
|
||||||
config::write(&result, &configuration)?;
|
config::write(&result, &configuration)?;
|
||||||
|
|
||||||
yield ReturnSuccess::value(Value::Row(result.into()).tagged(name));
|
yield ReturnSuccess::value(UntaggedValue::Row(result.into()).into_value(name));
|
||||||
} else {
|
} else {
|
||||||
// Take in the pipeline as a table
|
// 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());
|
result.insert(key.to_string(), value.clone());
|
||||||
|
|
||||||
config::write(&result, &configuration)?;
|
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 {
|
else if let Tagged { item: true, tag } = clear {
|
||||||
@ -139,14 +141,14 @@ pub fn config(
|
|||||||
|
|
||||||
config::write(&result, &configuration)?;
|
config::write(&result, &configuration)?;
|
||||||
|
|
||||||
yield ReturnSuccess::value(Value::Row(result.into()).tagged(tag));
|
yield ReturnSuccess::value(UntaggedValue::Row(result.into()).into_value(tag));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if let Tagged { item: true, tag } = path {
|
else if let Tagged { item: true, tag } = path {
|
||||||
let path = config::default_path_for(&configuration)?;
|
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 {
|
else if let Some(v) = remove {
|
||||||
let key = v.to_string();
|
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 {
|
else {
|
||||||
yield ReturnSuccess::value(Value::Row(result.into()).tagged(name));
|
yield ReturnSuccess::value(UntaggedValue::Row(result.into()).into_value(name));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -37,9 +37,9 @@ pub fn count(
|
|||||||
RunnableContext { input, name, .. }: RunnableContext,
|
RunnableContext { input, name, .. }: RunnableContext,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let rows: Vec<Tagged<Value>> = input.values.collect().await;
|
let rows: Vec<Value> = 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())
|
Ok(stream.to_output_stream())
|
||||||
|
@ -3,6 +3,7 @@ use crate::errors::ShellError;
|
|||||||
use crate::parser::hir::SyntaxShape;
|
use crate::parser::hir::SyntaxShape;
|
||||||
use crate::parser::registry::{CommandRegistry, Signature};
|
use crate::parser::registry::{CommandRegistry, Signature};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_source::Tagged;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub struct Cpy;
|
pub struct Cpy;
|
||||||
@ -35,7 +36,7 @@ impl PerItemCommand for Cpy {
|
|||||||
call_info: &CallInfo,
|
call_info: &CallInfo,
|
||||||
_registry: &CommandRegistry,
|
_registry: &CommandRegistry,
|
||||||
raw_args: &RawCommandArgs,
|
raw_args: &RawCommandArgs,
|
||||||
_input: Tagged<Value>,
|
_input: Value,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
call_info.process(&raw_args.shell_manager, cp)?.run()
|
call_info.process(&raw_args.shell_manager, cp)?.run()
|
||||||
}
|
}
|
||||||
|
@ -35,26 +35,44 @@ impl WholeStreamCommand for Date {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn date_to_value<T: TimeZone>(dt: DateTime<T>, tag: Tag) -> Tagged<Value>
|
pub fn date_to_value<T: TimeZone>(dt: DateTime<T>, tag: Tag) -> Value
|
||||||
where
|
where
|
||||||
T::Offset: Display,
|
T::Offset: Display,
|
||||||
{
|
{
|
||||||
let mut indexmap = IndexMap::new();
|
let mut indexmap = IndexMap::new();
|
||||||
|
|
||||||
indexmap.insert("year".to_string(), Value::int(dt.year()).tagged(&tag));
|
indexmap.insert(
|
||||||
indexmap.insert("month".to_string(), Value::int(dt.month()).tagged(&tag));
|
"year".to_string(),
|
||||||
indexmap.insert("day".to_string(), Value::int(dt.day()).tagged(&tag));
|
UntaggedValue::int(dt.year()).into_value(&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(
|
||||||
indexmap.insert("second".to_string(), Value::int(dt.second()).tagged(&tag));
|
"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();
|
let tz = dt.offset();
|
||||||
indexmap.insert(
|
indexmap.insert(
|
||||||
"timezone".to_string(),
|
"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<OutputStream, ShellError> {
|
pub fn date(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
|
@ -34,6 +34,8 @@ fn debug_value(
|
|||||||
) -> Result<impl ToOutputStream, ShellError> {
|
) -> Result<impl ToOutputStream, ShellError> {
|
||||||
Ok(input
|
Ok(input
|
||||||
.values
|
.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())
|
.to_output_stream())
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,12 @@ use crate::commands::WholeStreamCommand;
|
|||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::parser::CommandRegistry;
|
use crate::parser::CommandRegistry;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_source::Tagged;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct DefaultArgs {
|
struct DefaultArgs {
|
||||||
column: Tagged<String>,
|
column: Tagged<String>,
|
||||||
value: Tagged<Value>,
|
value: Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Default;
|
pub struct Default;
|
||||||
@ -49,15 +50,15 @@ fn default(
|
|||||||
let mut result = VecDeque::new();
|
let mut result = VecDeque::new();
|
||||||
|
|
||||||
let should_add = match item {
|
let should_add = match item {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Row(ref r),
|
value: UntaggedValue::Row(ref r),
|
||||||
..
|
..
|
||||||
} => r.get_data(&column.item).borrow().is_none(),
|
} => r.get_data(&column.item).borrow().is_none(),
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
if should_add {
|
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)),
|
Some(new_value) => result.push_back(ReturnSuccess::value(new_value)),
|
||||||
None => result.push_back(ReturnSuccess::value(item)),
|
None => result.push_back(ReturnSuccess::value(item)),
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ impl PerItemCommand for Echo {
|
|||||||
call_info: &CallInfo,
|
call_info: &CallInfo,
|
||||||
registry: &CommandRegistry,
|
registry: &CommandRegistry,
|
||||||
raw_args: &RawCommandArgs,
|
raw_args: &RawCommandArgs,
|
||||||
_input: Tagged<Value>,
|
_input: Value,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
run(call_info, registry, raw_args)
|
run(call_info, registry, raw_args)
|
||||||
}
|
}
|
||||||
@ -42,16 +42,16 @@ fn run(
|
|||||||
match i.as_string() {
|
match i.as_string() {
|
||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
output.push(Ok(ReturnSuccess::Value(
|
output.push(Ok(ReturnSuccess::Value(
|
||||||
Value::string(s).tagged(i.tag.clone()),
|
UntaggedValue::string(s).into_value(i.tag.clone()),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
_ => match i {
|
_ => match i {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Table(table),
|
value: UntaggedValue::Table(table),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
for item in table {
|
for value in table {
|
||||||
output.push(Ok(ReturnSuccess::Value(item.clone())));
|
output.push(Ok(ReturnSuccess::Value(value.clone())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -30,13 +30,13 @@ impl PerItemCommand for Enter {
|
|||||||
call_info: &CallInfo,
|
call_info: &CallInfo,
|
||||||
registry: ®istry::CommandRegistry,
|
registry: ®istry::CommandRegistry,
|
||||||
raw_args: &RawCommandArgs,
|
raw_args: &RawCommandArgs,
|
||||||
_input: Tagged<Value>,
|
_input: Value,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let registry = registry.clone();
|
let registry = registry.clone();
|
||||||
let raw_args = raw_args.clone();
|
let raw_args = raw_args.clone();
|
||||||
match call_info.args.expect_nth(0)? {
|
match call_info.args.expect_nth(0)? {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Primitive(Primitive::Path(location)),
|
value: UntaggedValue::Primitive(Primitive::Path(location)),
|
||||||
tag,
|
tag,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
@ -51,12 +51,12 @@ impl PerItemCommand for Enter {
|
|||||||
|
|
||||||
if registry.has(command) {
|
if registry.has(command) {
|
||||||
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterHelpShell(
|
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterHelpShell(
|
||||||
Value::string(command).tagged(Tag::unknown()),
|
UntaggedValue::string(command).into_value(Tag::unknown()),
|
||||||
)))]
|
)))]
|
||||||
.into())
|
.into())
|
||||||
} else {
|
} else {
|
||||||
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterHelpShell(
|
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterHelpShell(
|
||||||
Value::nothing().tagged(Tag::unknown()),
|
UntaggedValue::nothing().into_value(Tag::unknown()),
|
||||||
)))]
|
)))]
|
||||||
.into())
|
.into())
|
||||||
}
|
}
|
||||||
@ -80,8 +80,8 @@ impl PerItemCommand for Enter {
|
|||||||
).await?;
|
).await?;
|
||||||
|
|
||||||
match contents {
|
match contents {
|
||||||
Value::Primitive(Primitive::String(_)) => {
|
UntaggedValue::Primitive(Primitive::String(_)) => {
|
||||||
let tagged_contents = contents.tagged(&contents_tag);
|
let tagged_contents = contents.into_value(&contents_tag);
|
||||||
|
|
||||||
if let Some(extension) = file_extension {
|
if let Some(extension) = file_extension {
|
||||||
let command_name = format!("from-{}", extension);
|
let command_name = format!("from-{}", extension);
|
||||||
@ -97,6 +97,7 @@ impl PerItemCommand for Enter {
|
|||||||
head: raw_args.call_info.args.head,
|
head: raw_args.call_info.args.head,
|
||||||
positional: None,
|
positional: None,
|
||||||
named: None,
|
named: None,
|
||||||
|
span: Span::unknown()
|
||||||
},
|
},
|
||||||
source: raw_args.call_info.source,
|
source: raw_args.call_info.source,
|
||||||
name_tag: raw_args.call_info.name_tag,
|
name_tag: raw_args.call_info.name_tag,
|
||||||
@ -110,13 +111,13 @@ impl PerItemCommand for Enter {
|
|||||||
result.drain_vec().await;
|
result.drain_vec().await;
|
||||||
for res in result_vec {
|
for res in result_vec {
|
||||||
match res {
|
match res {
|
||||||
Ok(ReturnSuccess::Value(Tagged {
|
Ok(ReturnSuccess::Value(Value {
|
||||||
item,
|
value,
|
||||||
..
|
..
|
||||||
})) => {
|
})) => {
|
||||||
yield Ok(ReturnSuccess::Action(CommandAction::EnterValueShell(
|
yield Ok(ReturnSuccess::Action(CommandAction::EnterValueShell(
|
||||||
Tagged {
|
Value {
|
||||||
item,
|
value,
|
||||||
tag: contents_tag.clone(),
|
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)));
|
yield Ok(ReturnSuccess::Action(CommandAction::EnterValueShell(tagged_contents)));
|
||||||
}
|
}
|
||||||
|
@ -33,34 +33,49 @@ impl WholeStreamCommand for Env {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_environment(tag: Tag) -> Result<Tagged<Value>, Box<dyn std::error::Error>> {
|
pub fn get_environment(tag: Tag) -> Result<Value, Box<dyn std::error::Error>> {
|
||||||
let mut indexmap = IndexMap::new();
|
let mut indexmap = IndexMap::new();
|
||||||
|
|
||||||
let path = std::env::current_dir()?;
|
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() {
|
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()?;
|
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();
|
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();
|
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);
|
let mut dict = TaggedDictBuilder::new(&tag);
|
||||||
for v in std::env::vars() {
|
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() {
|
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<OutputStream, ShellError> {
|
pub fn env(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
use crate::commands::WholeStreamCommand;
|
||||||
use crate::parser::hir::SyntaxShape;
|
use crate::parser::hir::SyntaxShape;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_source::{SpannedItem, Tagged};
|
||||||
|
|
||||||
pub struct EvaluateBy;
|
pub struct EvaluateBy;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
@ -39,7 +41,7 @@ pub fn evaluate_by(
|
|||||||
RunnableContext { input, name, .. }: RunnableContext,
|
RunnableContext { input, name, .. }: RunnableContext,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let values: Vec<Tagged<Value>> = input.values.collect().await;
|
let values: Vec<Value> = input.values.collect().await;
|
||||||
|
|
||||||
|
|
||||||
if values.is_empty() {
|
if values.is_empty() {
|
||||||
@ -66,30 +68,18 @@ pub fn evaluate_by(
|
|||||||
Ok(stream.to_output_stream())
|
Ok(stream.to_output_stream())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch(
|
fn fetch(key: Option<String>) -> Box<dyn Fn(Value, Tag) -> Option<Value> + 'static> {
|
||||||
key: Option<String>,
|
Box::new(move |value: Value, tag| match &key {
|
||||||
) -> Box<dyn Fn(Tagged<Value>, Tag) -> Option<Tagged<Value>> + 'static> {
|
Some(key_given) => value.get_data_by_key(key_given[..].spanned(tag.span)),
|
||||||
Box::new(move |value: Tagged<Value>, tag| match key {
|
None => Some(UntaggedValue::int(1).into_value(tag)),
|
||||||
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)),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn evaluate(
|
pub fn evaluate(
|
||||||
values: &Tagged<Value>,
|
values: &Value,
|
||||||
evaluator: Option<String>,
|
evaluator: Option<String>,
|
||||||
tag: impl Into<Tag>,
|
tag: impl Into<Tag>,
|
||||||
) -> Result<Tagged<Value>, ShellError> {
|
) -> Result<Value, ShellError> {
|
||||||
let tag = tag.into();
|
let tag = tag.into();
|
||||||
|
|
||||||
let evaluate_with = match evaluator {
|
let evaluate_with = match evaluator {
|
||||||
@ -97,44 +87,44 @@ pub fn evaluate(
|
|||||||
None => fetch(None),
|
None => fetch(None),
|
||||||
};
|
};
|
||||||
|
|
||||||
let results: Tagged<Value> = match values {
|
let results: Value = match values {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Table(datasets),
|
value: UntaggedValue::Table(datasets),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let datasets: Vec<_> = datasets
|
let datasets: Vec<_> = datasets
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|subsets| match subsets {
|
.map(|subsets| match subsets {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Table(subsets),
|
value: UntaggedValue::Table(subsets),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let subsets: Vec<_> = subsets
|
let subsets: Vec<_> = subsets
|
||||||
.clone()
|
.clone()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|data| match data {
|
.map(|data| match data {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Table(data),
|
value: UntaggedValue::Table(data),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let data: Vec<_> = data
|
let data: Vec<_> = data
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|x| evaluate_with(x.clone(), tag.clone()).unwrap())
|
.map(|x| evaluate_with(x.clone(), tag.clone()).unwrap())
|
||||||
.collect();
|
.collect();
|
||||||
Value::Table(data).tagged(&tag)
|
UntaggedValue::Table(data).into_value(&tag)
|
||||||
}
|
}
|
||||||
_ => Value::Table(vec![]).tagged(&tag),
|
_ => UntaggedValue::Table(vec![]).into_value(&tag),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
Value::Table(subsets).tagged(&tag)
|
UntaggedValue::Table(subsets).into_value(&tag)
|
||||||
}
|
}
|
||||||
_ => Value::Table(vec![]).tagged(&tag),
|
_ => UntaggedValue::Table(vec![]).into_value(&tag),
|
||||||
})
|
})
|
||||||
.collect();
|
.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)
|
Ok(results)
|
||||||
@ -146,28 +136,28 @@ mod tests {
|
|||||||
use crate::commands::evaluate_by::{evaluate, fetch};
|
use crate::commands::evaluate_by::{evaluate, fetch};
|
||||||
use crate::commands::group_by::group;
|
use crate::commands::group_by::group;
|
||||||
use crate::commands::t_sort_by::t_sort;
|
use crate::commands::t_sort_by::t_sort;
|
||||||
use crate::data::meta::*;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::Value;
|
use crate::Value;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
use nu_source::TaggedItem;
|
||||||
|
|
||||||
fn int(s: impl Into<BigInt>) -> Tagged<Value> {
|
fn int(s: impl Into<BigInt>) -> Value {
|
||||||
Value::int(s).tagged_unknown()
|
UntaggedValue::int(s).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn string(input: impl Into<String>) -> Tagged<Value> {
|
fn string(input: impl Into<String>) -> Value {
|
||||||
Value::string(input.into()).tagged_unknown()
|
UntaggedValue::string(input.into()).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn row(entries: IndexMap<String, Tagged<Value>>) -> Tagged<Value> {
|
fn row(entries: IndexMap<String, Value>) -> Value {
|
||||||
Value::row(entries).tagged_unknown()
|
UntaggedValue::row(entries).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn table(list: &Vec<Tagged<Value>>) -> Tagged<Value> {
|
fn table(list: &Vec<Value>) -> Value {
|
||||||
Value::table(list).tagged_unknown()
|
UntaggedValue::table(list).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nu_releases_sorted_by_date() -> Tagged<Value> {
|
fn nu_releases_sorted_by_date() -> Value {
|
||||||
let key = String::from("date");
|
let key = String::from("date");
|
||||||
|
|
||||||
t_sort(
|
t_sort(
|
||||||
@ -179,12 +169,12 @@ mod tests {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nu_releases_grouped_by_date() -> Tagged<Value> {
|
fn nu_releases_grouped_by_date() -> Value {
|
||||||
let key = String::from("date").tagged_unknown();
|
let key = String::from("date").tagged_unknown();
|
||||||
group(&key, nu_releases_commiters(), Tag::unknown()).unwrap()
|
group(&key, nu_releases_commiters(), Tag::unknown()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nu_releases_commiters() -> Vec<Tagged<Value>> {
|
fn nu_releases_commiters() -> Vec<Value> {
|
||||||
vec![
|
vec![
|
||||||
row(
|
row(
|
||||||
indexmap! {"name".into() => string("AR"), "country".into() => string("EC"), "date".into() => string("August 23-2019")},
|
indexmap! {"name".into() => string("AR"), "country".into() => string("EC"), "date".into() => string("August 23-2019")},
|
||||||
@ -232,7 +222,7 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
evaluator(subject, Tag::unknown()),
|
evaluator(subject, Tag::unknown()),
|
||||||
Some(Value::int(1).tagged_unknown())
|
Some(UntaggedValue::int(1).into_untagged_value())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
use crate::commands::UnevaluatedCallInfo;
|
use crate::commands::UnevaluatedCallInfo;
|
||||||
use crate::context::AnchorLocation;
|
use crate::data::base::Value;
|
||||||
use crate::data::meta::Span;
|
|
||||||
use crate::data::Value;
|
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::parser::hir::SyntaxShape;
|
use crate::parser::hir::SyntaxShape;
|
||||||
use crate::parser::registry::Signature;
|
use crate::parser::registry::Signature;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use mime::Mime;
|
use mime::Mime;
|
||||||
|
use nu_source::{AnchorLocation, Span};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use surf::mime;
|
use surf::mime;
|
||||||
|
|
||||||
pub struct Fetch;
|
pub struct Fetch;
|
||||||
|
|
||||||
impl PerItemCommand for Fetch {
|
impl PerItemCommand for Fetch {
|
||||||
@ -36,7 +36,7 @@ impl PerItemCommand for Fetch {
|
|||||||
call_info: &CallInfo,
|
call_info: &CallInfo,
|
||||||
registry: &CommandRegistry,
|
registry: &CommandRegistry,
|
||||||
raw_args: &RawCommandArgs,
|
raw_args: &RawCommandArgs,
|
||||||
_input: Tagged<Value>,
|
_input: Value,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
run(call_info, registry, raw_args)
|
run(call_info, registry, raw_args)
|
||||||
}
|
}
|
||||||
@ -81,7 +81,7 @@ fn run(
|
|||||||
file_extension.or(path_str.split('.').last().map(String::from))
|
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 {
|
if let Some(extension) = file_extension {
|
||||||
let command_name = format!("from-{}", extension);
|
let command_name = format!("from-{}", extension);
|
||||||
@ -94,7 +94,8 @@ fn run(
|
|||||||
args: crate::parser::hir::Call {
|
args: crate::parser::hir::Call {
|
||||||
head: raw_args.call_info.args.head,
|
head: raw_args.call_info.args.head,
|
||||||
positional: None,
|
positional: None,
|
||||||
named: None
|
named: None,
|
||||||
|
span: Span::unknown()
|
||||||
},
|
},
|
||||||
source: raw_args.call_info.source,
|
source: raw_args.call_info.source,
|
||||||
name_tag: raw_args.call_info.name_tag,
|
name_tag: raw_args.call_info.name_tag,
|
||||||
@ -104,13 +105,13 @@ fn run(
|
|||||||
let result_vec: Vec<Result<ReturnSuccess, ShellError>> = result.drain_vec().await;
|
let result_vec: Vec<Result<ReturnSuccess, ShellError>> = result.drain_vec().await;
|
||||||
for res in result_vec {
|
for res in result_vec {
|
||||||
match res {
|
match res {
|
||||||
Ok(ReturnSuccess::Value(Tagged { item: Value::Table(list), ..})) => {
|
Ok(ReturnSuccess::Value(Value { value: UntaggedValue::Table(list), ..})) => {
|
||||||
for l in list {
|
for l in list {
|
||||||
yield Ok(ReturnSuccess::Value(l));
|
yield Ok(ReturnSuccess::Value(l));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(ReturnSuccess::Value(Tagged { item, .. })) => {
|
Ok(ReturnSuccess::Value(Value { value, .. })) => {
|
||||||
yield Ok(ReturnSuccess::Value(Tagged { item, tag: contents_tag.clone() }));
|
yield Ok(ReturnSuccess::Value(value.into_value(contents_tag.clone())));
|
||||||
}
|
}
|
||||||
x => yield x,
|
x => yield x,
|
||||||
}
|
}
|
||||||
@ -126,7 +127,10 @@ fn run(
|
|||||||
Ok(stream.to_output_stream())
|
Ok(stream.to_output_stream())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn fetch(location: &str, span: Span) -> Result<(Option<String>, Value, Tag), ShellError> {
|
pub async fn fetch(
|
||||||
|
location: &str,
|
||||||
|
span: Span,
|
||||||
|
) -> Result<(Option<String>, UntaggedValue, Tag), ShellError> {
|
||||||
if let Err(_) = url::Url::parse(location) {
|
if let Err(_) = url::Url::parse(location) {
|
||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"Incomplete or incorrect url",
|
"Incomplete or incorrect url",
|
||||||
@ -143,7 +147,7 @@ pub async fn fetch(location: &str, span: Span) -> Result<(Option<String>, Value,
|
|||||||
match (content_type.type_(), content_type.subtype()) {
|
match (content_type.type_(), content_type.subtype()) {
|
||||||
(mime::APPLICATION, mime::XML) => Ok((
|
(mime::APPLICATION, mime::XML) => Ok((
|
||||||
Some("xml".to_string()),
|
Some("xml".to_string()),
|
||||||
Value::string(r.body_string().await.map_err(|_| {
|
UntaggedValue::string(r.body_string().await.map_err(|_| {
|
||||||
ShellError::labeled_error(
|
ShellError::labeled_error(
|
||||||
"Could not load text from remote url",
|
"Could not load text from remote url",
|
||||||
"could not load",
|
"could not load",
|
||||||
@ -157,7 +161,7 @@ pub async fn fetch(location: &str, span: Span) -> Result<(Option<String>, Value,
|
|||||||
)),
|
)),
|
||||||
(mime::APPLICATION, mime::JSON) => Ok((
|
(mime::APPLICATION, mime::JSON) => Ok((
|
||||||
Some("json".to_string()),
|
Some("json".to_string()),
|
||||||
Value::string(r.body_string().await.map_err(|_| {
|
UntaggedValue::string(r.body_string().await.map_err(|_| {
|
||||||
ShellError::labeled_error(
|
ShellError::labeled_error(
|
||||||
"Could not load text from remote url",
|
"Could not load text from remote url",
|
||||||
"could not load",
|
"could not load",
|
||||||
@ -179,7 +183,7 @@ pub async fn fetch(location: &str, span: Span) -> Result<(Option<String>, Value,
|
|||||||
})?;
|
})?;
|
||||||
Ok((
|
Ok((
|
||||||
None,
|
None,
|
||||||
Value::binary(buf),
|
UntaggedValue::binary(buf),
|
||||||
Tag {
|
Tag {
|
||||||
span,
|
span,
|
||||||
anchor: Some(AnchorLocation::Url(location.to_string())),
|
anchor: Some(AnchorLocation::Url(location.to_string())),
|
||||||
@ -188,7 +192,7 @@ pub async fn fetch(location: &str, span: Span) -> Result<(Option<String>, Value,
|
|||||||
}
|
}
|
||||||
(mime::IMAGE, mime::SVG) => Ok((
|
(mime::IMAGE, mime::SVG) => Ok((
|
||||||
Some("svg".to_string()),
|
Some("svg".to_string()),
|
||||||
Value::string(r.body_string().await.map_err(|_| {
|
UntaggedValue::string(r.body_string().await.map_err(|_| {
|
||||||
ShellError::labeled_error(
|
ShellError::labeled_error(
|
||||||
"Could not load svg from remote url",
|
"Could not load svg from remote url",
|
||||||
"could not load",
|
"could not load",
|
||||||
@ -210,7 +214,7 @@ pub async fn fetch(location: &str, span: Span) -> Result<(Option<String>, Value,
|
|||||||
})?;
|
})?;
|
||||||
Ok((
|
Ok((
|
||||||
Some(image_ty.to_string()),
|
Some(image_ty.to_string()),
|
||||||
Value::binary(buf),
|
UntaggedValue::binary(buf),
|
||||||
Tag {
|
Tag {
|
||||||
span,
|
span,
|
||||||
anchor: Some(AnchorLocation::Url(location.to_string())),
|
anchor: Some(AnchorLocation::Url(location.to_string())),
|
||||||
@ -219,7 +223,7 @@ pub async fn fetch(location: &str, span: Span) -> Result<(Option<String>, Value,
|
|||||||
}
|
}
|
||||||
(mime::TEXT, mime::HTML) => Ok((
|
(mime::TEXT, mime::HTML) => Ok((
|
||||||
Some("html".to_string()),
|
Some("html".to_string()),
|
||||||
Value::string(r.body_string().await.map_err(|_| {
|
UntaggedValue::string(r.body_string().await.map_err(|_| {
|
||||||
ShellError::labeled_error(
|
ShellError::labeled_error(
|
||||||
"Could not load text from remote url",
|
"Could not load text from remote url",
|
||||||
"could not load",
|
"could not load",
|
||||||
@ -245,7 +249,7 @@ pub async fn fetch(location: &str, span: Span) -> Result<(Option<String>, Value,
|
|||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
path_extension,
|
path_extension,
|
||||||
Value::string(r.body_string().await.map_err(|_| {
|
UntaggedValue::string(r.body_string().await.map_err(|_| {
|
||||||
ShellError::labeled_error(
|
ShellError::labeled_error(
|
||||||
"Could not load text from remote url",
|
"Could not load text from remote url",
|
||||||
"could not load",
|
"could not load",
|
||||||
@ -260,7 +264,10 @@ pub async fn fetch(location: &str, span: Span) -> Result<(Option<String>, Value,
|
|||||||
}
|
}
|
||||||
(ty, sub_ty) => Ok((
|
(ty, sub_ty) => Ok((
|
||||||
None,
|
None,
|
||||||
Value::string(format!("Not yet supported MIME type: {} {}", ty, sub_ty)),
|
UntaggedValue::string(format!(
|
||||||
|
"Not yet supported MIME type: {} {}",
|
||||||
|
ty, sub_ty
|
||||||
|
)),
|
||||||
Tag {
|
Tag {
|
||||||
span,
|
span,
|
||||||
anchor: Some(AnchorLocation::Url(location.to_string())),
|
anchor: Some(AnchorLocation::Url(location.to_string())),
|
||||||
@ -270,7 +277,7 @@ pub async fn fetch(location: &str, span: Span) -> Result<(Option<String>, Value,
|
|||||||
}
|
}
|
||||||
None => Ok((
|
None => Ok((
|
||||||
None,
|
None,
|
||||||
Value::string(format!("No content type found")),
|
UntaggedValue::string(format!("No content type found")),
|
||||||
Tag {
|
Tag {
|
||||||
span,
|
span,
|
||||||
anchor: Some(AnchorLocation::Url(location.to_string())),
|
anchor: Some(AnchorLocation::Url(location.to_string())),
|
||||||
|
@ -2,6 +2,7 @@ use crate::commands::WholeStreamCommand;
|
|||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::parser::CommandRegistry;
|
use crate::parser::CommandRegistry;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_source::Tagged;
|
||||||
|
|
||||||
pub struct First;
|
pub struct First;
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
use crate::commands::WholeStreamCommand;
|
||||||
use crate::data::{Primitive, TaggedDictBuilder, Value};
|
use crate::data::TaggedDictBuilder;
|
||||||
use crate::errors::ExpectedRange;
|
use crate::errors::ExpectedRange;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use bson::{decode_document, spec::BinarySubtype, Bson};
|
use bson::{decode_document, spec::BinarySubtype, Bson};
|
||||||
|
use nu_source::SpannedItem;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
pub struct FromBSON;
|
pub struct FromBSON;
|
||||||
@ -29,7 +30,7 @@ impl WholeStreamCommand for FromBSON {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bson_array(input: &Vec<Bson>, tag: Tag) -> Result<Vec<Tagged<Value>>, ShellError> {
|
fn bson_array(input: &Vec<Bson>, tag: Tag) -> Result<Vec<Value>, ShellError> {
|
||||||
let mut out = vec![];
|
let mut out = vec![];
|
||||||
|
|
||||||
for value in input {
|
for value in input {
|
||||||
@ -39,109 +40,114 @@ fn bson_array(input: &Vec<Bson>, tag: Tag) -> Result<Vec<Tagged<Value>>, ShellEr
|
|||||||
Ok(out)
|
Ok(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_bson_value_to_nu_value(
|
fn convert_bson_value_to_nu_value(v: &Bson, tag: impl Into<Tag>) -> Result<Value, ShellError> {
|
||||||
v: &Bson,
|
|
||||||
tag: impl Into<Tag>,
|
|
||||||
) -> Result<Tagged<Value>, ShellError> {
|
|
||||||
let tag = tag.into();
|
let tag = tag.into();
|
||||||
|
let span = tag.span;
|
||||||
|
|
||||||
Ok(match v {
|
Ok(match v {
|
||||||
Bson::FloatingPoint(n) => Value::Primitive(Primitive::from(*n)).tagged(&tag),
|
Bson::FloatingPoint(n) => UntaggedValue::Primitive(Primitive::from(*n)).into_value(&tag),
|
||||||
Bson::String(s) => Value::Primitive(Primitive::String(String::from(s))).tagged(&tag),
|
Bson::String(s) => {
|
||||||
Bson::Array(a) => Value::Table(bson_array(a, tag.clone())?).tagged(&tag),
|
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) => {
|
Bson::Document(doc) => {
|
||||||
let mut collected = TaggedDictBuilder::new(tag.clone());
|
let mut collected = TaggedDictBuilder::new(tag.clone());
|
||||||
for (k, v) in doc.iter() {
|
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::Boolean(b) => UntaggedValue::Primitive(Primitive::Boolean(*b)).into_value(&tag),
|
||||||
Bson::Null => Value::Primitive(Primitive::Nothing).tagged(&tag),
|
Bson::Null => UntaggedValue::Primitive(Primitive::Nothing).into_value(&tag),
|
||||||
Bson::RegExp(r, opts) => {
|
Bson::RegExp(r, opts) => {
|
||||||
let mut collected = TaggedDictBuilder::new(tag.clone());
|
let mut collected = TaggedDictBuilder::new(tag.clone());
|
||||||
collected.insert_tagged(
|
collected.insert_value(
|
||||||
"$regex".to_string(),
|
"$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(),
|
"$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::I32(n) => UntaggedValue::number(n).into_value(&tag),
|
||||||
Bson::I64(n) => Value::number(n).tagged(&tag),
|
Bson::I64(n) => UntaggedValue::number(n).into_value(&tag),
|
||||||
Bson::Decimal128(n) => {
|
Bson::Decimal128(n) => {
|
||||||
// TODO: this really isn't great, and we should update this to do a higher
|
// TODO: this really isn't great, and we should update this to do a higher
|
||||||
// fidelity translation
|
// fidelity translation
|
||||||
let decimal = BigDecimal::from_str(&format!("{}", n)).map_err(|_| {
|
let decimal = BigDecimal::from_str(&format!("{}", n)).map_err(|_| {
|
||||||
ShellError::range_error(
|
ShellError::range_error(
|
||||||
ExpectedRange::BigDecimal,
|
ExpectedRange::BigDecimal,
|
||||||
&n.tagged(&tag),
|
&n.spanned(span),
|
||||||
format!("converting BSON Decimal128 to BigDecimal"),
|
format!("converting BSON Decimal128 to BigDecimal"),
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
Value::Primitive(Primitive::Decimal(decimal)).tagged(&tag)
|
UntaggedValue::Primitive(Primitive::Decimal(decimal)).into_value(&tag)
|
||||||
}
|
}
|
||||||
Bson::JavaScriptCode(js) => {
|
Bson::JavaScriptCode(js) => {
|
||||||
let mut collected = TaggedDictBuilder::new(tag.clone());
|
let mut collected = TaggedDictBuilder::new(tag.clone());
|
||||||
collected.insert_tagged(
|
collected.insert_value(
|
||||||
"$javascript".to_string(),
|
"$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) => {
|
Bson::JavaScriptCodeWithScope(js, doc) => {
|
||||||
let mut collected = TaggedDictBuilder::new(tag.clone());
|
let mut collected = TaggedDictBuilder::new(tag.clone());
|
||||||
collected.insert_tagged(
|
collected.insert_value(
|
||||||
"$javascript".to_string(),
|
"$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(),
|
"$scope".to_string(),
|
||||||
convert_bson_value_to_nu_value(&Bson::Document(doc.to_owned()), tag.clone())?,
|
convert_bson_value_to_nu_value(&Bson::Document(doc.to_owned()), tag.clone())?,
|
||||||
);
|
);
|
||||||
collected.into_tagged_value()
|
collected.into_value()
|
||||||
}
|
}
|
||||||
Bson::TimeStamp(ts) => {
|
Bson::TimeStamp(ts) => {
|
||||||
let mut collected = TaggedDictBuilder::new(tag.clone());
|
let mut collected = TaggedDictBuilder::new(tag.clone());
|
||||||
collected.insert_tagged("$timestamp".to_string(), Value::number(ts).tagged(&tag));
|
collected.insert_value(
|
||||||
collected.into_tagged_value()
|
"$timestamp".to_string(),
|
||||||
|
UntaggedValue::number(ts).into_value(&tag),
|
||||||
|
);
|
||||||
|
collected.into_value()
|
||||||
}
|
}
|
||||||
Bson::Binary(bst, bytes) => {
|
Bson::Binary(bst, bytes) => {
|
||||||
let mut collected = TaggedDictBuilder::new(tag.clone());
|
let mut collected = TaggedDictBuilder::new(tag.clone());
|
||||||
collected.insert_tagged(
|
collected.insert_value(
|
||||||
"$binary_subtype".to_string(),
|
"$binary_subtype".to_string(),
|
||||||
match bst {
|
match bst {
|
||||||
BinarySubtype::UserDefined(u) => Value::number(u),
|
BinarySubtype::UserDefined(u) => UntaggedValue::number(u),
|
||||||
_ => Value::Primitive(Primitive::String(binary_subtype_to_string(*bst))),
|
_ => {
|
||||||
|
UntaggedValue::Primitive(Primitive::String(binary_subtype_to_string(*bst)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.tagged(&tag),
|
.into_value(&tag),
|
||||||
);
|
);
|
||||||
collected.insert_tagged(
|
collected.insert_value(
|
||||||
"$binary".to_string(),
|
"$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) => {
|
Bson::ObjectId(obj_id) => {
|
||||||
let mut collected = TaggedDictBuilder::new(tag.clone());
|
let mut collected = TaggedDictBuilder::new(tag.clone());
|
||||||
collected.insert_tagged(
|
collected.insert_value(
|
||||||
"$object_id".to_string(),
|
"$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) => {
|
Bson::Symbol(s) => {
|
||||||
let mut collected = TaggedDictBuilder::new(tag.clone());
|
let mut collected = TaggedDictBuilder::new(tag.clone());
|
||||||
collected.insert_tagged(
|
collected.insert_value(
|
||||||
"$symbol".to_string(),
|
"$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(
|
pub fn from_bson_bytes_to_value(bytes: Vec<u8>, tag: impl Into<Tag>) -> Result<Value, ShellError> {
|
||||||
bytes: Vec<u8>,
|
|
||||||
tag: impl Into<Tag>,
|
|
||||||
) -> Result<Tagged<Value>, ShellError> {
|
|
||||||
let mut docs = Vec::new();
|
let mut docs = Vec::new();
|
||||||
let mut b_reader = BytesReader::new(bytes);
|
let mut b_reader = BytesReader::new(bytes);
|
||||||
while let Ok(v) = decode_document(&mut b_reader) {
|
while let Ok(v) = decode_document(&mut b_reader) {
|
||||||
@ -202,12 +205,12 @@ fn from_bson(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStre
|
|||||||
let input = args.input;
|
let input = args.input;
|
||||||
|
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let values: Vec<Tagged<Value>> = input.values.collect().await;
|
let values: Vec<Value> = input.values.collect().await;
|
||||||
|
|
||||||
for value in values {
|
for value in values {
|
||||||
let value_tag = value.tag();
|
let value_tag = &value.tag;
|
||||||
match value.item {
|
match value.value {
|
||||||
Value::Primitive(Primitive::Binary(vb)) =>
|
UntaggedValue::Primitive(Primitive::Binary(vb)) =>
|
||||||
match from_bson_bytes_to_value(vb, tag.clone()) {
|
match from_bson_bytes_to_value(vb, tag.clone()) {
|
||||||
Ok(x) => yield ReturnSuccess::value(x),
|
Ok(x) => yield ReturnSuccess::value(x),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
|
@ -8,7 +8,7 @@ pub struct FromCSV;
|
|||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct FromCSVArgs {
|
pub struct FromCSVArgs {
|
||||||
headerless: bool,
|
headerless: bool,
|
||||||
separator: Option<Tagged<Value>>,
|
separator: Option<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WholeStreamCommand for FromCSV {
|
impl WholeStreamCommand for FromCSV {
|
||||||
@ -47,8 +47,8 @@ fn from_csv(
|
|||||||
runnable_context: RunnableContext,
|
runnable_context: RunnableContext,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let sep = match separator {
|
let sep = match separator {
|
||||||
Some(Tagged {
|
Some(Value {
|
||||||
item: Value::Primitive(Primitive::String(s)),
|
value: UntaggedValue::Primitive(Primitive::String(s)),
|
||||||
tag,
|
tag,
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
|
@ -7,7 +7,7 @@ fn from_delimited_string_to_value(
|
|||||||
headerless: bool,
|
headerless: bool,
|
||||||
separator: char,
|
separator: char,
|
||||||
tag: impl Into<Tag>,
|
tag: impl Into<Tag>,
|
||||||
) -> Result<Tagged<Value>, csv::Error> {
|
) -> Result<Value, csv::Error> {
|
||||||
let mut reader = ReaderBuilder::new()
|
let mut reader = ReaderBuilder::new()
|
||||||
.has_headers(!headerless)
|
.has_headers(!headerless)
|
||||||
.delimiter(separator as u8)
|
.delimiter(separator as u8)
|
||||||
@ -26,15 +26,15 @@ fn from_delimited_string_to_value(
|
|||||||
for row in reader.records() {
|
for row in reader.records() {
|
||||||
let mut tagged_row = TaggedDictBuilder::new(&tag);
|
let mut tagged_row = TaggedDictBuilder::new(&tag);
|
||||||
for (value, header) in row?.iter().zip(headers.iter()) {
|
for (value, header) in row?.iter().zip(headers.iter()) {
|
||||||
tagged_row.insert_tagged(
|
tagged_row.insert_value(
|
||||||
header,
|
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(
|
pub fn from_delimited_data(
|
||||||
@ -46,16 +46,16 @@ pub fn from_delimited_data(
|
|||||||
let name_tag = name;
|
let name_tag = name;
|
||||||
|
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let values: Vec<Tagged<Value>> = input.values.collect().await;
|
let values: Vec<Value> = input.values.collect().await;
|
||||||
|
|
||||||
let mut concat_string = String::new();
|
let mut concat_string = String::new();
|
||||||
let mut latest_tag: Option<Tag> = None;
|
let mut latest_tag: Option<Tag> = None;
|
||||||
|
|
||||||
for value in values {
|
for value in values {
|
||||||
let value_tag = value.tag();
|
let value_tag = &value.tag;
|
||||||
latest_tag = Some(value_tag.clone());
|
latest_tag = Some(value_tag.clone());
|
||||||
match value.item {
|
match &value.value {
|
||||||
Value::Primitive(Primitive::String(s)) => {
|
UntaggedValue::Primitive(Primitive::String(s)) => {
|
||||||
concat_string.push_str(&s);
|
concat_string.push_str(&s);
|
||||||
concat_string.push_str("\n");
|
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()) {
|
match from_delimited_string_to_value(concat_string, headerless, sep, name_tag.clone()) {
|
||||||
Ok(x) => match x {
|
Ok(x) => match x {
|
||||||
Tagged { item: Value::Table(list), .. } => {
|
Value { value: UntaggedValue::Table(list), .. } => {
|
||||||
for l in list {
|
for l in list {
|
||||||
yield ReturnSuccess::value(l);
|
yield ReturnSuccess::value(l);
|
||||||
}
|
}
|
||||||
|
@ -27,40 +27,37 @@ impl WholeStreamCommand for FromINI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_ini_second_to_nu_value(
|
fn convert_ini_second_to_nu_value(v: &HashMap<String, String>, tag: impl Into<Tag>) -> Value {
|
||||||
v: &HashMap<String, String>,
|
|
||||||
tag: impl Into<Tag>,
|
|
||||||
) -> Tagged<Value> {
|
|
||||||
let mut second = TaggedDictBuilder::new(tag);
|
let mut second = TaggedDictBuilder::new(tag);
|
||||||
|
|
||||||
for (key, value) in v.into_iter() {
|
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(
|
fn convert_ini_top_to_nu_value(
|
||||||
v: &HashMap<String, HashMap<String, String>>,
|
v: &HashMap<String, HashMap<String, String>>,
|
||||||
tag: impl Into<Tag>,
|
tag: impl Into<Tag>,
|
||||||
) -> Tagged<Value> {
|
) -> Value {
|
||||||
let tag = tag.into();
|
let tag = tag.into();
|
||||||
let mut top_level = TaggedDictBuilder::new(tag.clone());
|
let mut top_level = TaggedDictBuilder::new(tag.clone());
|
||||||
|
|
||||||
for (key, value) in v.iter() {
|
for (key, value) in v.iter() {
|
||||||
top_level.insert_tagged(
|
top_level.insert_value(
|
||||||
key.clone(),
|
key.clone(),
|
||||||
convert_ini_second_to_nu_value(value, tag.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(
|
pub fn from_ini_string_to_value(
|
||||||
s: String,
|
s: String,
|
||||||
tag: impl Into<Tag>,
|
tag: impl Into<Tag>,
|
||||||
) -> Result<Tagged<Value>, serde_ini::de::Error> {
|
) -> Result<Value, serde_ini::de::Error> {
|
||||||
let v: HashMap<String, HashMap<String, String>> = serde_ini::from_str(&s)?;
|
let v: HashMap<String, HashMap<String, String>> = serde_ini::from_str(&s)?;
|
||||||
Ok(convert_ini_top_to_nu_value(&v, tag))
|
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<OutputStream, ShellError> {
|
fn from_ini(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
let args = args.evaluate_once(registry)?;
|
let args = args.evaluate_once(registry)?;
|
||||||
let tag = args.name_tag();
|
let tag = args.name_tag();
|
||||||
|
let span = tag.span;
|
||||||
let input = args.input;
|
let input = args.input;
|
||||||
|
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let values: Vec<Tagged<Value>> = input.values.collect().await;
|
let values: Vec<Value> = input.values.collect().await;
|
||||||
|
|
||||||
let mut concat_string = String::new();
|
let mut concat_string = String::new();
|
||||||
let mut latest_tag: Option<Tag> = None;
|
let mut latest_tag: Option<Tag> = None;
|
||||||
|
|
||||||
for value in values {
|
for value in values {
|
||||||
let value_tag = value.tag();
|
latest_tag = Some(value.tag.clone());
|
||||||
latest_tag = Some(value_tag.clone());
|
let value_span = value.tag.span;
|
||||||
match value.item {
|
match &value.value {
|
||||||
Value::Primitive(Primitive::String(s)) => {
|
UntaggedValue::Primitive(Primitive::String(s)) => {
|
||||||
concat_string.push_str(&s);
|
concat_string.push_str(&s);
|
||||||
concat_string.push_str("\n");
|
concat_string.push_str("\n");
|
||||||
}
|
}
|
||||||
_ => yield Err(ShellError::labeled_error_with_secondary(
|
_ => yield Err(ShellError::labeled_error_with_secondary(
|
||||||
"Expected a string from pipeline",
|
"Expected a string from pipeline",
|
||||||
"requires string input",
|
"requires string input",
|
||||||
&tag,
|
span,
|
||||||
"value originates from here",
|
"value originates from here",
|
||||||
&value_tag,
|
value_span,
|
||||||
)),
|
)),
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -97,7 +95,7 @@ fn from_ini(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStrea
|
|||||||
|
|
||||||
match from_ini_string_to_value(concat_string, tag.clone()) {
|
match from_ini_string_to_value(concat_string, tag.clone()) {
|
||||||
Ok(x) => match x {
|
Ok(x) => match x {
|
||||||
Tagged { item: Value::Table(list), .. } => {
|
Value { value: UntaggedValue::Table(list), .. } => {
|
||||||
for l in list {
|
for l in list {
|
||||||
yield ReturnSuccess::value(l);
|
yield ReturnSuccess::value(l);
|
||||||
}
|
}
|
||||||
|
@ -31,39 +31,36 @@ impl WholeStreamCommand for FromJSON {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_json_value_to_nu_value(v: &serde_hjson::Value, tag: impl Into<Tag>) -> Tagged<Value> {
|
fn convert_json_value_to_nu_value(v: &serde_hjson::Value, tag: impl Into<Tag>) -> Value {
|
||||||
let tag = tag.into();
|
let tag = tag.into();
|
||||||
|
|
||||||
match v {
|
match v {
|
||||||
serde_hjson::Value::Null => Value::Primitive(Primitive::Nothing).tagged(&tag),
|
serde_hjson::Value::Null => UntaggedValue::Primitive(Primitive::Nothing).into_value(&tag),
|
||||||
serde_hjson::Value::Bool(b) => Value::boolean(*b).tagged(&tag),
|
serde_hjson::Value::Bool(b) => UntaggedValue::boolean(*b).into_value(&tag),
|
||||||
serde_hjson::Value::F64(n) => Value::number(n).tagged(&tag),
|
serde_hjson::Value::F64(n) => UntaggedValue::number(n).into_value(&tag),
|
||||||
serde_hjson::Value::U64(n) => Value::number(n).tagged(&tag),
|
serde_hjson::Value::U64(n) => UntaggedValue::number(n).into_value(&tag),
|
||||||
serde_hjson::Value::I64(n) => Value::number(n).tagged(&tag),
|
serde_hjson::Value::I64(n) => UntaggedValue::number(n).into_value(&tag),
|
||||||
serde_hjson::Value::String(s) => {
|
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()
|
a.iter()
|
||||||
.map(|x| convert_json_value_to_nu_value(x, &tag))
|
.map(|x| convert_json_value_to_nu_value(x, &tag))
|
||||||
.collect(),
|
.collect(),
|
||||||
)
|
)
|
||||||
.tagged(tag),
|
.into_value(tag),
|
||||||
serde_hjson::Value::Object(o) => {
|
serde_hjson::Value::Object(o) => {
|
||||||
let mut collected = TaggedDictBuilder::new(&tag);
|
let mut collected = TaggedDictBuilder::new(&tag);
|
||||||
for (k, v) in o.iter() {
|
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(
|
pub fn from_json_string_to_value(s: String, tag: impl Into<Tag>) -> serde_hjson::Result<Value> {
|
||||||
s: String,
|
|
||||||
tag: impl Into<Tag>,
|
|
||||||
) -> serde_hjson::Result<Tagged<Value>> {
|
|
||||||
let v: serde_hjson::Value = serde_hjson::from_str(&s)?;
|
let v: serde_hjson::Value = serde_hjson::from_str(&s)?;
|
||||||
Ok(convert_json_value_to_nu_value(&v, tag))
|
Ok(convert_json_value_to_nu_value(&v, tag))
|
||||||
}
|
}
|
||||||
@ -72,28 +69,29 @@ fn from_json(
|
|||||||
FromJSONArgs { objects }: FromJSONArgs,
|
FromJSONArgs { objects }: FromJSONArgs,
|
||||||
RunnableContext { input, name, .. }: RunnableContext,
|
RunnableContext { input, name, .. }: RunnableContext,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
|
let name_span = name.span;
|
||||||
let name_tag = name;
|
let name_tag = name;
|
||||||
|
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let values: Vec<Tagged<Value>> = input.values.collect().await;
|
let values: Vec<Value> = input.values.collect().await;
|
||||||
|
|
||||||
let mut concat_string = String::new();
|
let mut concat_string = String::new();
|
||||||
let mut latest_tag: Option<Tag> = None;
|
let mut latest_tag: Option<Tag> = None;
|
||||||
|
|
||||||
for value in values {
|
for value in values {
|
||||||
let value_tag = value.tag();
|
latest_tag = Some(value.tag.clone());
|
||||||
latest_tag = Some(value_tag.clone());
|
let value_span = value.tag.span;
|
||||||
match value.item {
|
match &value.value {
|
||||||
Value::Primitive(Primitive::String(s)) => {
|
UntaggedValue::Primitive(Primitive::String(s)) => {
|
||||||
concat_string.push_str(&s);
|
concat_string.push_str(&s);
|
||||||
concat_string.push_str("\n");
|
concat_string.push_str("\n");
|
||||||
}
|
}
|
||||||
_ => yield Err(ShellError::labeled_error_with_secondary(
|
_ => yield Err(ShellError::labeled_error_with_secondary(
|
||||||
"Expected a string from pipeline",
|
"Expected a string from pipeline",
|
||||||
"requires string input",
|
"requires string input",
|
||||||
&name_tag,
|
name_span,
|
||||||
"value originates from here",
|
"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()) {
|
match from_json_string_to_value(concat_string, name_tag.clone()) {
|
||||||
Ok(x) =>
|
Ok(x) =>
|
||||||
match x {
|
match x {
|
||||||
Tagged { item: Value::Table(list), .. } => {
|
Value { value: UntaggedValue::Table(list), .. } => {
|
||||||
for l in list {
|
for l in list {
|
||||||
yield ReturnSuccess::value(l);
|
yield ReturnSuccess::value(l);
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ impl WholeStreamCommand for FromDB {
|
|||||||
pub fn convert_sqlite_file_to_nu_value(
|
pub fn convert_sqlite_file_to_nu_value(
|
||||||
path: &Path,
|
path: &Path,
|
||||||
tag: impl Into<Tag> + Clone,
|
tag: impl Into<Tag> + Clone,
|
||||||
) -> Result<Tagged<Value>, rusqlite::Error> {
|
) -> Result<Value, rusqlite::Error> {
|
||||||
let conn = Connection::open(path)?;
|
let conn = Connection::open(path)?;
|
||||||
|
|
||||||
let mut meta_out = Vec::new();
|
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()? {
|
while let Some(table_row) = table_rows.next()? {
|
||||||
out.push(convert_sqlite_row_to_nu_value(table_row, tag.clone())?)
|
out.push(convert_sqlite_row_to_nu_value(table_row, tag.clone())?)
|
||||||
}
|
}
|
||||||
meta_dict.insert_tagged(
|
meta_dict.insert_value(
|
||||||
"table_name".to_string(),
|
"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_dict.insert_value(
|
||||||
meta_out.push(meta_dict.into_tagged_value());
|
"table_values",
|
||||||
|
UntaggedValue::Table(out).into_value(tag.clone()),
|
||||||
|
);
|
||||||
|
meta_out.push(meta_dict.into_value());
|
||||||
}
|
}
|
||||||
let tag = tag.into();
|
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(
|
fn convert_sqlite_row_to_nu_value(
|
||||||
row: &Row,
|
row: &Row,
|
||||||
tag: impl Into<Tag> + Clone,
|
tag: impl Into<Tag> + Clone,
|
||||||
) -> Result<Tagged<Value>, rusqlite::Error> {
|
) -> Result<Value, rusqlite::Error> {
|
||||||
let mut collected = TaggedDictBuilder::new(tag.clone());
|
let mut collected = TaggedDictBuilder::new(tag.clone());
|
||||||
for (i, c) in row.columns().iter().enumerate() {
|
for (i, c) in row.columns().iter().enumerate() {
|
||||||
collected.insert_tagged(
|
collected.insert_value(
|
||||||
c.name().to_string(),
|
c.name().to_string(),
|
||||||
convert_sqlite_value_to_nu_value(row.get_raw(i), tag.clone()),
|
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<Tag> + Clone) -> Tagged<Value> {
|
fn convert_sqlite_value_to_nu_value(value: ValueRef, tag: impl Into<Tag> + Clone) -> Value {
|
||||||
match value {
|
match value {
|
||||||
ValueRef::Null => Value::Primitive(Primitive::String(String::from(""))).tagged(tag),
|
ValueRef::Null => {
|
||||||
ValueRef::Integer(i) => Value::number(i).tagged(tag),
|
UntaggedValue::Primitive(Primitive::String(String::from(""))).into_value(tag)
|
||||||
ValueRef::Real(f) => Value::number(f).tagged(tag),
|
}
|
||||||
|
ValueRef::Integer(i) => UntaggedValue::number(i).into_value(tag),
|
||||||
|
ValueRef::Real(f) => UntaggedValue::number(f).into_value(tag),
|
||||||
t @ ValueRef::Text(_) => {
|
t @ ValueRef::Text(_) => {
|
||||||
// this unwrap is safe because we know the ValueRef is 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(
|
pub fn from_sqlite_bytes_to_value(
|
||||||
mut bytes: Vec<u8>,
|
mut bytes: Vec<u8>,
|
||||||
tag: impl Into<Tag> + Clone,
|
tag: impl Into<Tag> + Clone,
|
||||||
) -> Result<Tagged<Value>, std::io::Error> {
|
) -> Result<Value, std::io::Error> {
|
||||||
// FIXME: should probably write a sqlite virtual filesystem
|
// FIXME: should probably write a sqlite virtual filesystem
|
||||||
// that will allow us to use bytes as a file to avoid this
|
// that will allow us to use bytes as a file to avoid this
|
||||||
// write out, but this will require C code. Might be
|
// write out, but this will require C code. Might be
|
||||||
@ -132,15 +138,15 @@ fn from_sqlite(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputSt
|
|||||||
let input = args.input;
|
let input = args.input;
|
||||||
|
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let values: Vec<Tagged<Value>> = input.values.collect().await;
|
let values: Vec<Value> = input.values.collect().await;
|
||||||
|
|
||||||
for value in values {
|
for value in values {
|
||||||
let value_tag = value.tag();
|
let value_tag = &value.tag;
|
||||||
match value.item {
|
match value.value {
|
||||||
Value::Primitive(Primitive::Binary(vb)) =>
|
UntaggedValue::Primitive(Primitive::Binary(vb)) =>
|
||||||
match from_sqlite_bytes_to_value(vb, tag.clone()) {
|
match from_sqlite_bytes_to_value(vb, tag.clone()) {
|
||||||
Ok(x) => match x {
|
Ok(x) => match x {
|
||||||
Tagged { item: Value::Table(list), .. } => {
|
Value { value: UntaggedValue::Table(list), .. } => {
|
||||||
for l in list {
|
for l in list {
|
||||||
yield ReturnSuccess::value(l);
|
yield ReturnSuccess::value(l);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
use crate::commands::WholeStreamCommand;
|
||||||
use crate::data::{Primitive, TaggedDictBuilder, Value};
|
use crate::data::{Primitive, TaggedDictBuilder, Value};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_source::Tagged;
|
||||||
|
|
||||||
pub struct FromSSV;
|
pub struct FromSSV;
|
||||||
|
|
||||||
@ -223,23 +224,24 @@ fn from_ssv_string_to_value(
|
|||||||
aligned_columns: bool,
|
aligned_columns: bool,
|
||||||
split_at: usize,
|
split_at: usize,
|
||||||
tag: impl Into<Tag>,
|
tag: impl Into<Tag>,
|
||||||
) -> Option<Tagged<Value>> {
|
) -> Option<Value> {
|
||||||
let tag = tag.into();
|
let tag = tag.into();
|
||||||
let rows = string_to_table(s, headerless, aligned_columns, split_at)?
|
let rows = string_to_table(s, headerless, aligned_columns, split_at)?
|
||||||
.iter()
|
.iter()
|
||||||
.map(|row| {
|
.map(|row| {
|
||||||
let mut tagged_dict = TaggedDictBuilder::new(&tag);
|
let mut tagged_dict = TaggedDictBuilder::new(&tag);
|
||||||
for (col, entry) in row {
|
for (col, entry) in row {
|
||||||
tagged_dict.insert_tagged(
|
tagged_dict.insert_value(
|
||||||
col,
|
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();
|
.collect();
|
||||||
|
|
||||||
Some(Value::Table(rows).tagged(&tag))
|
Some(UntaggedValue::Table(rows).into_value(&tag))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_ssv(
|
fn from_ssv(
|
||||||
@ -251,7 +253,7 @@ fn from_ssv(
|
|||||||
RunnableContext { input, name, .. }: RunnableContext,
|
RunnableContext { input, name, .. }: RunnableContext,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let values: Vec<Tagged<Value>> = input.values.collect().await;
|
let values: Vec<Value> = input.values.collect().await;
|
||||||
let mut concat_string = String::new();
|
let mut concat_string = String::new();
|
||||||
let mut latest_tag: Option<Tag> = None;
|
let mut latest_tag: Option<Tag> = None;
|
||||||
let split_at = match minimum_spaces {
|
let split_at = match minimum_spaces {
|
||||||
@ -260,10 +262,10 @@ fn from_ssv(
|
|||||||
};
|
};
|
||||||
|
|
||||||
for value in values {
|
for value in values {
|
||||||
let value_tag = value.tag();
|
let value_tag = value.tag.clone();
|
||||||
latest_tag = Some(value_tag.clone());
|
latest_tag = Some(value_tag.clone());
|
||||||
match value.item {
|
match &value.value {
|
||||||
Value::Primitive(Primitive::String(s)) => {
|
UntaggedValue::Primitive(Primitive::String(s)) => {
|
||||||
concat_string.push_str(&s);
|
concat_string.push_str(&s);
|
||||||
}
|
}
|
||||||
_ => yield Err(ShellError::labeled_error_with_secondary (
|
_ => 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()) {
|
match from_ssv_string_to_value(&concat_string, headerless, aligned_columns, split_at, name.clone()) {
|
||||||
Some(x) => match x {
|
Some(x) => match x {
|
||||||
Tagged { item: Value::Table(list), ..} => {
|
Value { value: UntaggedValue::Table(list), ..} => {
|
||||||
for l in list { yield ReturnSuccess::value(l) }
|
for l in list { yield ReturnSuccess::value(l) }
|
||||||
}
|
}
|
||||||
x => yield ReturnSuccess::value(x)
|
x => yield ReturnSuccess::value(x)
|
||||||
|
@ -26,39 +26,38 @@ impl WholeStreamCommand for FromTOML {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn convert_toml_value_to_nu_value(v: &toml::Value, tag: impl Into<Tag>) -> Tagged<Value> {
|
pub fn convert_toml_value_to_nu_value(v: &toml::Value, tag: impl Into<Tag>) -> Value {
|
||||||
let tag = tag.into();
|
let tag = tag.into();
|
||||||
|
|
||||||
match v {
|
match v {
|
||||||
toml::Value::Boolean(b) => Value::boolean(*b).tagged(tag),
|
toml::Value::Boolean(b) => UntaggedValue::boolean(*b).into_value(tag),
|
||||||
toml::Value::Integer(n) => Value::number(n).tagged(tag),
|
toml::Value::Integer(n) => UntaggedValue::number(n).into_value(tag),
|
||||||
toml::Value::Float(n) => Value::number(n).tagged(tag),
|
toml::Value::Float(n) => UntaggedValue::number(n).into_value(tag),
|
||||||
toml::Value::String(s) => Value::Primitive(Primitive::String(String::from(s))).tagged(tag),
|
toml::Value::String(s) => {
|
||||||
toml::Value::Array(a) => Value::Table(
|
UntaggedValue::Primitive(Primitive::String(String::from(s))).into_value(tag)
|
||||||
|
}
|
||||||
|
toml::Value::Array(a) => UntaggedValue::Table(
|
||||||
a.iter()
|
a.iter()
|
||||||
.map(|x| convert_toml_value_to_nu_value(x, &tag))
|
.map(|x| convert_toml_value_to_nu_value(x, &tag))
|
||||||
.collect(),
|
.collect(),
|
||||||
)
|
)
|
||||||
.tagged(tag),
|
.into_value(tag),
|
||||||
toml::Value::Datetime(dt) => {
|
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) => {
|
toml::Value::Table(t) => {
|
||||||
let mut collected = TaggedDictBuilder::new(&tag);
|
let mut collected = TaggedDictBuilder::new(&tag);
|
||||||
|
|
||||||
for (k, v) in t.iter() {
|
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(
|
pub fn from_toml_string_to_value(s: String, tag: impl Into<Tag>) -> Result<Value, toml::de::Error> {
|
||||||
s: String,
|
|
||||||
tag: impl Into<Tag>,
|
|
||||||
) -> Result<Tagged<Value>, toml::de::Error> {
|
|
||||||
let v: toml::Value = s.parse::<toml::Value>()?;
|
let v: toml::Value = s.parse::<toml::Value>()?;
|
||||||
Ok(convert_toml_value_to_nu_value(&v, tag))
|
Ok(convert_toml_value_to_nu_value(&v, tag))
|
||||||
}
|
}
|
||||||
@ -69,28 +68,29 @@ pub fn from_toml(
|
|||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let args = args.evaluate_once(registry)?;
|
let args = args.evaluate_once(registry)?;
|
||||||
let tag = args.name_tag();
|
let tag = args.name_tag();
|
||||||
|
let name_span = tag.span;
|
||||||
let input = args.input;
|
let input = args.input;
|
||||||
|
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let values: Vec<Tagged<Value>> = input.values.collect().await;
|
let values: Vec<Value> = input.values.collect().await;
|
||||||
|
|
||||||
let mut concat_string = String::new();
|
let mut concat_string = String::new();
|
||||||
let mut latest_tag: Option<Tag> = None;
|
let mut latest_tag: Option<Tag> = None;
|
||||||
|
|
||||||
for value in values {
|
for value in values {
|
||||||
let value_tag = value.tag();
|
latest_tag = Some(value.tag.clone());
|
||||||
latest_tag = Some(value_tag.clone());
|
let value_span = value.tag.span;
|
||||||
match value.item {
|
match value.value {
|
||||||
Value::Primitive(Primitive::String(s)) => {
|
UntaggedValue::Primitive(Primitive::String(s)) => {
|
||||||
concat_string.push_str(&s);
|
concat_string.push_str(&s);
|
||||||
concat_string.push_str("\n");
|
concat_string.push_str("\n");
|
||||||
}
|
}
|
||||||
_ => yield Err(ShellError::labeled_error_with_secondary(
|
_ => yield Err(ShellError::labeled_error_with_secondary(
|
||||||
"Expected a string from pipeline",
|
"Expected a string from pipeline",
|
||||||
"requires string input",
|
"requires string input",
|
||||||
&tag,
|
name_span,
|
||||||
"value originates from here",
|
"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()) {
|
match from_toml_string_to_value(concat_string, tag.clone()) {
|
||||||
Ok(x) => match x {
|
Ok(x) => match x {
|
||||||
Tagged { item: Value::Table(list), .. } => {
|
Value { value: UntaggedValue::Table(list), .. } => {
|
||||||
for l in list {
|
for l in list {
|
||||||
yield ReturnSuccess::value(l);
|
yield ReturnSuccess::value(l);
|
||||||
}
|
}
|
||||||
|
@ -29,27 +29,28 @@ impl WholeStreamCommand for FromURL {
|
|||||||
fn from_url(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
fn from_url(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
let args = args.evaluate_once(registry)?;
|
let args = args.evaluate_once(registry)?;
|
||||||
let tag = args.name_tag();
|
let tag = args.name_tag();
|
||||||
|
let name_span = tag.span;
|
||||||
let input = args.input;
|
let input = args.input;
|
||||||
|
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let values: Vec<Tagged<Value>> = input.values.collect().await;
|
let values: Vec<Value> = input.values.collect().await;
|
||||||
|
|
||||||
let mut concat_string = String::new();
|
let mut concat_string = String::new();
|
||||||
let mut latest_tag: Option<Tag> = None;
|
let mut latest_tag: Option<Tag> = None;
|
||||||
|
|
||||||
for value in values {
|
for value in values {
|
||||||
let value_tag = value.tag();
|
latest_tag = Some(value.tag.clone());
|
||||||
latest_tag = Some(value_tag.clone());
|
let value_span = value.tag.span;
|
||||||
match value.item {
|
match value.value {
|
||||||
Value::Primitive(Primitive::String(s)) => {
|
UntaggedValue::Primitive(Primitive::String(s)) => {
|
||||||
concat_string.push_str(&s);
|
concat_string.push_str(&s);
|
||||||
}
|
}
|
||||||
_ => yield Err(ShellError::labeled_error_with_secondary(
|
_ => yield Err(ShellError::labeled_error_with_secondary(
|
||||||
"Expected a string from pipeline",
|
"Expected a string from pipeline",
|
||||||
"requires string input",
|
"requires string input",
|
||||||
&tag,
|
name_span,
|
||||||
"value originates from here",
|
"value originates from here",
|
||||||
&value_tag,
|
value_span,
|
||||||
)),
|
)),
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -62,10 +63,10 @@ fn from_url(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStrea
|
|||||||
let mut row = TaggedDictBuilder::new(tag);
|
let mut row = TaggedDictBuilder::new(tag);
|
||||||
|
|
||||||
for (k,v) in result {
|
for (k,v) in result {
|
||||||
row.insert(k, Value::string(v));
|
row.insert_untagged(k, UntaggedValue::string(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
yield ReturnSuccess::value(row.into_tagged_value());
|
yield ReturnSuccess::value(row.into_value());
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if let Some(last_tag) = latest_tag {
|
if let Some(last_tag) = latest_tag {
|
||||||
|
@ -45,12 +45,14 @@ fn from_xlsx(
|
|||||||
let tag = runnable_context.name;
|
let tag = runnable_context.name;
|
||||||
|
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let values: Vec<Tagged<Value>> = input.values.collect().await;
|
let values: Vec<Value> = input.values.collect().await;
|
||||||
|
|
||||||
for value in values {
|
for value in values {
|
||||||
let value_tag = value.tag();
|
let value_span = value.tag.span;
|
||||||
match value.item {
|
let value_tag = value.tag.clone();
|
||||||
Value::Primitive(Primitive::Binary(vb)) => {
|
|
||||||
|
match value.value {
|
||||||
|
UntaggedValue::Primitive(Primitive::Binary(vb)) => {
|
||||||
let mut buf: Cursor<Vec<u8>> = Cursor::new(vb);
|
let mut buf: Cursor<Vec<u8>> = Cursor::new(vb);
|
||||||
let mut xls = Xlsx::<_>::new(buf).unwrap();
|
let mut xls = Xlsx::<_>::new(buf).unwrap();
|
||||||
|
|
||||||
@ -67,24 +69,24 @@ fn from_xlsx(
|
|||||||
let mut row_output = TaggedDictBuilder::new(&tag);
|
let mut row_output = TaggedDictBuilder::new(&tag);
|
||||||
for (i, cell) in row.iter().enumerate() {
|
for (i, cell) in row.iter().enumerate() {
|
||||||
let value = match cell {
|
let value = match cell {
|
||||||
DataType::Empty => Value::nothing(),
|
DataType::Empty => UntaggedValue::nothing(),
|
||||||
DataType::String(s) => Value::string(s),
|
DataType::String(s) => UntaggedValue::string(s),
|
||||||
DataType::Float(f) => Value::decimal(*f),
|
DataType::Float(f) => UntaggedValue::decimal(*f),
|
||||||
DataType::Int(i) => Value::int(*i),
|
DataType::Int(i) => UntaggedValue::int(*i),
|
||||||
DataType::Bool(b) => Value::boolean(*b),
|
DataType::Bool(b) => UntaggedValue::boolean(*b),
|
||||||
_ => Value::nothing(),
|
_ => 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(
|
_ => yield Err(ShellError::labeled_error_with_secondary(
|
||||||
"Expected binary data from pipeline",
|
"Expected binary data from pipeline",
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
use crate::commands::WholeStreamCommand;
|
||||||
use crate::data::{Primitive, TaggedDictBuilder, Value};
|
use crate::data::base::{Primitive, UntaggedValue, Value};
|
||||||
|
use crate::data::TaggedDictBuilder;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub struct FromXML;
|
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<Tag>) -> Tagged<Value> {
|
fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>, tag: impl Into<Tag>) -> Value {
|
||||||
let tag = tag.into();
|
let tag = tag.into();
|
||||||
|
|
||||||
if n.is_element() {
|
if n.is_element() {
|
||||||
@ -37,11 +38,11 @@ fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>, tag: impl Into<Tag>)
|
|||||||
children_values.push(from_node_to_value(&c, &tag));
|
children_values.push(from_node_to_value(&c, &tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
let children_values: Vec<Tagged<Value>> = children_values
|
let children_values: Vec<Value> = children_values
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|x| match x {
|
.filter(|x| match x {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Primitive(Primitive::String(f)),
|
value: UntaggedValue::Primitive(Primitive::String(f)),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
if f.trim() == "" {
|
if f.trim() == "" {
|
||||||
@ -55,28 +56,25 @@ fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>, tag: impl Into<Tag>)
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mut collected = TaggedDictBuilder::new(tag);
|
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() {
|
} else if n.is_comment() {
|
||||||
Value::string("<comment>").tagged(tag)
|
UntaggedValue::string("<comment>").into_value(tag)
|
||||||
} else if n.is_pi() {
|
} else if n.is_pi() {
|
||||||
Value::string("<processing_instruction>").tagged(tag)
|
UntaggedValue::string("<processing_instruction>").into_value(tag)
|
||||||
} else if n.is_text() {
|
} else if n.is_text() {
|
||||||
Value::string(n.text().unwrap()).tagged(tag)
|
UntaggedValue::string(n.text().unwrap()).into_value(tag)
|
||||||
} else {
|
} else {
|
||||||
Value::string("<unknown>").tagged(tag)
|
UntaggedValue::string("<unknown>").into_value(tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_document_to_value(d: &roxmltree::Document, tag: impl Into<Tag>) -> Tagged<Value> {
|
fn from_document_to_value(d: &roxmltree::Document, tag: impl Into<Tag>) -> Value {
|
||||||
from_node_to_value(&d.root_element(), tag)
|
from_node_to_value(&d.root_element(), tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_xml_string_to_value(
|
pub fn from_xml_string_to_value(s: String, tag: impl Into<Tag>) -> Result<Value, roxmltree::Error> {
|
||||||
s: String,
|
|
||||||
tag: impl Into<Tag>,
|
|
||||||
) -> Result<Tagged<Value>, roxmltree::Error> {
|
|
||||||
let parsed = roxmltree::Document::parse(&s)?;
|
let parsed = roxmltree::Document::parse(&s)?;
|
||||||
Ok(from_document_to_value(&parsed, tag))
|
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<OutputStream, ShellError> {
|
fn from_xml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
let args = args.evaluate_once(registry)?;
|
let args = args.evaluate_once(registry)?;
|
||||||
let tag = args.name_tag();
|
let tag = args.name_tag();
|
||||||
|
let name_span = tag.span;
|
||||||
let input = args.input;
|
let input = args.input;
|
||||||
|
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let values: Vec<Tagged<Value>> = input.values.collect().await;
|
let values: Vec<Value> = input.values.collect().await;
|
||||||
|
|
||||||
let mut concat_string = String::new();
|
let mut concat_string = String::new();
|
||||||
let mut latest_tag: Option<Tag> = None;
|
let mut latest_tag: Option<Tag> = None;
|
||||||
|
|
||||||
for value in values {
|
for value in values {
|
||||||
let value_tag = value.tag();
|
latest_tag = Some(value.tag.clone());
|
||||||
latest_tag = Some(value_tag.clone());
|
let value_span = value.tag.span;
|
||||||
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(&s);
|
||||||
concat_string.push_str("\n");
|
concat_string.push_str("\n");
|
||||||
}
|
}
|
||||||
_ => yield Err(ShellError::labeled_error_with_secondary(
|
_ => yield Err(ShellError::labeled_error_with_secondary(
|
||||||
"Expected a string from pipeline",
|
"Expected a string from pipeline",
|
||||||
"requires string input",
|
"requires string input",
|
||||||
&tag,
|
name_span,
|
||||||
"value originates from here",
|
"value originates from here",
|
||||||
&value_tag,
|
value_span,
|
||||||
)),
|
)),
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -113,7 +113,7 @@ fn from_xml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStrea
|
|||||||
|
|
||||||
match from_xml_string_to_value(concat_string, tag.clone()) {
|
match from_xml_string_to_value(concat_string, tag.clone()) {
|
||||||
Ok(x) => match x {
|
Ok(x) => match x {
|
||||||
Tagged { item: Value::Table(list), .. } => {
|
Value { value: UntaggedValue::Table(list), .. } => {
|
||||||
for l in list {
|
for l in list {
|
||||||
yield ReturnSuccess::value(l);
|
yield ReturnSuccess::value(l);
|
||||||
}
|
}
|
||||||
@ -139,23 +139,23 @@ fn from_xml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStrea
|
|||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::commands::from_xml;
|
use crate::commands::from_xml;
|
||||||
use crate::data::meta::*;
|
use crate::data::base::{UntaggedValue, Value};
|
||||||
use crate::Value;
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
use nu_source::*;
|
||||||
|
|
||||||
fn string(input: impl Into<String>) -> Tagged<Value> {
|
fn string(input: impl Into<String>) -> Value {
|
||||||
Value::string(input.into()).tagged_unknown()
|
UntaggedValue::string(input.into()).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn row(entries: IndexMap<String, Tagged<Value>>) -> Tagged<Value> {
|
fn row(entries: IndexMap<String, Value>) -> Value {
|
||||||
Value::row(entries).tagged_unknown()
|
UntaggedValue::row(entries).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn table(list: &Vec<Tagged<Value>>) -> Tagged<Value> {
|
fn table(list: &Vec<Value>) -> Value {
|
||||||
Value::table(list).tagged_unknown()
|
UntaggedValue::table(list).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse(xml: &str) -> Tagged<Value> {
|
fn parse(xml: &str) -> Value {
|
||||||
from_xml::from_xml_string_to_value(xml.to_string(), Tag::unknown()).unwrap()
|
from_xml::from_xml_string_to_value(xml.to_string(), Tag::unknown()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,47 +50,44 @@ impl WholeStreamCommand for FromYML {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_yaml_value_to_nu_value(v: &serde_yaml::Value, tag: impl Into<Tag>) -> Tagged<Value> {
|
fn convert_yaml_value_to_nu_value(v: &serde_yaml::Value, tag: impl Into<Tag>) -> Value {
|
||||||
let tag = tag.into();
|
let tag = tag.into();
|
||||||
|
|
||||||
match v {
|
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() => {
|
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() => {
|
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::String(s) => UntaggedValue::string(s).into_value(tag),
|
||||||
serde_yaml::Value::Sequence(a) => Value::Table(
|
serde_yaml::Value::Sequence(a) => UntaggedValue::Table(
|
||||||
a.iter()
|
a.iter()
|
||||||
.map(|x| convert_yaml_value_to_nu_value(x, &tag))
|
.map(|x| convert_yaml_value_to_nu_value(x, &tag))
|
||||||
.collect(),
|
.collect(),
|
||||||
)
|
)
|
||||||
.tagged(tag),
|
.into_value(tag),
|
||||||
serde_yaml::Value::Mapping(t) => {
|
serde_yaml::Value::Mapping(t) => {
|
||||||
let mut collected = TaggedDictBuilder::new(&tag);
|
let mut collected = TaggedDictBuilder::new(&tag);
|
||||||
|
|
||||||
for (k, v) in t.iter() {
|
for (k, v) in t.iter() {
|
||||||
match k {
|
match k {
|
||||||
serde_yaml::Value::String(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"),
|
_ => 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),
|
x => unimplemented!("Unsupported yaml case: {:?}", x),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_yaml_string_to_value(
|
pub fn from_yaml_string_to_value(s: String, tag: impl Into<Tag>) -> serde_yaml::Result<Value> {
|
||||||
s: String,
|
|
||||||
tag: impl Into<Tag>,
|
|
||||||
) -> serde_yaml::Result<Tagged<Value>> {
|
|
||||||
let v: serde_yaml::Value = serde_yaml::from_str(&s)?;
|
let v: serde_yaml::Value = serde_yaml::from_str(&s)?;
|
||||||
Ok(convert_yaml_value_to_nu_value(&v, tag))
|
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<OutputStream, ShellError> {
|
fn from_yaml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
let args = args.evaluate_once(registry)?;
|
let args = args.evaluate_once(registry)?;
|
||||||
let tag = args.name_tag();
|
let tag = args.name_tag();
|
||||||
|
let name_span = tag.span;
|
||||||
let input = args.input;
|
let input = args.input;
|
||||||
|
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let values: Vec<Tagged<Value>> = input.values.collect().await;
|
let values: Vec<Value> = input.values.collect().await;
|
||||||
|
|
||||||
let mut concat_string = String::new();
|
let mut concat_string = String::new();
|
||||||
let mut latest_tag: Option<Tag> = None;
|
let mut latest_tag: Option<Tag> = None;
|
||||||
|
|
||||||
for value in values {
|
for value in values {
|
||||||
let value_tag = value.tag();
|
latest_tag = Some(value.tag.clone());
|
||||||
latest_tag = Some(value_tag.clone());
|
let value_span = value.tag.span;
|
||||||
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(&s);
|
||||||
concat_string.push_str("\n");
|
concat_string.push_str("\n");
|
||||||
}
|
}
|
||||||
_ => yield Err(ShellError::labeled_error_with_secondary(
|
_ => yield Err(ShellError::labeled_error_with_secondary(
|
||||||
"Expected a string from pipeline",
|
"Expected a string from pipeline",
|
||||||
"requires string input",
|
"requires string input",
|
||||||
&tag,
|
name_span,
|
||||||
"value originates from here",
|
"value originates from here",
|
||||||
&value_tag,
|
value_span,
|
||||||
)),
|
)),
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -127,7 +126,7 @@ fn from_yaml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStre
|
|||||||
|
|
||||||
match from_yaml_string_to_value(concat_string, tag.clone()) {
|
match from_yaml_string_to_value(concat_string, tag.clone()) {
|
||||||
Ok(x) => match x {
|
Ok(x) => match x {
|
||||||
Tagged { item: Value::Table(list), .. } => {
|
Value { value: UntaggedValue::Table(list), .. } => {
|
||||||
for l in list {
|
for l in list {
|
||||||
yield ReturnSuccess::value(l);
|
yield ReturnSuccess::value(l);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ use crate::utils::did_you_mean;
|
|||||||
use crate::ColumnPath;
|
use crate::ColumnPath;
|
||||||
use futures_util::pin_mut;
|
use futures_util::pin_mut;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
use nu_source::{span_for_spanned_list, PrettyDebug};
|
||||||
|
|
||||||
pub struct Get;
|
pub struct Get;
|
||||||
|
|
||||||
@ -40,31 +41,31 @@ impl WholeStreamCommand for Get {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_column_path(
|
pub fn get_column_path(path: &ColumnPath, obj: &Value) -> Result<Value, ShellError> {
|
||||||
path: &ColumnPath,
|
|
||||||
obj: &Tagged<Value>,
|
|
||||||
) -> Result<Tagged<Value>, ShellError> {
|
|
||||||
let fields = path.clone();
|
let fields = path.clone();
|
||||||
|
|
||||||
let value = obj.get_data_by_column_path(
|
obj.get_data_by_column_path(
|
||||||
path,
|
path,
|
||||||
Box::new(move |(obj_source, column_path_tried, error)| {
|
Box::new(move |(obj_source, column_path_tried, error)| {
|
||||||
match obj_source {
|
match &obj_source.value {
|
||||||
Value::Table(rows) => {
|
UntaggedValue::Table(rows) => {
|
||||||
let total = rows.len();
|
let total = rows.len();
|
||||||
let end_tag = match fields
|
let end_tag = match fields
|
||||||
.members()
|
.members()
|
||||||
.iter()
|
.iter()
|
||||||
.nth_back(if fields.members().len() > 2 { 1 } else { 0 })
|
.nth_back(if fields.members().len() > 2 { 1 } else { 0 })
|
||||||
{
|
{
|
||||||
Some(last_field) => last_field.span(),
|
Some(last_field) => last_field.span,
|
||||||
None => column_path_tried.span(),
|
None => column_path_tried.span,
|
||||||
};
|
};
|
||||||
|
|
||||||
return ShellError::labeled_error_with_secondary(
|
return ShellError::labeled_error_with_secondary(
|
||||||
"Row not found",
|
"Row not found",
|
||||||
format!("There isn't a row indexed at {}", **column_path_tried),
|
format!(
|
||||||
column_path_tried.span(),
|
"There isn't a row indexed at {}",
|
||||||
|
column_path_tried.display()
|
||||||
|
),
|
||||||
|
column_path_tried.span,
|
||||||
if total == 1 {
|
if total == 1 {
|
||||||
format!("The table only has 1 row")
|
format!("The table only has 1 row")
|
||||||
} else {
|
} else {
|
||||||
@ -81,7 +82,7 @@ pub fn get_column_path(
|
|||||||
return ShellError::labeled_error(
|
return ShellError::labeled_error(
|
||||||
"Unknown column",
|
"Unknown column",
|
||||||
format!("did you mean '{}'?", suggestions[0].1),
|
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 => {}
|
None => {}
|
||||||
@ -89,14 +90,7 @@ pub fn get_column_path(
|
|||||||
|
|
||||||
return error;
|
return error;
|
||||||
}),
|
}),
|
||||||
);
|
)
|
||||||
|
|
||||||
let res = match value {
|
|
||||||
Ok(Tagged { item: v, tag }) => Ok((v.clone()).tagged(&tag)),
|
|
||||||
Err(reason) => Err(reason),
|
|
||||||
};
|
|
||||||
|
|
||||||
res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(
|
pub fn get(
|
||||||
@ -112,7 +106,7 @@ pub fn get(
|
|||||||
let mut index = 0;
|
let mut index = 0;
|
||||||
|
|
||||||
while let Some(row) = values.next().await {
|
while let Some(row) = values.next().await {
|
||||||
shapes.add(&row.item, index);
|
shapes.add(&row, index);
|
||||||
index += 1;
|
index += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,8 +138,8 @@ pub fn get(
|
|||||||
|
|
||||||
match res {
|
match res {
|
||||||
Ok(got) => match got {
|
Ok(got) => match got {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Table(rows),
|
value: UntaggedValue::Table(rows),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
for item in rows {
|
for item in rows {
|
||||||
@ -154,8 +148,9 @@ pub fn get(
|
|||||||
}
|
}
|
||||||
other => result.push_back(ReturnSuccess::value(other.clone())),
|
other => result.push_back(ReturnSuccess::value(other.clone())),
|
||||||
},
|
},
|
||||||
Err(reason) => result
|
Err(reason) => result.push_back(ReturnSuccess::value(
|
||||||
.push_back(ReturnSuccess::value(Value::Error(reason).tagged_unknown())),
|
UntaggedValue::Error(reason).into_untagged_value(),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
use crate::commands::WholeStreamCommand;
|
||||||
|
use crate::data::base::UntaggedValue;
|
||||||
use crate::data::TaggedDictBuilder;
|
use crate::data::TaggedDictBuilder;
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_source::Tagged;
|
||||||
|
|
||||||
pub struct GroupBy;
|
pub struct GroupBy;
|
||||||
|
|
||||||
@ -41,7 +43,7 @@ pub fn group_by(
|
|||||||
RunnableContext { input, name, .. }: RunnableContext,
|
RunnableContext { input, name, .. }: RunnableContext,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let values: Vec<Tagged<Value>> = input.values.collect().await;
|
let values: Vec<Value> = input.values.collect().await;
|
||||||
|
|
||||||
if values.is_empty() {
|
if values.is_empty() {
|
||||||
yield Err(ShellError::labeled_error(
|
yield Err(ShellError::labeled_error(
|
||||||
@ -62,9 +64,9 @@ pub fn group_by(
|
|||||||
|
|
||||||
pub fn group(
|
pub fn group(
|
||||||
column_name: &Tagged<String>,
|
column_name: &Tagged<String>,
|
||||||
values: Vec<Tagged<Value>>,
|
values: Vec<Value>,
|
||||||
tag: impl Into<Tag>,
|
tag: impl Into<Tag>,
|
||||||
) -> Result<Tagged<Value>, ShellError> {
|
) -> Result<Value, ShellError> {
|
||||||
let tag = tag.into();
|
let tag = tag.into();
|
||||||
|
|
||||||
let mut groups = indexmap::IndexMap::new();
|
let mut groups = indexmap::IndexMap::new();
|
||||||
@ -105,33 +107,32 @@ pub fn group(
|
|||||||
let mut out = TaggedDictBuilder::new(&tag);
|
let mut out = TaggedDictBuilder::new(&tag);
|
||||||
|
|
||||||
for (k, v) in groups.iter() {
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::commands::group_by::group;
|
use crate::commands::group_by::group;
|
||||||
use crate::data::meta::*;
|
use crate::data::base::{UntaggedValue, Value};
|
||||||
use crate::Value;
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
use nu_source::*;
|
||||||
|
|
||||||
fn string(input: impl Into<String>) -> Tagged<Value> {
|
fn string(input: impl Into<String>) -> Value {
|
||||||
Value::string(input.into()).tagged_unknown()
|
UntaggedValue::string(input.into()).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn row(entries: IndexMap<String, Tagged<Value>>) -> Tagged<Value> {
|
fn row(entries: IndexMap<String, Value>) -> Value {
|
||||||
Value::row(entries).tagged_unknown()
|
UntaggedValue::row(entries).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn table(list: &Vec<Tagged<Value>>) -> Tagged<Value> {
|
fn table(list: &Vec<Value>) -> Value {
|
||||||
Value::table(list).tagged_unknown()
|
UntaggedValue::table(list).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nu_releases_commiters() -> Vec<Tagged<Value>> {
|
fn nu_releases_commiters() -> Vec<Value> {
|
||||||
vec![
|
vec![
|
||||||
row(
|
row(
|
||||||
indexmap! {"name".into() => string("AR"), "country".into() => string("EC"), "date".into() => string("August 23-2019")},
|
indexmap! {"name".into() => string("AR"), "country".into() => string("EC"), "date".into() => string("August 23-2019")},
|
||||||
|
@ -3,6 +3,7 @@ use crate::data::{command_dict, TaggedDictBuilder};
|
|||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::parser::registry::{self, NamedType, PositionalType};
|
use crate::parser::registry::{self, NamedType, PositionalType};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_source::SpannedItem;
|
||||||
|
|
||||||
pub struct Help;
|
pub struct Help;
|
||||||
|
|
||||||
@ -24,13 +25,13 @@ impl PerItemCommand for Help {
|
|||||||
call_info: &CallInfo,
|
call_info: &CallInfo,
|
||||||
registry: &CommandRegistry,
|
registry: &CommandRegistry,
|
||||||
_raw_args: &RawCommandArgs,
|
_raw_args: &RawCommandArgs,
|
||||||
_input: Tagged<Value>,
|
_input: Value,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let tag = &call_info.name_tag;
|
let tag = &call_info.name_tag;
|
||||||
|
|
||||||
match call_info.args.nth(0) {
|
match call_info.args.nth(0) {
|
||||||
Some(Tagged {
|
Some(Value {
|
||||||
item: Value::Primitive(Primitive::String(document)),
|
value: UntaggedValue::Primitive(Primitive::String(document)),
|
||||||
tag,
|
tag,
|
||||||
}) => {
|
}) => {
|
||||||
let mut help = VecDeque::new();
|
let mut help = VecDeque::new();
|
||||||
@ -41,8 +42,8 @@ impl PerItemCommand for Help {
|
|||||||
let mut short_desc = TaggedDictBuilder::new(tag.clone());
|
let mut short_desc = TaggedDictBuilder::new(tag.clone());
|
||||||
let value = command_dict(registry.get_command(&cmd).unwrap(), tag.clone());
|
let value = command_dict(registry.get_command(&cmd).unwrap(), tag.clone());
|
||||||
|
|
||||||
short_desc.insert("name", cmd);
|
short_desc.insert_untagged("name", cmd);
|
||||||
short_desc.insert(
|
short_desc.insert_untagged(
|
||||||
"description",
|
"description",
|
||||||
value
|
value
|
||||||
.get_data_by_key("usage".spanned_unknown())
|
.get_data_by_key("usage".spanned_unknown())
|
||||||
@ -51,7 +52,7 @@ impl PerItemCommand for Help {
|
|||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
help.push_back(ReturnSuccess::value(short_desc.into_tagged_value()));
|
help.push_back(ReturnSuccess::value(short_desc.into_value()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let Some(command) = registry.get_command(document) {
|
if let Some(command) = registry.get_command(document) {
|
||||||
@ -148,7 +149,7 @@ impl PerItemCommand for Help {
|
|||||||
}
|
}
|
||||||
|
|
||||||
help.push_back(ReturnSuccess::value(
|
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();
|
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())
|
Ok(output_stream.to_output_stream())
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ use crate::commands::WholeStreamCommand;
|
|||||||
use crate::data::TaggedDictBuilder;
|
use crate::data::TaggedDictBuilder;
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_source::Tagged;
|
||||||
use num_traits::cast::ToPrimitive;
|
use num_traits::cast::ToPrimitive;
|
||||||
|
|
||||||
pub struct Histogram;
|
pub struct Histogram;
|
||||||
@ -54,7 +55,7 @@ pub fn histogram(
|
|||||||
RunnableContext { input, name, .. }: RunnableContext,
|
RunnableContext { input, name, .. }: RunnableContext,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let values: Vec<Tagged<Value>> = input.values.collect().await;
|
let values: Vec<Value> = input.values.collect().await;
|
||||||
|
|
||||||
let Tagged { item: group_by, .. } = column_name.clone();
|
let Tagged { item: group_by, .. } = column_name.clone();
|
||||||
|
|
||||||
@ -67,8 +68,8 @@ pub fn histogram(
|
|||||||
let percents = percentages(&reduced, maxima, &name)?;
|
let percents = percentages(&reduced, maxima, &name)?;
|
||||||
|
|
||||||
match percents {
|
match percents {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Table(datasets),
|
value: UntaggedValue::Table(datasets),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
|
|
||||||
@ -84,20 +85,21 @@ pub fn histogram(
|
|||||||
|
|
||||||
let column = (*column_name).clone();
|
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() {
|
for percentage in start.into_iter() {
|
||||||
|
|
||||||
let mut fact = TaggedDictBuilder::new(&name);
|
let mut fact = TaggedDictBuilder::new(&name);
|
||||||
let value: Tagged<String> = group_labels.get(idx).unwrap().clone();
|
let value: Tagged<String> = 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() {
|
if let Value { value: UntaggedValue::Primitive(Primitive::Int(ref num)), .. } = percentage.clone() {
|
||||||
fact.insert(&frequency_column_name, std::iter::repeat("*").take(num.to_i32().unwrap() as usize).collect::<String>());
|
let string = std::iter::repeat("*").take(num.to_i32().unwrap() as usize).collect::<String>();
|
||||||
|
fact.insert_untagged(&frequency_column_name, UntaggedValue::string(string));
|
||||||
}
|
}
|
||||||
|
|
||||||
idx = idx + 1;
|
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())
|
Ok(stream.to_output_stream())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn percentages(
|
fn percentages(values: &Value, max: Value, tag: impl Into<Tag>) -> Result<Value, ShellError> {
|
||||||
values: &Tagged<Value>,
|
|
||||||
max: Tagged<Value>,
|
|
||||||
tag: impl Into<Tag>,
|
|
||||||
) -> Result<Tagged<Value>, ShellError> {
|
|
||||||
let tag = tag.into();
|
let tag = tag.into();
|
||||||
|
|
||||||
let results: Tagged<Value> = match values {
|
let results: Value = match values {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Table(datasets),
|
value: UntaggedValue::Table(datasets),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let datasets: Vec<_> = datasets
|
let datasets: Vec<_> = datasets
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|subsets| match subsets {
|
.map(|subsets| match subsets {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Table(data),
|
value: UntaggedValue::Table(data),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let data = data
|
let data =
|
||||||
.into_iter()
|
data.into_iter()
|
||||||
.map(|d| match d {
|
.map(|d| match d {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Primitive(Primitive::Int(n)),
|
value: UntaggedValue::Primitive(Primitive::Int(n)),
|
||||||
..
|
|
||||||
} => {
|
|
||||||
let max = match max {
|
|
||||||
Tagged {
|
|
||||||
item: Value::Primitive(Primitive::Int(ref maxima)),
|
|
||||||
..
|
..
|
||||||
} => 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)
|
UntaggedValue::number(n).into_value(&tag)
|
||||||
}
|
}
|
||||||
_ => Value::number(0).tagged(&tag),
|
_ => UntaggedValue::number(0).into_value(&tag),
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
Value::Table(data).tagged(&tag)
|
UntaggedValue::Table(data).into_value(&tag)
|
||||||
}
|
}
|
||||||
_ => Value::Table(vec![]).tagged(&tag),
|
_ => UntaggedValue::Table(vec![]).into_value(&tag),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Value::Table(datasets).tagged(&tag)
|
UntaggedValue::Table(datasets).into_value(&tag)
|
||||||
}
|
}
|
||||||
other => other.clone(),
|
other => other.clone(),
|
||||||
};
|
};
|
||||||
|
@ -26,7 +26,7 @@ impl PerItemCommand for History {
|
|||||||
call_info: &CallInfo,
|
call_info: &CallInfo,
|
||||||
_registry: &CommandRegistry,
|
_registry: &CommandRegistry,
|
||||||
_raw_args: &RawCommandArgs,
|
_raw_args: &RawCommandArgs,
|
||||||
_input: Tagged<Value>,
|
_input: Value,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let tag = call_info.name_tag.clone();
|
let tag = call_info.name_tag.clone();
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ impl PerItemCommand for History {
|
|||||||
let reader = BufReader::new(file);
|
let reader = BufReader::new(file);
|
||||||
for line in reader.lines() {
|
for line in reader.lines() {
|
||||||
if let Ok(line) = line {
|
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 {
|
} else {
|
||||||
|
@ -2,6 +2,7 @@ use crate::commands::WholeStreamCommand;
|
|||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::parser::CommandRegistry;
|
use crate::parser::CommandRegistry;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_source::Tagged;
|
||||||
|
|
||||||
pub struct Last;
|
pub struct Last;
|
||||||
|
|
||||||
@ -50,7 +51,7 @@ fn last(LastArgs { rows }: LastArgs, context: RunnableContext) -> Result<OutputS
|
|||||||
if count < v.len() {
|
if count < v.len() {
|
||||||
let k = v.len() - count;
|
let k = v.len() - count;
|
||||||
for x in v[k..].iter() {
|
for x in v[k..].iter() {
|
||||||
let y: Tagged<Value> = x.clone();
|
let y: Value = x.clone();
|
||||||
yield ReturnSuccess::value(y)
|
yield ReturnSuccess::value(y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
use crate::commands::WholeStreamCommand;
|
||||||
use crate::data::{Primitive, Value};
|
use crate::data::Primitive;
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
@ -33,12 +33,13 @@ impl WholeStreamCommand for Lines {
|
|||||||
fn lines(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
fn lines(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
let args = args.evaluate_once(registry)?;
|
let args = args.evaluate_once(registry)?;
|
||||||
let tag = args.name_tag();
|
let tag = args.name_tag();
|
||||||
|
let name_span = tag.span;
|
||||||
let input = args.input;
|
let input = args.input;
|
||||||
|
|
||||||
let stream = input
|
let stream = input
|
||||||
.values
|
.values
|
||||||
.map(move |v| match v.item {
|
.map(move |v| match v.value {
|
||||||
Value::Primitive(Primitive::String(s)) => {
|
UntaggedValue::Primitive(Primitive::String(s)) => {
|
||||||
let split_result: Vec<_> = s.lines().filter(|s| s.trim() != "").collect();
|
let split_result: Vec<_> = s.lines().filter(|s| s.trim() != "").collect();
|
||||||
|
|
||||||
trace!("split result = {:?}", split_result);
|
trace!("split result = {:?}", split_result);
|
||||||
@ -46,19 +47,21 @@ fn lines(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream,
|
|||||||
let mut result = VecDeque::new();
|
let mut result = VecDeque::new();
|
||||||
for s in split_result {
|
for s in split_result {
|
||||||
result.push_back(ReturnSuccess::value(
|
result.push_back(ReturnSuccess::value(
|
||||||
Value::Primitive(Primitive::String(s.into())).tagged_unknown(),
|
UntaggedValue::Primitive(Primitive::String(s.into())).into_untagged_value(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let mut result = VecDeque::new();
|
let mut result = VecDeque::new();
|
||||||
|
let value_span = v.tag.span;
|
||||||
|
|
||||||
result.push_back(Err(ShellError::labeled_error_with_secondary(
|
result.push_back(Err(ShellError::labeled_error_with_secondary(
|
||||||
"Expected a string from pipeline",
|
"Expected a string from pipeline",
|
||||||
"requires string input",
|
"requires string input",
|
||||||
&tag,
|
name_span,
|
||||||
"value originates from here",
|
"value originates from here",
|
||||||
v.tag(),
|
value_span,
|
||||||
)));
|
)));
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
use crate::commands::WholeStreamCommand;
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_source::Tagged;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub struct LS;
|
pub struct LS;
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
use crate::commands::WholeStreamCommand;
|
||||||
use crate::parser::hir::SyntaxShape;
|
use crate::parser::hir::SyntaxShape;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_source::Tagged;
|
||||||
use num_traits::cast::ToPrimitive;
|
use num_traits::cast::ToPrimitive;
|
||||||
|
|
||||||
pub struct MapMaxBy;
|
pub struct MapMaxBy;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
@ -40,7 +42,7 @@ pub fn map_max_by(
|
|||||||
RunnableContext { input, name, .. }: RunnableContext,
|
RunnableContext { input, name, .. }: RunnableContext,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let values: Vec<Tagged<Value>> = input.values.collect().await;
|
let values: Vec<Value> = input.values.collect().await;
|
||||||
|
|
||||||
|
|
||||||
if values.is_empty() {
|
if values.is_empty() {
|
||||||
@ -68,27 +70,27 @@ pub fn map_max_by(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_max(
|
pub fn map_max(
|
||||||
values: &Tagged<Value>,
|
values: &Value,
|
||||||
_map_by_column_name: Option<String>,
|
_map_by_column_name: Option<String>,
|
||||||
tag: impl Into<Tag>,
|
tag: impl Into<Tag>,
|
||||||
) -> Result<Tagged<Value>, ShellError> {
|
) -> Result<Value, ShellError> {
|
||||||
let tag = tag.into();
|
let tag = tag.into();
|
||||||
|
|
||||||
let results: Tagged<Value> = match values {
|
let results: Value = match values {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Table(datasets),
|
value: UntaggedValue::Table(datasets),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let datasets: Vec<_> = datasets
|
let datasets: Vec<_> = datasets
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|subsets| match subsets {
|
.map(|subsets| match subsets {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Table(data),
|
value: UntaggedValue::Table(data),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let data = data.into_iter().fold(0, |acc, value| match value {
|
let data = data.into_iter().fold(0, |acc, value| match value {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Primitive(Primitive::Int(n)),
|
value: UntaggedValue::Primitive(Primitive::Int(n)),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
if n.to_i32().unwrap() > acc {
|
if n.to_i32().unwrap() > acc {
|
||||||
@ -99,15 +101,15 @@ pub fn map_max(
|
|||||||
}
|
}
|
||||||
_ => acc,
|
_ => acc,
|
||||||
});
|
});
|
||||||
Value::number(data).tagged(&tag)
|
UntaggedValue::number(data).into_value(&tag)
|
||||||
}
|
}
|
||||||
_ => Value::number(0).tagged(&tag),
|
_ => UntaggedValue::number(0).into_value(&tag),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let datasets = datasets.iter().fold(0, |max, value| match value {
|
let datasets = datasets.iter().fold(0, |max, value| match value {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Primitive(Primitive::Int(n)),
|
value: UntaggedValue::Primitive(Primitive::Int(n)),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
if n.to_i32().unwrap() > max {
|
if n.to_i32().unwrap() > max {
|
||||||
@ -118,9 +120,9 @@ pub fn map_max(
|
|||||||
}
|
}
|
||||||
_ => 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)
|
Ok(results)
|
||||||
@ -134,28 +136,28 @@ mod tests {
|
|||||||
use crate::commands::map_max_by::map_max;
|
use crate::commands::map_max_by::map_max;
|
||||||
use crate::commands::reduce_by::reduce;
|
use crate::commands::reduce_by::reduce;
|
||||||
use crate::commands::t_sort_by::t_sort;
|
use crate::commands::t_sort_by::t_sort;
|
||||||
use crate::data::meta::*;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::Value;
|
use crate::Value;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
use nu_source::*;
|
||||||
|
|
||||||
fn int(s: impl Into<BigInt>) -> Tagged<Value> {
|
fn int(s: impl Into<BigInt>) -> Value {
|
||||||
Value::int(s).tagged_unknown()
|
UntaggedValue::int(s).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn string(input: impl Into<String>) -> Tagged<Value> {
|
fn string(input: impl Into<String>) -> Value {
|
||||||
Value::string(input.into()).tagged_unknown()
|
UntaggedValue::string(input.into()).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn row(entries: IndexMap<String, Tagged<Value>>) -> Tagged<Value> {
|
fn row(entries: IndexMap<String, Value>) -> Value {
|
||||||
Value::row(entries).tagged_unknown()
|
UntaggedValue::row(entries).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nu_releases_evaluated_by_default_one() -> Tagged<Value> {
|
fn nu_releases_evaluated_by_default_one() -> Value {
|
||||||
evaluate(&nu_releases_sorted_by_date(), None, Tag::unknown()).unwrap()
|
evaluate(&nu_releases_sorted_by_date(), None, Tag::unknown()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nu_releases_reduced_by_sum() -> Tagged<Value> {
|
fn nu_releases_reduced_by_sum() -> Value {
|
||||||
reduce(
|
reduce(
|
||||||
&nu_releases_evaluated_by_default_one(),
|
&nu_releases_evaluated_by_default_one(),
|
||||||
Some(String::from("sum")),
|
Some(String::from("sum")),
|
||||||
@ -164,7 +166,7 @@ mod tests {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nu_releases_sorted_by_date() -> Tagged<Value> {
|
fn nu_releases_sorted_by_date() -> Value {
|
||||||
let key = String::from("date");
|
let key = String::from("date");
|
||||||
|
|
||||||
t_sort(
|
t_sort(
|
||||||
@ -176,12 +178,12 @@ mod tests {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nu_releases_grouped_by_date() -> Tagged<Value> {
|
fn nu_releases_grouped_by_date() -> Value {
|
||||||
let key = String::from("date").tagged_unknown();
|
let key = String::from("date").tagged_unknown();
|
||||||
group(&key, nu_releases_commiters(), Tag::unknown()).unwrap()
|
group(&key, nu_releases_commiters(), Tag::unknown()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nu_releases_commiters() -> Vec<Tagged<Value>> {
|
fn nu_releases_commiters() -> Vec<Value> {
|
||||||
vec![
|
vec![
|
||||||
row(
|
row(
|
||||||
indexmap! {"name".into() => string("AR"), "country".into() => string("EC"), "date".into() => string("August 23-2019")},
|
indexmap! {"name".into() => string("AR"), "country".into() => string("EC"), "date".into() => string("August 23-2019")},
|
||||||
|
@ -2,6 +2,7 @@ use crate::commands::command::RunnablePerItemContext;
|
|||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::parser::registry::{CommandRegistry, Signature};
|
use crate::parser::registry::{CommandRegistry, Signature};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_source::Tagged;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub struct Mkdir;
|
pub struct Mkdir;
|
||||||
@ -29,7 +30,7 @@ impl PerItemCommand for Mkdir {
|
|||||||
call_info: &CallInfo,
|
call_info: &CallInfo,
|
||||||
_registry: &CommandRegistry,
|
_registry: &CommandRegistry,
|
||||||
raw_args: &RawCommandArgs,
|
raw_args: &RawCommandArgs,
|
||||||
_input: Tagged<Value>,
|
_input: Value,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
call_info.process(&raw_args.shell_manager, mkdir)?.run()
|
call_info.process(&raw_args.shell_manager, mkdir)?.run()
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ use crate::errors::ShellError;
|
|||||||
use crate::parser::hir::SyntaxShape;
|
use crate::parser::hir::SyntaxShape;
|
||||||
use crate::parser::registry::{CommandRegistry, Signature};
|
use crate::parser::registry::{CommandRegistry, Signature};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_source::Tagged;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub struct Move;
|
pub struct Move;
|
||||||
@ -41,7 +42,7 @@ impl PerItemCommand for Move {
|
|||||||
call_info: &CallInfo,
|
call_info: &CallInfo,
|
||||||
_registry: &CommandRegistry,
|
_registry: &CommandRegistry,
|
||||||
raw_args: &RawCommandArgs,
|
raw_args: &RawCommandArgs,
|
||||||
_input: Tagged<Value>,
|
_input: Value,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
call_info.process(&raw_args.shell_manager, mv)?.run()
|
call_info.process(&raw_args.shell_manager, mv)?.run()
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ use crate::commands::WholeStreamCommand;
|
|||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::parser::CommandRegistry;
|
use crate::parser::CommandRegistry;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_source::Tagged;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct NthArgs {
|
struct NthArgs {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
use crate::commands::UnevaluatedCallInfo;
|
use crate::commands::UnevaluatedCallInfo;
|
||||||
use crate::context::AnchorLocation;
|
|
||||||
use crate::data::meta::Span;
|
|
||||||
use crate::data::Value;
|
use crate::data::Value;
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::parser::hir::SyntaxShape;
|
use crate::parser::hir::SyntaxShape;
|
||||||
use crate::parser::registry::Signature;
|
use crate::parser::registry::Signature;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_source::AnchorLocation;
|
||||||
|
use nu_source::Span;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
pub struct Open;
|
pub struct Open;
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ impl PerItemCommand for Open {
|
|||||||
call_info: &CallInfo,
|
call_info: &CallInfo,
|
||||||
registry: &CommandRegistry,
|
registry: &CommandRegistry,
|
||||||
raw_args: &RawCommandArgs,
|
raw_args: &RawCommandArgs,
|
||||||
_input: Tagged<Value>,
|
_input: Value,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
run(call_info, registry, raw_args)
|
run(call_info, registry, raw_args)
|
||||||
}
|
}
|
||||||
@ -48,15 +48,14 @@ fn run(
|
|||||||
let cwd = PathBuf::from(shell_manager.path());
|
let cwd = PathBuf::from(shell_manager.path());
|
||||||
let full_path = PathBuf::from(cwd);
|
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(
|
ShellError::labeled_error(
|
||||||
"No file or directory specified",
|
"No file or directory specified",
|
||||||
"for command",
|
"for command",
|
||||||
&call_info.name_tag,
|
&call_info.name_tag,
|
||||||
)
|
)
|
||||||
})? {
|
})?;
|
||||||
file => file,
|
|
||||||
};
|
|
||||||
let path_buf = path.as_path()?;
|
let path_buf = path.as_path()?;
|
||||||
let path_str = path_buf.display().to_string();
|
let path_str = path_buf.display().to_string();
|
||||||
let path_span = path.tag.span;
|
let path_span = path.tag.span;
|
||||||
@ -82,7 +81,7 @@ fn run(
|
|||||||
file_extension.or(path_str.split('.').last().map(String::from))
|
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 {
|
if let Some(extension) = file_extension {
|
||||||
let command_name = format!("from-{}", extension);
|
let command_name = format!("from-{}", extension);
|
||||||
@ -95,7 +94,8 @@ fn run(
|
|||||||
args: crate::parser::hir::Call {
|
args: crate::parser::hir::Call {
|
||||||
head: raw_args.call_info.args.head,
|
head: raw_args.call_info.args.head,
|
||||||
positional: None,
|
positional: None,
|
||||||
named: None
|
named: None,
|
||||||
|
span: Span::unknown()
|
||||||
},
|
},
|
||||||
source: raw_args.call_info.source,
|
source: raw_args.call_info.source,
|
||||||
name_tag: raw_args.call_info.name_tag,
|
name_tag: raw_args.call_info.name_tag,
|
||||||
@ -105,13 +105,13 @@ fn run(
|
|||||||
let result_vec: Vec<Result<ReturnSuccess, ShellError>> = result.drain_vec().await;
|
let result_vec: Vec<Result<ReturnSuccess, ShellError>> = result.drain_vec().await;
|
||||||
for res in result_vec {
|
for res in result_vec {
|
||||||
match res {
|
match res {
|
||||||
Ok(ReturnSuccess::Value(Tagged { item: Value::Table(list), ..})) => {
|
Ok(ReturnSuccess::Value(Value { value: UntaggedValue::Table(list), ..})) => {
|
||||||
for l in list {
|
for l in list {
|
||||||
yield Ok(ReturnSuccess::Value(l));
|
yield Ok(ReturnSuccess::Value(l));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(ReturnSuccess::Value(Tagged { item, .. })) => {
|
Ok(ReturnSuccess::Value(Value { value, .. })) => {
|
||||||
yield Ok(ReturnSuccess::Value(Tagged { item, tag: contents_tag.clone() }));
|
yield Ok(ReturnSuccess::Value(Value { value, tag: contents_tag.clone() }));
|
||||||
}
|
}
|
||||||
x => yield x,
|
x => yield x,
|
||||||
}
|
}
|
||||||
@ -131,7 +131,7 @@ pub async fn fetch(
|
|||||||
cwd: &PathBuf,
|
cwd: &PathBuf,
|
||||||
location: &str,
|
location: &str,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> Result<(Option<String>, Value, Tag), ShellError> {
|
) -> Result<(Option<String>, UntaggedValue, Tag), ShellError> {
|
||||||
let mut cwd = cwd.clone();
|
let mut cwd = cwd.clone();
|
||||||
|
|
||||||
cwd.push(Path::new(location));
|
cwd.push(Path::new(location));
|
||||||
@ -141,7 +141,7 @@ pub async fn fetch(
|
|||||||
Ok(s) => Ok((
|
Ok(s) => Ok((
|
||||||
cwd.extension()
|
cwd.extension()
|
||||||
.map(|name| name.to_string_lossy().to_string()),
|
.map(|name| name.to_string_lossy().to_string()),
|
||||||
Value::string(s),
|
UntaggedValue::string(s),
|
||||||
Tag {
|
Tag {
|
||||||
span,
|
span,
|
||||||
anchor: Some(AnchorLocation::File(cwd.to_string_lossy().to_string())),
|
anchor: Some(AnchorLocation::File(cwd.to_string_lossy().to_string())),
|
||||||
@ -159,7 +159,7 @@ pub async fn fetch(
|
|||||||
Ok(s) => Ok((
|
Ok(s) => Ok((
|
||||||
cwd.extension()
|
cwd.extension()
|
||||||
.map(|name| name.to_string_lossy().to_string()),
|
.map(|name| name.to_string_lossy().to_string()),
|
||||||
Value::string(s),
|
UntaggedValue::string(s),
|
||||||
Tag {
|
Tag {
|
||||||
span,
|
span,
|
||||||
anchor: Some(AnchorLocation::File(
|
anchor: Some(AnchorLocation::File(
|
||||||
@ -169,7 +169,7 @@ pub async fn fetch(
|
|||||||
)),
|
)),
|
||||||
Err(_) => Ok((
|
Err(_) => Ok((
|
||||||
None,
|
None,
|
||||||
Value::binary(bytes),
|
UntaggedValue::binary(bytes),
|
||||||
Tag {
|
Tag {
|
||||||
span,
|
span,
|
||||||
anchor: Some(AnchorLocation::File(
|
anchor: Some(AnchorLocation::File(
|
||||||
@ -181,7 +181,7 @@ pub async fn fetch(
|
|||||||
} else {
|
} else {
|
||||||
Ok((
|
Ok((
|
||||||
None,
|
None,
|
||||||
Value::binary(bytes),
|
UntaggedValue::binary(bytes),
|
||||||
Tag {
|
Tag {
|
||||||
span,
|
span,
|
||||||
anchor: Some(AnchorLocation::File(
|
anchor: Some(AnchorLocation::File(
|
||||||
@ -200,7 +200,7 @@ pub async fn fetch(
|
|||||||
Ok(s) => Ok((
|
Ok(s) => Ok((
|
||||||
cwd.extension()
|
cwd.extension()
|
||||||
.map(|name| name.to_string_lossy().to_string()),
|
.map(|name| name.to_string_lossy().to_string()),
|
||||||
Value::string(s),
|
UntaggedValue::string(s),
|
||||||
Tag {
|
Tag {
|
||||||
span,
|
span,
|
||||||
anchor: Some(AnchorLocation::File(
|
anchor: Some(AnchorLocation::File(
|
||||||
@ -210,7 +210,7 @@ pub async fn fetch(
|
|||||||
)),
|
)),
|
||||||
Err(_) => Ok((
|
Err(_) => Ok((
|
||||||
None,
|
None,
|
||||||
Value::binary(bytes),
|
UntaggedValue::binary(bytes),
|
||||||
Tag {
|
Tag {
|
||||||
span,
|
span,
|
||||||
anchor: Some(AnchorLocation::File(
|
anchor: Some(AnchorLocation::File(
|
||||||
@ -222,7 +222,7 @@ pub async fn fetch(
|
|||||||
} else {
|
} else {
|
||||||
Ok((
|
Ok((
|
||||||
None,
|
None,
|
||||||
Value::binary(bytes),
|
UntaggedValue::binary(bytes),
|
||||||
Tag {
|
Tag {
|
||||||
span,
|
span,
|
||||||
anchor: Some(AnchorLocation::File(
|
anchor: Some(AnchorLocation::File(
|
||||||
@ -234,7 +234,7 @@ pub async fn fetch(
|
|||||||
}
|
}
|
||||||
_ => Ok((
|
_ => Ok((
|
||||||
None,
|
None,
|
||||||
Value::binary(bytes),
|
UntaggedValue::binary(bytes),
|
||||||
Tag {
|
Tag {
|
||||||
span,
|
span,
|
||||||
anchor: Some(AnchorLocation::File(
|
anchor: Some(AnchorLocation::File(
|
||||||
|
@ -3,6 +3,7 @@ use crate::context::CommandRegistry;
|
|||||||
use crate::data::base::select_fields;
|
use crate::data::base::select_fields;
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_source::Tagged;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct PickArgs {
|
struct PickArgs {
|
||||||
@ -49,7 +50,7 @@ fn pick(
|
|||||||
|
|
||||||
let objects = input
|
let objects = input
|
||||||
.values
|
.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())
|
Ok(objects.from_input_stream())
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ use crate::commands::WholeStreamCommand;
|
|||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::TaggedDictBuilder;
|
use crate::TaggedDictBuilder;
|
||||||
|
use nu_source::{SpannedItem, Tagged};
|
||||||
|
|
||||||
pub struct Pivot;
|
pub struct Pivot;
|
||||||
|
|
||||||
@ -42,7 +43,7 @@ impl WholeStreamCommand for Pivot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge_descriptors(values: &[Tagged<Value>]) -> Vec<String> {
|
fn merge_descriptors(values: &[Value]) -> Vec<String> {
|
||||||
let mut ret = vec![];
|
let mut ret = vec![];
|
||||||
for value in values {
|
for value in values {
|
||||||
for desc in value.data_descriptors() {
|
for desc in value.data_descriptors() {
|
||||||
@ -110,23 +111,23 @@ pub fn pivot(args: PivotArgs, context: RunnableContext) -> Result<OutputStream,
|
|||||||
let mut dict = TaggedDictBuilder::new(&context.name);
|
let mut dict = TaggedDictBuilder::new(&context.name);
|
||||||
|
|
||||||
if !args.ignore_titles && !args.header_row {
|
if !args.ignore_titles && !args.header_row {
|
||||||
dict.insert(headers[column_num].clone(), Value::string(desc.clone()));
|
dict.insert_untagged(headers[column_num].clone(), UntaggedValue::string(desc.clone()));
|
||||||
column_num += 1
|
column_num += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in input.clone() {
|
for i in input.clone() {
|
||||||
match i.get_data_by_key(desc[..].spanned_unknown()) {
|
match i.get_data_by_key(desc[..].spanned_unknown()) {
|
||||||
Some(x) => {
|
Some(x) => {
|
||||||
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;
|
column_num += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
yield ReturnSuccess::value(dict.into_tagged_value());
|
yield ReturnSuccess::value(dict.into_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -79,11 +79,11 @@ pub fn filter_plugin(
|
|||||||
.spawn()
|
.spawn()
|
||||||
.expect("Failed to spawn child process");
|
.expect("Failed to spawn child process");
|
||||||
|
|
||||||
let mut bos: VecDeque<Tagged<Value>> = VecDeque::new();
|
let mut bos: VecDeque<Value> = VecDeque::new();
|
||||||
bos.push_back(Value::Primitive(Primitive::BeginningOfStream).tagged_unknown());
|
bos.push_back(UntaggedValue::Primitive(Primitive::BeginningOfStream).into_untagged_value());
|
||||||
|
|
||||||
let mut eos: VecDeque<Tagged<Value>> = VecDeque::new();
|
let mut eos: VecDeque<Value> = VecDeque::new();
|
||||||
eos.push_back(Value::Primitive(Primitive::EndOfStream).tagged_unknown());
|
eos.push_back(UntaggedValue::Primitive(Primitive::EndOfStream).into_untagged_value());
|
||||||
|
|
||||||
let call_info = args.call_info.clone();
|
let call_info = args.call_info.clone();
|
||||||
|
|
||||||
@ -93,8 +93,8 @@ pub fn filter_plugin(
|
|||||||
.chain(args.input.values)
|
.chain(args.input.values)
|
||||||
.chain(eos)
|
.chain(eos)
|
||||||
.map(move |v| match v {
|
.map(move |v| match v {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Primitive(Primitive::BeginningOfStream),
|
value: UntaggedValue::Primitive(Primitive::BeginningOfStream),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
|
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
|
||||||
@ -146,8 +146,8 @@ pub fn filter_plugin(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Primitive(Primitive::EndOfStream),
|
value: UntaggedValue::Primitive(Primitive::EndOfStream),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
|
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 call_info = args.call_info.clone();
|
||||||
|
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let input: Vec<Tagged<Value>> = args.input.values.collect().await;
|
let input: Vec<Value> = args.input.values.collect().await;
|
||||||
|
|
||||||
let request = JsonRpc::new("sink", (call_info.clone(), input));
|
let request = JsonRpc::new("sink", (call_info.clone(), input));
|
||||||
let request_raw = serde_json::to_string(&request).unwrap();
|
let request_raw = serde_json::to_string(&request).unwrap();
|
||||||
@ -315,7 +315,7 @@ pub fn sink_plugin(
|
|||||||
|
|
||||||
// Needed for async_stream to type check
|
// Needed for async_stream to type check
|
||||||
if false {
|
if false {
|
||||||
yield ReturnSuccess::value(Value::nothing().tagged_unknown());
|
yield ReturnSuccess::value(UntaggedValue::nothing().into_untagged_value());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(OutputStream::new(stream))
|
Ok(OutputStream::new(stream))
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
use crate::commands::UnevaluatedCallInfo;
|
use crate::commands::UnevaluatedCallInfo;
|
||||||
use crate::context::AnchorLocation;
|
use crate::data::base::{UntaggedValue, Value};
|
||||||
use crate::data::Value;
|
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::parser::hir::SyntaxShape;
|
use crate::parser::hir::SyntaxShape;
|
||||||
use crate::parser::registry::Signature;
|
use crate::parser::registry::Signature;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use base64::encode;
|
use base64::encode;
|
||||||
use mime::Mime;
|
use mime::Mime;
|
||||||
|
use nu_source::AnchorLocation;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use surf::mime;
|
use surf::mime;
|
||||||
@ -55,7 +55,7 @@ impl PerItemCommand for Post {
|
|||||||
call_info: &CallInfo,
|
call_info: &CallInfo,
|
||||||
registry: &CommandRegistry,
|
registry: &CommandRegistry,
|
||||||
raw_args: &RawCommandArgs,
|
raw_args: &RawCommandArgs,
|
||||||
_input: Tagged<Value>,
|
_input: Value,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
run(call_info, registry, raw_args)
|
run(call_info, registry, raw_args)
|
||||||
}
|
}
|
||||||
@ -74,6 +74,7 @@ fn run(
|
|||||||
})? {
|
})? {
|
||||||
file => file.clone(),
|
file => file.clone(),
|
||||||
};
|
};
|
||||||
|
let path_tag = path.tag.clone();
|
||||||
let body =
|
let body =
|
||||||
match call_info.args.nth(1).ok_or_else(|| {
|
match call_info.args.nth(1).ok_or_else(|| {
|
||||||
ShellError::labeled_error("No body specified", "for command", &name_tag)
|
ShellError::labeled_error("No body specified", "for command", &name_tag)
|
||||||
@ -81,7 +82,6 @@ fn run(
|
|||||||
file => file.clone(),
|
file => file.clone(),
|
||||||
};
|
};
|
||||||
let path_str = path.as_string()?;
|
let path_str = path.as_string()?;
|
||||||
let path_span = path.tag();
|
|
||||||
let has_raw = call_info.args.has("raw");
|
let has_raw = call_info.args.has("raw");
|
||||||
let user = call_info.args.get("user").map(|x| x.as_string().unwrap());
|
let user = call_info.args.get("user").map(|x| x.as_string().unwrap());
|
||||||
let password = call_info
|
let password = call_info
|
||||||
@ -95,7 +95,7 @@ fn run(
|
|||||||
|
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let (file_extension, contents, contents_tag) =
|
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 {
|
let file_extension = if has_raw {
|
||||||
None
|
None
|
||||||
@ -105,7 +105,7 @@ fn run(
|
|||||||
file_extension.or(path_str.split('.').last().map(String::from))
|
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 {
|
if let Some(extension) = file_extension {
|
||||||
let command_name = format!("from-{}", extension);
|
let command_name = format!("from-{}", extension);
|
||||||
@ -118,7 +118,8 @@ fn run(
|
|||||||
args: crate::parser::hir::Call {
|
args: crate::parser::hir::Call {
|
||||||
head: raw_args.call_info.args.head,
|
head: raw_args.call_info.args.head,
|
||||||
positional: None,
|
positional: None,
|
||||||
named: None
|
named: None,
|
||||||
|
span: Span::unknown()
|
||||||
},
|
},
|
||||||
source: raw_args.call_info.source,
|
source: raw_args.call_info.source,
|
||||||
name_tag: raw_args.call_info.name_tag,
|
name_tag: raw_args.call_info.name_tag,
|
||||||
@ -128,13 +129,13 @@ fn run(
|
|||||||
let result_vec: Vec<Result<ReturnSuccess, ShellError>> = result.drain_vec().await;
|
let result_vec: Vec<Result<ReturnSuccess, ShellError>> = result.drain_vec().await;
|
||||||
for res in result_vec {
|
for res in result_vec {
|
||||||
match res {
|
match res {
|
||||||
Ok(ReturnSuccess::Value(Tagged { item: Value::Table(list), ..})) => {
|
Ok(ReturnSuccess::Value(Value { value: UntaggedValue::Table(list), ..})) => {
|
||||||
for l in list {
|
for l in list {
|
||||||
yield Ok(ReturnSuccess::Value(l));
|
yield Ok(ReturnSuccess::Value(l));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(ReturnSuccess::Value(Tagged { item, .. })) => {
|
Ok(ReturnSuccess::Value(Value { value, .. })) => {
|
||||||
yield Ok(ReturnSuccess::Value(Tagged { item, tag: contents_tag.clone() }));
|
yield Ok(ReturnSuccess::Value(Value { value, tag: contents_tag.clone() }));
|
||||||
}
|
}
|
||||||
x => yield x,
|
x => yield x,
|
||||||
}
|
}
|
||||||
@ -180,11 +181,11 @@ fn extract_header_value(call_info: &CallInfo, key: &str) -> Result<Option<String
|
|||||||
if call_info.args.has(key) {
|
if call_info.args.has(key) {
|
||||||
let tagged = call_info.args.get(key);
|
let tagged = call_info.args.get(key);
|
||||||
let val = match tagged {
|
let val = match tagged {
|
||||||
Some(Tagged {
|
Some(Value {
|
||||||
item: Value::Primitive(Primitive::String(s)),
|
value: UntaggedValue::Primitive(Primitive::String(s)),
|
||||||
..
|
..
|
||||||
}) => s.clone(),
|
}) => s.clone(),
|
||||||
Some(Tagged { tag, .. }) => {
|
Some(Value { tag, .. }) => {
|
||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
format!("{} not in expected format. Expected string.", key),
|
format!("{} not in expected format. Expected string.", key),
|
||||||
"post error",
|
"post error",
|
||||||
@ -207,14 +208,14 @@ fn extract_header_value(call_info: &CallInfo, key: &str) -> Result<Option<String
|
|||||||
|
|
||||||
pub async fn post(
|
pub async fn post(
|
||||||
location: &str,
|
location: &str,
|
||||||
body: &Tagged<Value>,
|
body: &Value,
|
||||||
user: Option<String>,
|
user: Option<String>,
|
||||||
password: Option<String>,
|
password: Option<String>,
|
||||||
headers: &Vec<HeaderKind>,
|
headers: &Vec<HeaderKind>,
|
||||||
tag: Tag,
|
tag: Tag,
|
||||||
registry: &CommandRegistry,
|
registry: &CommandRegistry,
|
||||||
raw_args: &RawCommandArgs,
|
raw_args: &RawCommandArgs,
|
||||||
) -> Result<(Option<String>, Value, Tag), ShellError> {
|
) -> Result<(Option<String>, UntaggedValue, Tag), ShellError> {
|
||||||
let registry = registry.clone();
|
let registry = registry.clone();
|
||||||
let raw_args = raw_args.clone();
|
let raw_args = raw_args.clone();
|
||||||
if location.starts_with("http:") || location.starts_with("https:") {
|
if location.starts_with("http:") || location.starts_with("https:") {
|
||||||
@ -224,8 +225,8 @@ pub async fn post(
|
|||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
let response = match body {
|
let response = match body {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Primitive(Primitive::String(body_str)),
|
value: UntaggedValue::Primitive(Primitive::String(body_str)),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let mut s = surf::post(location).body_string(body_str.to_string());
|
let mut s = surf::post(location).body_string(body_str.to_string());
|
||||||
@ -241,8 +242,8 @@ pub async fn post(
|
|||||||
}
|
}
|
||||||
s.await
|
s.await
|
||||||
}
|
}
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Primitive(Primitive::Binary(b)),
|
value: UntaggedValue::Primitive(Primitive::Binary(b)),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let mut s = surf::post(location).body_bytes(b);
|
let mut s = surf::post(location).body_bytes(b);
|
||||||
@ -251,7 +252,7 @@ pub async fn post(
|
|||||||
}
|
}
|
||||||
s.await
|
s.await
|
||||||
}
|
}
|
||||||
Tagged { item, tag } => {
|
Value { value, tag } => {
|
||||||
if let Some(converter) = registry.get_command("to-json") {
|
if let Some(converter) = registry.get_command("to-json") {
|
||||||
let new_args = RawCommandArgs {
|
let new_args = RawCommandArgs {
|
||||||
host: raw_args.host,
|
host: raw_args.host,
|
||||||
@ -262,13 +263,14 @@ pub async fn post(
|
|||||||
head: raw_args.call_info.args.head,
|
head: raw_args.call_info.args.head,
|
||||||
positional: None,
|
positional: None,
|
||||||
named: None,
|
named: None,
|
||||||
|
span: Span::unknown(),
|
||||||
},
|
},
|
||||||
source: raw_args.call_info.source,
|
source: raw_args.call_info.source,
|
||||||
name_tag: raw_args.call_info.name_tag,
|
name_tag: raw_args.call_info.name_tag,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let mut result = converter.run(
|
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,
|
®istry,
|
||||||
);
|
);
|
||||||
let result_vec: Vec<Result<ReturnSuccess, ShellError>> =
|
let result_vec: Vec<Result<ReturnSuccess, ShellError>> =
|
||||||
@ -276,8 +278,8 @@ pub async fn post(
|
|||||||
let mut result_string = String::new();
|
let mut result_string = String::new();
|
||||||
for res in result_vec {
|
for res in result_vec {
|
||||||
match res {
|
match res {
|
||||||
Ok(ReturnSuccess::Value(Tagged {
|
Ok(ReturnSuccess::Value(Value {
|
||||||
item: Value::Primitive(Primitive::String(s)),
|
value: UntaggedValue::Primitive(Primitive::String(s)),
|
||||||
..
|
..
|
||||||
})) => {
|
})) => {
|
||||||
result_string.push_str(&s);
|
result_string.push_str(&s);
|
||||||
@ -314,7 +316,7 @@ pub async fn post(
|
|||||||
match (content_type.type_(), content_type.subtype()) {
|
match (content_type.type_(), content_type.subtype()) {
|
||||||
(mime::APPLICATION, mime::XML) => Ok((
|
(mime::APPLICATION, mime::XML) => Ok((
|
||||||
Some("xml".to_string()),
|
Some("xml".to_string()),
|
||||||
Value::string(r.body_string().await.map_err(|_| {
|
UntaggedValue::string(r.body_string().await.map_err(|_| {
|
||||||
ShellError::labeled_error(
|
ShellError::labeled_error(
|
||||||
"Could not load text from remote url",
|
"Could not load text from remote url",
|
||||||
"could not load",
|
"could not load",
|
||||||
@ -328,7 +330,7 @@ pub async fn post(
|
|||||||
)),
|
)),
|
||||||
(mime::APPLICATION, mime::JSON) => Ok((
|
(mime::APPLICATION, mime::JSON) => Ok((
|
||||||
Some("json".to_string()),
|
Some("json".to_string()),
|
||||||
Value::string(r.body_string().await.map_err(|_| {
|
UntaggedValue::string(r.body_string().await.map_err(|_| {
|
||||||
ShellError::labeled_error(
|
ShellError::labeled_error(
|
||||||
"Could not load text from remote url",
|
"Could not load text from remote url",
|
||||||
"could not load",
|
"could not load",
|
||||||
@ -350,7 +352,7 @@ pub async fn post(
|
|||||||
})?;
|
})?;
|
||||||
Ok((
|
Ok((
|
||||||
None,
|
None,
|
||||||
Value::binary(buf),
|
UntaggedValue::binary(buf),
|
||||||
Tag {
|
Tag {
|
||||||
anchor: Some(AnchorLocation::Url(location.to_string())),
|
anchor: Some(AnchorLocation::Url(location.to_string())),
|
||||||
span: tag.span,
|
span: tag.span,
|
||||||
@ -367,7 +369,7 @@ pub async fn post(
|
|||||||
})?;
|
})?;
|
||||||
Ok((
|
Ok((
|
||||||
Some(image_ty.to_string()),
|
Some(image_ty.to_string()),
|
||||||
Value::binary(buf),
|
UntaggedValue::binary(buf),
|
||||||
Tag {
|
Tag {
|
||||||
anchor: Some(AnchorLocation::Url(location.to_string())),
|
anchor: Some(AnchorLocation::Url(location.to_string())),
|
||||||
span: tag.span,
|
span: tag.span,
|
||||||
@ -376,7 +378,7 @@ pub async fn post(
|
|||||||
}
|
}
|
||||||
(mime::TEXT, mime::HTML) => Ok((
|
(mime::TEXT, mime::HTML) => Ok((
|
||||||
Some("html".to_string()),
|
Some("html".to_string()),
|
||||||
Value::string(r.body_string().await.map_err(|_| {
|
UntaggedValue::string(r.body_string().await.map_err(|_| {
|
||||||
ShellError::labeled_error(
|
ShellError::labeled_error(
|
||||||
"Could not load text from remote url",
|
"Could not load text from remote url",
|
||||||
"could not load",
|
"could not load",
|
||||||
@ -402,7 +404,7 @@ pub async fn post(
|
|||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
path_extension,
|
path_extension,
|
||||||
Value::string(r.body_string().await.map_err(|_| {
|
UntaggedValue::string(r.body_string().await.map_err(|_| {
|
||||||
ShellError::labeled_error(
|
ShellError::labeled_error(
|
||||||
"Could not load text from remote url",
|
"Could not load text from remote url",
|
||||||
"could not load",
|
"could not load",
|
||||||
@ -417,7 +419,7 @@ pub async fn post(
|
|||||||
}
|
}
|
||||||
(ty, sub_ty) => Ok((
|
(ty, sub_ty) => Ok((
|
||||||
None,
|
None,
|
||||||
Value::string(format!(
|
UntaggedValue::string(format!(
|
||||||
"Not yet supported MIME type: {} {}",
|
"Not yet supported MIME type: {} {}",
|
||||||
ty, sub_ty
|
ty, sub_ty
|
||||||
)),
|
)),
|
||||||
@ -430,7 +432,7 @@ pub async fn post(
|
|||||||
}
|
}
|
||||||
None => Ok((
|
None => Ok((
|
||||||
None,
|
None,
|
||||||
Value::string(format!("No content type found")),
|
UntaggedValue::string(format!("No content type found")),
|
||||||
Tag {
|
Tag {
|
||||||
anchor: Some(AnchorLocation::Url(location.to_string())),
|
anchor: Some(AnchorLocation::Url(location.to_string())),
|
||||||
span: tag.span,
|
span: tag.span,
|
||||||
|
@ -5,7 +5,7 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct PrependArgs {
|
struct PrependArgs {
|
||||||
row: Tagged<Value>,
|
row: Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Prepend;
|
pub struct Prepend;
|
||||||
@ -40,7 +40,7 @@ fn prepend(
|
|||||||
PrependArgs { row }: PrependArgs,
|
PrependArgs { row }: PrependArgs,
|
||||||
RunnableContext { input, .. }: RunnableContext,
|
RunnableContext { input, .. }: RunnableContext,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let mut prepend: VecDeque<Tagged<Value>> = VecDeque::new();
|
let mut prepend: VecDeque<Value> = VecDeque::new();
|
||||||
prepend.push_back(row);
|
prepend.push_back(row);
|
||||||
|
|
||||||
Ok(OutputStream::from_input(prepend.chain(input.values)))
|
Ok(OutputStream::from_input(prepend.chain(input.values)))
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
use crate::commands::WholeStreamCommand;
|
||||||
use crate::parser::hir::SyntaxShape;
|
use crate::parser::hir::SyntaxShape;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_source::Tagged;
|
||||||
use num_traits::cast::ToPrimitive;
|
use num_traits::cast::ToPrimitive;
|
||||||
|
|
||||||
pub struct ReduceBy;
|
pub struct ReduceBy;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
@ -40,7 +42,7 @@ pub fn reduce_by(
|
|||||||
RunnableContext { input, name, .. }: RunnableContext,
|
RunnableContext { input, name, .. }: RunnableContext,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let values: Vec<Tagged<Value>> = input.values.collect().await;
|
let values: Vec<Value> = input.values.collect().await;
|
||||||
|
|
||||||
if values.is_empty() {
|
if values.is_empty() {
|
||||||
yield Err(ShellError::labeled_error(
|
yield Err(ShellError::labeled_error(
|
||||||
@ -66,10 +68,10 @@ pub fn reduce_by(
|
|||||||
Ok(stream.to_output_stream())
|
Ok(stream.to_output_stream())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sum(data: Vec<Tagged<Value>>) -> i32 {
|
fn sum(data: Vec<Value>) -> i32 {
|
||||||
data.into_iter().fold(0, |acc, value| match value {
|
data.into_iter().fold(0, |acc, value| match value {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Primitive(Primitive::Int(n)),
|
value: UntaggedValue::Primitive(Primitive::Int(n)),
|
||||||
..
|
..
|
||||||
} => acc + n.to_i32().unwrap(),
|
} => acc + n.to_i32().unwrap(),
|
||||||
_ => acc,
|
_ => acc,
|
||||||
@ -78,15 +80,15 @@ fn sum(data: Vec<Tagged<Value>>) -> i32 {
|
|||||||
|
|
||||||
fn formula(
|
fn formula(
|
||||||
acc_begin: i32,
|
acc_begin: i32,
|
||||||
calculator: Box<dyn Fn(Vec<Tagged<Value>>) -> i32 + 'static>,
|
calculator: Box<dyn Fn(Vec<Value>) -> i32 + 'static>,
|
||||||
) -> Box<dyn Fn(i32, Vec<Tagged<Value>>) -> i32 + 'static> {
|
) -> Box<dyn Fn(i32, Vec<Value>) -> i32 + 'static> {
|
||||||
Box::new(move |acc, datax| -> i32 {
|
Box::new(move |acc, datax| -> i32 {
|
||||||
let result = acc * acc_begin;
|
let result = acc * acc_begin;
|
||||||
result + calculator(datax)
|
result + calculator(datax)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reducer_for(command: Reduce) -> Box<dyn Fn(i32, Vec<Tagged<Value>>) -> i32 + 'static> {
|
fn reducer_for(command: Reduce) -> Box<dyn Fn(i32, Vec<Value>) -> i32 + 'static> {
|
||||||
match command {
|
match command {
|
||||||
Reduce::Sum | Reduce::Default => Box::new(formula(0, Box::new(sum))),
|
Reduce::Sum | Reduce::Default => Box::new(formula(0, Box::new(sum))),
|
||||||
}
|
}
|
||||||
@ -98,10 +100,10 @@ pub enum Reduce {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn reduce(
|
pub fn reduce(
|
||||||
values: &Tagged<Value>,
|
values: &Value,
|
||||||
reducer: Option<String>,
|
reducer: Option<String>,
|
||||||
tag: impl Into<Tag>,
|
tag: impl Into<Tag>,
|
||||||
) -> Result<Tagged<Value>, ShellError> {
|
) -> Result<Value, ShellError> {
|
||||||
let tag = tag.into();
|
let tag = tag.into();
|
||||||
|
|
||||||
let reduce_with = match reducer {
|
let reduce_with = match reducer {
|
||||||
@ -109,9 +111,9 @@ pub fn reduce(
|
|||||||
Some(_) | None => reducer_for(Reduce::Default),
|
Some(_) | None => reducer_for(Reduce::Default),
|
||||||
};
|
};
|
||||||
|
|
||||||
let results: Tagged<Value> = match values {
|
let results: Value = match values {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Table(datasets),
|
value: UntaggedValue::Table(datasets),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let datasets: Vec<_> = datasets
|
let datasets: Vec<_> = datasets
|
||||||
@ -119,35 +121,35 @@ pub fn reduce(
|
|||||||
.map(|subsets| {
|
.map(|subsets| {
|
||||||
let mut acc = 0;
|
let mut acc = 0;
|
||||||
match subsets {
|
match subsets {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Table(data),
|
value: UntaggedValue::Table(data),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let data = data
|
let data = data
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|d| {
|
.map(|d| {
|
||||||
if let Tagged {
|
if let Value {
|
||||||
item: Value::Table(x),
|
value: UntaggedValue::Table(x),
|
||||||
..
|
..
|
||||||
} = d
|
} = d
|
||||||
{
|
{
|
||||||
acc = reduce_with(acc, x.clone());
|
acc = reduce_with(acc, x.clone());
|
||||||
Value::number(acc).tagged(&tag)
|
UntaggedValue::number(acc).into_value(&tag)
|
||||||
} else {
|
} else {
|
||||||
Value::number(0).tagged(&tag)
|
UntaggedValue::number(0).into_value(&tag)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
Value::Table(data).tagged(&tag)
|
UntaggedValue::Table(data).into_value(&tag)
|
||||||
}
|
}
|
||||||
_ => Value::Table(vec![]).tagged(&tag),
|
_ => UntaggedValue::Table(vec![]).into_value(&tag),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.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)
|
Ok(results)
|
||||||
@ -160,28 +162,28 @@ mod tests {
|
|||||||
use crate::commands::group_by::group;
|
use crate::commands::group_by::group;
|
||||||
use crate::commands::reduce_by::{reduce, reducer_for, Reduce};
|
use crate::commands::reduce_by::{reduce, reducer_for, Reduce};
|
||||||
use crate::commands::t_sort_by::t_sort;
|
use crate::commands::t_sort_by::t_sort;
|
||||||
use crate::data::meta::*;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::Value;
|
use crate::Value;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
use nu_source::*;
|
||||||
|
|
||||||
fn int(s: impl Into<BigInt>) -> Tagged<Value> {
|
fn int(s: impl Into<BigInt>) -> Value {
|
||||||
Value::int(s).tagged_unknown()
|
UntaggedValue::int(s).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn string(input: impl Into<String>) -> Tagged<Value> {
|
fn string(input: impl Into<String>) -> Value {
|
||||||
Value::string(input.into()).tagged_unknown()
|
UntaggedValue::string(input.into()).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn row(entries: IndexMap<String, Tagged<Value>>) -> Tagged<Value> {
|
fn row(entries: IndexMap<String, Value>) -> Value {
|
||||||
Value::row(entries).tagged_unknown()
|
UntaggedValue::row(entries).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn table(list: &Vec<Tagged<Value>>) -> Tagged<Value> {
|
fn table(list: &Vec<Value>) -> Value {
|
||||||
Value::table(list).tagged_unknown()
|
UntaggedValue::table(list).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nu_releases_sorted_by_date() -> Tagged<Value> {
|
fn nu_releases_sorted_by_date() -> Value {
|
||||||
let key = String::from("date");
|
let key = String::from("date");
|
||||||
|
|
||||||
t_sort(
|
t_sort(
|
||||||
@ -193,16 +195,16 @@ mod tests {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nu_releases_evaluated_by_default_one() -> Tagged<Value> {
|
fn nu_releases_evaluated_by_default_one() -> Value {
|
||||||
evaluate(&nu_releases_sorted_by_date(), None, Tag::unknown()).unwrap()
|
evaluate(&nu_releases_sorted_by_date(), None, Tag::unknown()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nu_releases_grouped_by_date() -> Tagged<Value> {
|
fn nu_releases_grouped_by_date() -> Value {
|
||||||
let key = String::from("date").tagged_unknown();
|
let key = String::from("date").tagged_unknown();
|
||||||
group(&key, nu_releases_commiters(), Tag::unknown()).unwrap()
|
group(&key, nu_releases_commiters(), Tag::unknown()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nu_releases_commiters() -> Vec<Tagged<Value>> {
|
fn nu_releases_commiters() -> Vec<Value> {
|
||||||
vec![
|
vec![
|
||||||
row(
|
row(
|
||||||
indexmap! {"name".into() => string("AR"), "country".into() => string("EC"), "date".into() => string("August 23-2019")},
|
indexmap! {"name".into() => string("AR"), "country".into() => string("EC"), "date".into() => string("August 23-2019")},
|
||||||
|
@ -2,6 +2,7 @@ use crate::commands::WholeStreamCommand;
|
|||||||
use crate::data::base::reject_fields;
|
use crate::data::base::reject_fields;
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_source::Tagged;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct RejectArgs {
|
pub struct RejectArgs {
|
||||||
@ -48,7 +49,7 @@ fn reject(
|
|||||||
|
|
||||||
let stream = input
|
let stream = input
|
||||||
.values
|
.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())
|
Ok(stream.from_input_stream())
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ use crate::errors::ShellError;
|
|||||||
use crate::parser::hir::SyntaxShape;
|
use crate::parser::hir::SyntaxShape;
|
||||||
use crate::parser::registry::{CommandRegistry, Signature};
|
use crate::parser::registry::{CommandRegistry, Signature};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_source::Tagged;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub struct Remove;
|
pub struct Remove;
|
||||||
@ -38,7 +39,7 @@ impl PerItemCommand for Remove {
|
|||||||
call_info: &CallInfo,
|
call_info: &CallInfo,
|
||||||
_registry: &CommandRegistry,
|
_registry: &CommandRegistry,
|
||||||
raw_args: &RawCommandArgs,
|
raw_args: &RawCommandArgs,
|
||||||
_input: Tagged<Value>,
|
_input: Value,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
call_info.process(&raw_args.shell_manager, rm)?.run()
|
call_info.process(&raw_args.shell_manager, rm)?.run()
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ use crate::commands::{UnevaluatedCallInfo, WholeStreamCommand};
|
|||||||
use crate::data::Value;
|
use crate::data::Value;
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_source::Tagged;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
pub struct Save;
|
pub struct Save;
|
||||||
@ -11,8 +12,8 @@ macro_rules! process_string {
|
|||||||
let mut result_string = String::new();
|
let mut result_string = String::new();
|
||||||
for res in $input {
|
for res in $input {
|
||||||
match res {
|
match res {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Primitive(Primitive::String(s)),
|
value: UntaggedValue::Primitive(Primitive::String(s)),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
result_string.push_str(&s);
|
result_string.push_str(&s);
|
||||||
@ -35,8 +36,8 @@ macro_rules! process_string_return_success {
|
|||||||
let mut result_string = String::new();
|
let mut result_string = String::new();
|
||||||
for res in $result_vec {
|
for res in $result_vec {
|
||||||
match res {
|
match res {
|
||||||
Ok(ReturnSuccess::Value(Tagged {
|
Ok(ReturnSuccess::Value(Value {
|
||||||
item: Value::Primitive(Primitive::String(s)),
|
value: UntaggedValue::Primitive(Primitive::String(s)),
|
||||||
..
|
..
|
||||||
})) => {
|
})) => {
|
||||||
result_string.push_str(&s);
|
result_string.push_str(&s);
|
||||||
@ -59,8 +60,8 @@ macro_rules! process_binary_return_success {
|
|||||||
let mut result_binary: Vec<u8> = Vec::new();
|
let mut result_binary: Vec<u8> = Vec::new();
|
||||||
for res in $result_vec {
|
for res in $result_vec {
|
||||||
match res {
|
match res {
|
||||||
Ok(ReturnSuccess::Value(Tagged {
|
Ok(ReturnSuccess::Value(Value {
|
||||||
item: Value::Primitive(Primitive::Binary(b)),
|
value: UntaggedValue::Primitive(Primitive::Binary(b)),
|
||||||
..
|
..
|
||||||
})) => {
|
})) => {
|
||||||
for u in b.into_iter() {
|
for u in b.into_iter() {
|
||||||
@ -133,11 +134,11 @@ fn save(
|
|||||||
let name_tag = name.clone();
|
let name_tag = name.clone();
|
||||||
|
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let input: Vec<Tagged<Value>> = input.values.collect().await;
|
let input: Vec<Value> = input.values.collect().await;
|
||||||
if path.is_none() {
|
if path.is_none() {
|
||||||
// If there is no filename, check the metadata for the anchor filename
|
// If there is no filename, check the metadata for the anchor filename
|
||||||
if input.len() > 0 {
|
if input.len() > 0 {
|
||||||
let anchor = input[0].anchor();
|
let anchor = input[0].tag.anchor();
|
||||||
match anchor {
|
match anchor {
|
||||||
Some(path) => match path {
|
Some(path) => match path {
|
||||||
AnchorLocation::File(file) => {
|
AnchorLocation::File(file) => {
|
||||||
@ -187,7 +188,8 @@ fn save(
|
|||||||
args: crate::parser::hir::Call {
|
args: crate::parser::hir::Call {
|
||||||
head: raw_args.call_info.args.head,
|
head: raw_args.call_info.args.head,
|
||||||
positional: None,
|
positional: None,
|
||||||
named: None
|
named: None,
|
||||||
|
span: Span::unknown()
|
||||||
},
|
},
|
||||||
source: raw_args.call_info.source,
|
source: raw_args.call_info.source,
|
||||||
name_tag: raw_args.call_info.name_tag,
|
name_tag: raw_args.call_info.name_tag,
|
||||||
@ -224,7 +226,7 @@ fn save(
|
|||||||
Ok(OutputStream::new(stream))
|
Ok(OutputStream::new(stream))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn string_from(input: &Vec<Tagged<Value>>) -> String {
|
fn string_from(input: &Vec<Value>) -> String {
|
||||||
let mut save_data = String::new();
|
let mut save_data = String::new();
|
||||||
|
|
||||||
if input.len() > 0 {
|
if input.len() > 0 {
|
||||||
|
@ -36,14 +36,14 @@ fn shells(args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream
|
|||||||
let mut dict = TaggedDictBuilder::new(&tag);
|
let mut dict = TaggedDictBuilder::new(&tag);
|
||||||
|
|
||||||
if index == (*args.shell_manager.current_shell).load(Ordering::SeqCst) {
|
if index == (*args.shell_manager.current_shell).load(Ordering::SeqCst) {
|
||||||
dict.insert(" ", "X".to_string());
|
dict.insert_untagged(" ", "X".to_string());
|
||||||
} else {
|
} else {
|
||||||
dict.insert(" ", " ".to_string());
|
dict.insert_untagged(" ", " ".to_string());
|
||||||
}
|
}
|
||||||
dict.insert("name", shell.name());
|
dict.insert_untagged("name", shell.name());
|
||||||
dict.insert("path", shell.path());
|
dict.insert_untagged("path", shell.path());
|
||||||
|
|
||||||
shells_out.push_back(dict.into_tagged_value());
|
shells_out.push_back(dict.into_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(shells_out.to_output_stream())
|
Ok(shells_out.to_output_stream())
|
||||||
|
@ -30,22 +30,26 @@ impl WholeStreamCommand for Size {
|
|||||||
fn size(args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
fn size(args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
let input = args.input;
|
let input = args.input;
|
||||||
let tag = args.call_info.name_tag;
|
let tag = args.call_info.name_tag;
|
||||||
|
let name_span = tag.span;
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.values
|
.values
|
||||||
.map(move |v| match v.item {
|
.map(move |v| match v.value {
|
||||||
Value::Primitive(Primitive::String(ref s)) => ReturnSuccess::value(count(s, v.tag())),
|
UntaggedValue::Primitive(Primitive::String(ref s)) => {
|
||||||
|
ReturnSuccess::value(count(s, &v.tag))
|
||||||
|
}
|
||||||
_ => Err(ShellError::labeled_error_with_secondary(
|
_ => Err(ShellError::labeled_error_with_secondary(
|
||||||
"Expected a string from pipeline",
|
"Expected a string from pipeline",
|
||||||
"requires string input",
|
"requires string input",
|
||||||
&tag,
|
name_span,
|
||||||
"value originates from here",
|
"value originates from here",
|
||||||
v.tag(),
|
v.tag.span,
|
||||||
)),
|
)),
|
||||||
})
|
})
|
||||||
.to_output_stream())
|
.to_output_stream())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn count(contents: &str, tag: impl Into<Tag>) -> Tagged<Value> {
|
fn count(contents: &str, tag: impl Into<Tag>) -> Value {
|
||||||
let mut lines: i64 = 0;
|
let mut lines: i64 = 0;
|
||||||
let mut words: i64 = 0;
|
let mut words: i64 = 0;
|
||||||
let mut chars: i64 = 0;
|
let mut chars: i64 = 0;
|
||||||
@ -72,11 +76,11 @@ fn count(contents: &str, tag: impl Into<Tag>) -> Tagged<Value> {
|
|||||||
|
|
||||||
let mut dict = TaggedDictBuilder::new(tag);
|
let mut dict = TaggedDictBuilder::new(tag);
|
||||||
//TODO: add back in name when we have it in the tag
|
//TODO: add back in name when we have it in the tag
|
||||||
//dict.insert("name", Value::string(name));
|
//dict.insert("name", UntaggedValue::string(name));
|
||||||
dict.insert("lines", Value::int(lines));
|
dict.insert_untagged("lines", UntaggedValue::int(lines));
|
||||||
dict.insert("words", Value::int(words));
|
dict.insert_untagged("words", UntaggedValue::int(words));
|
||||||
dict.insert("chars", Value::int(chars));
|
dict.insert_untagged("chars", UntaggedValue::int(chars));
|
||||||
dict.insert("max length", Value::int(bytes));
|
dict.insert_untagged("max length", UntaggedValue::int(bytes));
|
||||||
|
|
||||||
dict.into_tagged_value()
|
dict.into_value()
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
use crate::commands::WholeStreamCommand;
|
||||||
|
use crate::data::base::Block;
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
@ -7,7 +8,7 @@ pub struct SkipWhile;
|
|||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct SkipWhileArgs {
|
pub struct SkipWhileArgs {
|
||||||
condition: value::Block,
|
condition: Block,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WholeStreamCommand for SkipWhile {
|
impl WholeStreamCommand for SkipWhile {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
use crate::commands::WholeStreamCommand;
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_source::Tagged;
|
||||||
|
|
||||||
pub struct SortBy;
|
pub struct SortBy;
|
||||||
|
|
||||||
@ -38,10 +39,10 @@ fn sort_by(
|
|||||||
Ok(OutputStream::new(async_stream! {
|
Ok(OutputStream::new(async_stream! {
|
||||||
let mut vec = context.input.drain_vec().await;
|
let mut vec = context.input.drain_vec().await;
|
||||||
|
|
||||||
let calc_key = |item: &Tagged<Value>| {
|
let calc_key = |item: &crate::data::base::Value| {
|
||||||
rest.iter()
|
rest.iter()
|
||||||
.map(|f| item.get_data_by_key(f.borrow_spanned()).map(|i| i.clone()))
|
.map(|f| item.get_data_by_key(f.borrow_spanned()).map(|i| i.clone()))
|
||||||
.collect::<Vec<Option<Tagged<Value>>>>()
|
.collect::<Vec<Option<crate::data::base::Value>>>()
|
||||||
};
|
};
|
||||||
vec.sort_by_cached_key(calc_key);
|
vec.sort_by_cached_key(calc_key);
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
use crate::commands::WholeStreamCommand;
|
||||||
|
use crate::data::base::UntaggedValue;
|
||||||
use crate::data::TaggedDictBuilder;
|
use crate::data::TaggedDictBuilder;
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use nu_source::Tagged;
|
||||||
|
|
||||||
pub struct SplitBy;
|
pub struct SplitBy;
|
||||||
|
|
||||||
@ -41,7 +43,7 @@ pub fn split_by(
|
|||||||
RunnableContext { input, name, .. }: RunnableContext,
|
RunnableContext { input, name, .. }: RunnableContext,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let values: Vec<Tagged<Value>> = input.values.collect().await;
|
let values: Vec<Value> = input.values.collect().await;
|
||||||
|
|
||||||
if values.len() > 1 || values.is_empty() {
|
if values.len() > 1 || values.is_empty() {
|
||||||
yield Err(ShellError::labeled_error(
|
yield Err(ShellError::labeled_error(
|
||||||
@ -62,22 +64,22 @@ pub fn split_by(
|
|||||||
|
|
||||||
pub fn split(
|
pub fn split(
|
||||||
column_name: &Tagged<String>,
|
column_name: &Tagged<String>,
|
||||||
value: &Tagged<Value>,
|
value: &Value,
|
||||||
tag: impl Into<Tag>,
|
tag: impl Into<Tag>,
|
||||||
) -> Result<Tagged<Value>, ShellError> {
|
) -> Result<Value, ShellError> {
|
||||||
let origin_tag = tag.into();
|
let origin_tag = tag.into();
|
||||||
|
|
||||||
let mut splits = indexmap::IndexMap::new();
|
let mut splits = indexmap::IndexMap::new();
|
||||||
|
|
||||||
match value {
|
match value {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Row(group_sets),
|
value: UntaggedValue::Row(group_sets),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
for (group_key, group_value) in group_sets.entries.iter() {
|
for (group_key, group_value) in group_sets.entries.iter() {
|
||||||
match *group_value {
|
match *group_value {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Table(ref dataset),
|
value: UntaggedValue::Table(ref dataset),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let group = crate::commands::group_by::group(
|
let group = crate::commands::group_by::group(
|
||||||
@ -87,14 +89,14 @@ pub fn split(
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
match group {
|
match group {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Row(o),
|
value: UntaggedValue::Row(o),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
for (split_label, subset) in o.entries.into_iter() {
|
for (split_label, subset) in o.entries.into_iter() {
|
||||||
match subset {
|
match subset {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Table(subset),
|
value: UntaggedValue::Table(subset),
|
||||||
tag,
|
tag,
|
||||||
} => {
|
} => {
|
||||||
let s = splits
|
let s = splits
|
||||||
@ -102,7 +104,7 @@ pub fn split(
|
|||||||
.or_insert(indexmap::IndexMap::new());
|
.or_insert(indexmap::IndexMap::new());
|
||||||
s.insert(
|
s.insert(
|
||||||
group_key.clone(),
|
group_key.clone(),
|
||||||
Value::table(&subset).tagged(tag),
|
UntaggedValue::table(&subset).into_value(tag),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
other => {
|
other => {
|
||||||
@ -142,38 +144,38 @@ pub fn split(
|
|||||||
let mut out = TaggedDictBuilder::new(&origin_tag);
|
let mut out = TaggedDictBuilder::new(&origin_tag);
|
||||||
|
|
||||||
for (k, v) in splits.into_iter() {
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::commands::group_by::group;
|
use crate::commands::group_by::group;
|
||||||
use crate::commands::split_by::split;
|
use crate::commands::split_by::split;
|
||||||
use crate::data::meta::*;
|
use crate::data::base::{UntaggedValue, Value};
|
||||||
use crate::Value;
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
use nu_source::*;
|
||||||
|
|
||||||
fn string(input: impl Into<String>) -> Tagged<Value> {
|
fn string(input: impl Into<String>) -> Value {
|
||||||
Value::string(input.into()).tagged_unknown()
|
UntaggedValue::string(input.into()).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn row(entries: IndexMap<String, Tagged<Value>>) -> Tagged<Value> {
|
fn row(entries: IndexMap<String, Value>) -> Value {
|
||||||
Value::row(entries).tagged_unknown()
|
UntaggedValue::row(entries).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn table(list: &Vec<Tagged<Value>>) -> Tagged<Value> {
|
fn table(list: &Vec<Value>) -> Value {
|
||||||
Value::table(list).tagged_unknown()
|
UntaggedValue::table(list).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nu_releases_grouped_by_date() -> Tagged<Value> {
|
fn nu_releases_grouped_by_date() -> Value {
|
||||||
let key = String::from("date").tagged_unknown();
|
let key = String::from("date").tagged_unknown();
|
||||||
group(&key, nu_releases_commiters(), Tag::unknown()).unwrap()
|
group(&key, nu_releases_commiters(), Tag::unknown()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nu_releases_commiters() -> Vec<Tagged<Value>> {
|
fn nu_releases_commiters() -> Vec<Value> {
|
||||||
vec![
|
vec![
|
||||||
row(
|
row(
|
||||||
indexmap! {"name".into() => string("AR"), "country".into() => string("EC"), "date".into() => string("August 23-2019")},
|
indexmap! {"name".into() => string("AR"), "country".into() => string("EC"), "date".into() => string("August 23-2019")},
|
||||||
@ -211,7 +213,7 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
split(&for_key, &nu_releases_grouped_by_date(), Tag::unknown()).unwrap(),
|
split(&for_key, &nu_releases_grouped_by_date(), Tag::unknown()).unwrap(),
|
||||||
Value::row(indexmap! {
|
UntaggedValue::row(indexmap! {
|
||||||
"EC".into() => row(indexmap! {
|
"EC".into() => row(indexmap! {
|
||||||
"August 23-2019".into() => table(&vec![
|
"August 23-2019".into() => table(&vec![
|
||||||
row(indexmap!{"name".into() => string("AR"), "country".into() => string("EC"), "date".into() => string("August 23-2019")})
|
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")})
|
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")})
|
row(indexmap!{"name".into() => string("AR"), "country".into() => string("EC"), "date".into() => string("August 23-2019")})
|
||||||
]),
|
]),
|
||||||
"Sept 24-2019".into() => table(&vec![
|
"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![
|
"October 10-2019".into() => table(&vec![
|
||||||
row(indexmap!{"name".into() => string("YK"), "country".into() => string("US"), "date".into() => string("October 10-2019")})
|
row(indexmap!{"name".into() => string("YK"), "country".into() => string("US"), "date".into() => string("October 10-2019")})
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
use crate::commands::WholeStreamCommand;
|
||||||
use crate::data::{Primitive, TaggedDictBuilder, Value};
|
use crate::data::{Primitive, TaggedDictBuilder};
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
use nu_source::Tagged;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct SplitColumnArgs {
|
struct SplitColumnArgs {
|
||||||
@ -51,10 +52,12 @@ fn split_column(
|
|||||||
}: SplitColumnArgs,
|
}: SplitColumnArgs,
|
||||||
RunnableContext { input, name, .. }: RunnableContext,
|
RunnableContext { input, name, .. }: RunnableContext,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
|
let name_span = name.span;
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.values
|
.values
|
||||||
.map(move |v| match v.item {
|
.map(move |v| match v.value {
|
||||||
Value::Primitive(Primitive::String(ref s)) => {
|
UntaggedValue::Primitive(Primitive::String(ref s)) => {
|
||||||
let splitter = separator.replace("\\n", "\n");
|
let splitter = separator.replace("\\n", "\n");
|
||||||
trace!("splitting with {:?}", splitter);
|
trace!("splitting with {:?}", splitter);
|
||||||
|
|
||||||
@ -75,32 +78,38 @@ fn split_column(
|
|||||||
gen_columns.push(format!("Column{}", i + 1));
|
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()) {
|
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() {
|
} 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()) {
|
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 {
|
} 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()) {
|
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(
|
_ => Err(ShellError::labeled_error_with_secondary(
|
||||||
"Expected a string from pipeline",
|
"Expected a string from pipeline",
|
||||||
"requires string input",
|
"requires string input",
|
||||||
&name,
|
name_span,
|
||||||
"value originates from here",
|
"value originates from here",
|
||||||
v.tag(),
|
v.tag.span,
|
||||||
)),
|
)),
|
||||||
})
|
})
|
||||||
.to_output_stream())
|
.to_output_stream())
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
use crate::commands::WholeStreamCommand;
|
||||||
use crate::data::{Primitive, Value};
|
use crate::data::Primitive;
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
use nu_source::Tagged;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct SplitRowArgs {
|
struct SplitRowArgs {
|
||||||
@ -43,8 +44,8 @@ fn split_row(
|
|||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let stream = input
|
let stream = input
|
||||||
.values
|
.values
|
||||||
.map(move |v| match v.item {
|
.map(move |v| match v.value {
|
||||||
Value::Primitive(Primitive::String(ref s)) => {
|
UntaggedValue::Primitive(Primitive::String(ref s)) => {
|
||||||
let splitter = separator.item.replace("\\n", "\n");
|
let splitter = separator.item.replace("\\n", "\n");
|
||||||
trace!("splitting with {:?}", splitter);
|
trace!("splitting with {:?}", splitter);
|
||||||
let split_result: Vec<_> = s.split(&splitter).filter(|s| s.trim() != "").collect();
|
let split_result: Vec<_> = s.split(&splitter).filter(|s| s.trim() != "").collect();
|
||||||
@ -54,7 +55,7 @@ fn split_row(
|
|||||||
let mut result = VecDeque::new();
|
let mut result = VecDeque::new();
|
||||||
for s in split_result {
|
for s in split_result {
|
||||||
result.push_back(ReturnSuccess::value(
|
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
|
result
|
||||||
@ -64,9 +65,9 @@ fn split_row(
|
|||||||
result.push_back(Err(ShellError::labeled_error_with_secondary(
|
result.push_back(Err(ShellError::labeled_error_with_secondary(
|
||||||
"Expected a string from pipeline",
|
"Expected a string from pipeline",
|
||||||
"requires string input",
|
"requires string input",
|
||||||
&name,
|
name.span,
|
||||||
"value originates from here",
|
"value originates from here",
|
||||||
v.tag(),
|
v.tag.span,
|
||||||
)));
|
)));
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ use crate::data::{TaggedDictBuilder, TaggedListBuilder};
|
|||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use chrono::{DateTime, NaiveDate, Utc};
|
use chrono::{DateTime, NaiveDate, Utc};
|
||||||
|
use nu_source::Tagged;
|
||||||
|
|
||||||
pub struct TSortBy;
|
pub struct TSortBy;
|
||||||
|
|
||||||
@ -57,7 +58,7 @@ fn t_sort_by(
|
|||||||
RunnableContext { input, name, .. }: RunnableContext,
|
RunnableContext { input, name, .. }: RunnableContext,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
Ok(OutputStream::new(async_stream! {
|
Ok(OutputStream::new(async_stream! {
|
||||||
let values: Vec<Tagged<Value>> = input.values.collect().await;
|
let values: Vec<Value> = input.values.collect().await;
|
||||||
|
|
||||||
let column_grouped_by_name = if let Some(grouped_by) = group_by {
|
let column_grouped_by_name = if let Some(grouped_by) = group_by {
|
||||||
Some(grouped_by.item().clone())
|
Some(grouped_by.item().clone())
|
||||||
@ -67,7 +68,7 @@ fn t_sort_by(
|
|||||||
|
|
||||||
if show_columns {
|
if show_columns {
|
||||||
for label in columns_sorted(column_grouped_by_name, &values[0], &name).into_iter() {
|
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 {
|
} else {
|
||||||
match t_sort(column_grouped_by_name, None, &values[0], name) {
|
match t_sort(column_grouped_by_name, None, &values[0], name) {
|
||||||
@ -80,41 +81,41 @@ fn t_sort_by(
|
|||||||
|
|
||||||
pub fn columns_sorted(
|
pub fn columns_sorted(
|
||||||
_group_by_name: Option<String>,
|
_group_by_name: Option<String>,
|
||||||
value: &Tagged<Value>,
|
value: &Value,
|
||||||
tag: impl Into<Tag>,
|
tag: impl Into<Tag>,
|
||||||
) -> Vec<Tagged<String>> {
|
) -> Vec<Tagged<String>> {
|
||||||
let origin_tag = tag.into();
|
let origin_tag = tag.into();
|
||||||
|
|
||||||
match value {
|
match value {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Row(rows),
|
value: UntaggedValue::Row(rows),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let mut keys: Vec<Tagged<Value>> =
|
let mut keys: Vec<Value> = rows
|
||||||
rows.entries
|
.entries
|
||||||
.keys()
|
.keys()
|
||||||
.map(|s| s.as_ref())
|
.map(|s| s.as_ref())
|
||||||
.map(|k: &str| {
|
.map(|k: &str| {
|
||||||
let date = NaiveDate::parse_from_str(k, "%B %d-%Y");
|
let date = NaiveDate::parse_from_str(k, "%B %d-%Y");
|
||||||
|
|
||||||
let date = match date {
|
let date = match date {
|
||||||
Ok(parsed) => Value::Primitive(Primitive::Date(
|
Ok(parsed) => UntaggedValue::Primitive(Primitive::Date(
|
||||||
DateTime::<Utc>::from_utc(parsed.and_hms(12, 34, 56), Utc),
|
DateTime::<Utc>::from_utc(parsed.and_hms(12, 34, 56), Utc),
|
||||||
)),
|
)),
|
||||||
Err(_) => Value::string(k),
|
Err(_) => UntaggedValue::string(k),
|
||||||
};
|
};
|
||||||
|
|
||||||
date.tagged_unknown()
|
date.into_untagged_value()
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
keys.sort();
|
keys.sort();
|
||||||
|
|
||||||
let keys: Vec<String> = keys
|
let keys: Vec<String> = keys
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|k| match k {
|
.map(|k| match k {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Primitive(Primitive::Date(d)),
|
value: UntaggedValue::Primitive(Primitive::Date(d)),
|
||||||
..
|
..
|
||||||
} => format!("{}", d.format("%B %d-%Y")),
|
} => format!("{}", d.format("%B %d-%Y")),
|
||||||
_ => k.as_string().unwrap(),
|
_ => k.as_string().unwrap(),
|
||||||
@ -130,9 +131,9 @@ pub fn columns_sorted(
|
|||||||
pub fn t_sort(
|
pub fn t_sort(
|
||||||
group_by_name: Option<String>,
|
group_by_name: Option<String>,
|
||||||
split_by_name: Option<String>,
|
split_by_name: Option<String>,
|
||||||
value: &Tagged<Value>,
|
value: &Value,
|
||||||
tag: impl Into<Tag>,
|
tag: impl Into<Tag>,
|
||||||
) -> Result<Tagged<Value>, ShellError> {
|
) -> Result<Value, ShellError> {
|
||||||
let origin_tag = tag.into();
|
let origin_tag = tag.into();
|
||||||
|
|
||||||
match group_by_name {
|
match group_by_name {
|
||||||
@ -143,12 +144,12 @@ pub fn t_sort(
|
|||||||
match split_by_name {
|
match split_by_name {
|
||||||
None => {
|
None => {
|
||||||
let mut dataset = TaggedDictBuilder::new(&origin_tag);
|
let mut dataset = TaggedDictBuilder::new(&origin_tag);
|
||||||
dataset.insert_tagged("default", value.clone());
|
dataset.insert_value("default", value.clone());
|
||||||
let dataset = dataset.into_tagged_value();
|
let dataset = dataset.into_value();
|
||||||
|
|
||||||
let split_labels: Vec<Tagged<String>> = match &dataset {
|
let split_labels: Vec<Tagged<String>> = match &dataset {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Row(rows),
|
value: UntaggedValue::Row(rows),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let mut keys: Vec<Tagged<String>> = rows
|
let mut keys: Vec<Tagged<String>> = rows
|
||||||
@ -164,7 +165,7 @@ pub fn t_sort(
|
|||||||
_ => vec![],
|
_ => vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
let results: Vec<Vec<Tagged<Value>>> = split_labels
|
let results: Vec<Vec<Value>> = split_labels
|
||||||
.iter()
|
.iter()
|
||||||
.map(|split| {
|
.map(|split| {
|
||||||
let groups = dataset.get_data_by_key(split.borrow_spanned());
|
let groups = dataset.get_data_by_key(split.borrow_spanned());
|
||||||
@ -173,14 +174,14 @@ pub fn t_sort(
|
|||||||
.clone()
|
.clone()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|label| match &groups {
|
.map(|label| match &groups {
|
||||||
Some(Tagged {
|
Some(Value {
|
||||||
item: Value::Row(dict),
|
value: UntaggedValue::Row(dict),
|
||||||
..
|
..
|
||||||
}) => dict
|
}) => dict
|
||||||
.get_data_by_key(label.borrow_spanned())
|
.get_data_by_key(label.borrow_spanned())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.clone(),
|
.clone(),
|
||||||
_ => Value::Table(vec![]).tagged(&origin_tag),
|
_ => UntaggedValue::Table(vec![]).into_value(&origin_tag),
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
@ -189,15 +190,15 @@ pub fn t_sort(
|
|||||||
let mut outer = TaggedListBuilder::new(&origin_tag);
|
let mut outer = TaggedListBuilder::new(&origin_tag);
|
||||||
|
|
||||||
for i in results {
|
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)]
|
#[cfg(test)]
|
||||||
@ -205,28 +206,28 @@ mod tests {
|
|||||||
|
|
||||||
use crate::commands::group_by::group;
|
use crate::commands::group_by::group;
|
||||||
use crate::commands::t_sort_by::{columns_sorted, t_sort};
|
use crate::commands::t_sort_by::{columns_sorted, t_sort};
|
||||||
use crate::data::meta::*;
|
use crate::data::base::{UntaggedValue, Value};
|
||||||
use crate::Value;
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
use nu_source::*;
|
||||||
|
|
||||||
fn string(input: impl Into<String>) -> Tagged<Value> {
|
fn string(input: impl Into<String>) -> Value {
|
||||||
Value::string(input.into()).tagged_unknown()
|
UntaggedValue::string(input.into()).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn row(entries: IndexMap<String, Tagged<Value>>) -> Tagged<Value> {
|
fn row(entries: IndexMap<String, Value>) -> Value {
|
||||||
Value::row(entries).tagged_unknown()
|
UntaggedValue::row(entries).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn table(list: &Vec<Tagged<Value>>) -> Tagged<Value> {
|
fn table(list: &Vec<Value>) -> Value {
|
||||||
Value::table(list).tagged_unknown()
|
UntaggedValue::table(list).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nu_releases_grouped_by_date() -> Tagged<Value> {
|
fn nu_releases_grouped_by_date() -> Value {
|
||||||
let key = String::from("date").tagged_unknown();
|
let key = String::from("date").tagged_unknown();
|
||||||
group(&key, nu_releases_commiters(), Tag::unknown()).unwrap()
|
group(&key, nu_releases_commiters(), Tag::unknown()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nu_releases_commiters() -> Vec<Tagged<Value>> {
|
fn nu_releases_commiters() -> Vec<Value> {
|
||||||
vec![
|
vec![
|
||||||
row(
|
row(
|
||||||
indexmap! {"name".into() => string("AR"), "country".into() => string("EC"), "date".into() => string("August 23-2019")},
|
indexmap! {"name".into() => string("AR"), "country".into() => string("EC"), "date".into() => string("August 23-2019")},
|
||||||
|
@ -37,7 +37,7 @@ fn table(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream,
|
|||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let host = args.host.clone();
|
let host = args.host.clone();
|
||||||
let start_number = match args.get("start_number") {
|
let start_number = match args.get("start_number") {
|
||||||
Some(Tagged { item: Value::Primitive(Primitive::Int(i)), .. }) => {
|
Some(Value { value: UntaggedValue::Primitive(Primitive::Int(i)), .. }) => {
|
||||||
i.to_usize().unwrap()
|
i.to_usize().unwrap()
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@ -45,7 +45,7 @@ fn table(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream,
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let input: Vec<Tagged<Value>> = args.input.into_vec().await;
|
let input: Vec<Value> = args.input.into_vec().await;
|
||||||
if input.len() > 0 {
|
if input.len() > 0 {
|
||||||
let mut host = host.lock().unwrap();
|
let mut host = host.lock().unwrap();
|
||||||
let view = TableView::from_list(&input, start_number);
|
let view = TableView::from_list(&input, start_number);
|
||||||
@ -56,7 +56,7 @@ fn table(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream,
|
|||||||
}
|
}
|
||||||
// Needed for async_stream to type check
|
// Needed for async_stream to type check
|
||||||
if false {
|
if false {
|
||||||
yield ReturnSuccess::value(Value::nothing().tagged_unknown());
|
yield ReturnSuccess::value(UntaggedValue::nothing().into_value(Tag::unknown()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
use crate::commands::WholeStreamCommand;
|
||||||
use crate::data::{TaggedDictBuilder, Value};
|
use crate::data::TaggedDictBuilder;
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
@ -35,24 +35,24 @@ fn tags(args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream,
|
|||||||
let mut tags = TaggedDictBuilder::new(v.tag());
|
let mut tags = TaggedDictBuilder::new(v.tag());
|
||||||
{
|
{
|
||||||
let anchor = v.anchor();
|
let anchor = v.anchor();
|
||||||
let span = v.tag().span;
|
let span = v.tag.span;
|
||||||
let mut dict = TaggedDictBuilder::new(v.tag());
|
let mut dict = TaggedDictBuilder::new(v.tag());
|
||||||
dict.insert("start", Value::int(span.start() as i64));
|
dict.insert_untagged("start", UntaggedValue::int(span.start() as i64));
|
||||||
dict.insert("end", Value::int(span.end() as i64));
|
dict.insert_untagged("end", UntaggedValue::int(span.end() as i64));
|
||||||
tags.insert_tagged("span", dict.into_tagged_value());
|
tags.insert_value("span", dict.into_value());
|
||||||
|
|
||||||
match anchor {
|
match anchor {
|
||||||
Some(AnchorLocation::File(source)) => {
|
Some(AnchorLocation::File(source)) => {
|
||||||
tags.insert("anchor", Value::string(source));
|
tags.insert_untagged("anchor", UntaggedValue::string(source));
|
||||||
}
|
}
|
||||||
Some(AnchorLocation::Url(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())
|
.to_output_stream())
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
use crate::commands::WholeStreamCommand;
|
||||||
use crate::data::{Dictionary, Primitive, Value};
|
use crate::data::{Dictionary, Primitive, Value};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::RawPathMember;
|
use crate::UnspannedPathMember;
|
||||||
use bson::{encode_document, oid::ObjectId, spec::BinarySubtype, Bson, Document};
|
use bson::{encode_document, oid::ObjectId, spec::BinarySubtype, Bson, Document};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
|
||||||
@ -33,46 +33,48 @@ impl WholeStreamCommand for ToBSON {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value_to_bson_value(v: &Tagged<Value>) -> Result<Bson, ShellError> {
|
pub fn value_to_bson_value(v: &Value) -> Result<Bson, ShellError> {
|
||||||
Ok(match &v.item {
|
Ok(match &v.value {
|
||||||
Value::Primitive(Primitive::Boolean(b)) => Bson::Boolean(*b),
|
UntaggedValue::Primitive(Primitive::Boolean(b)) => Bson::Boolean(*b),
|
||||||
// FIXME: What about really big decimals?
|
// FIXME: What about really big decimals?
|
||||||
Value::Primitive(Primitive::Bytes(decimal)) => Bson::FloatingPoint(
|
UntaggedValue::Primitive(Primitive::Bytes(decimal)) => Bson::FloatingPoint(
|
||||||
(decimal)
|
(decimal)
|
||||||
.to_f64()
|
.to_f64()
|
||||||
.expect("Unimplemented BUG: What about big decimals?"),
|
.expect("Unimplemented BUG: What about big decimals?"),
|
||||||
),
|
),
|
||||||
Value::Primitive(Primitive::Duration(secs)) => Bson::I64(*secs as i64),
|
UntaggedValue::Primitive(Primitive::Duration(secs)) => Bson::I64(*secs as i64),
|
||||||
Value::Primitive(Primitive::Date(d)) => Bson::UtcDatetime(*d),
|
UntaggedValue::Primitive(Primitive::Date(d)) => Bson::UtcDatetime(*d),
|
||||||
Value::Primitive(Primitive::EndOfStream) => Bson::Null,
|
UntaggedValue::Primitive(Primitive::EndOfStream) => Bson::Null,
|
||||||
Value::Primitive(Primitive::BeginningOfStream) => Bson::Null,
|
UntaggedValue::Primitive(Primitive::BeginningOfStream) => Bson::Null,
|
||||||
Value::Primitive(Primitive::Decimal(d)) => Bson::FloatingPoint(d.to_f64().unwrap()),
|
UntaggedValue::Primitive(Primitive::Decimal(d)) => Bson::FloatingPoint(d.to_f64().unwrap()),
|
||||||
Value::Primitive(Primitive::Int(i)) => {
|
UntaggedValue::Primitive(Primitive::Int(i)) => {
|
||||||
Bson::I64(i.tagged(&v.tag).coerce_into("converting to BSON")?)
|
Bson::I64(i.tagged(&v.tag).coerce_into("converting to BSON")?)
|
||||||
}
|
}
|
||||||
Value::Primitive(Primitive::Nothing) => Bson::Null,
|
UntaggedValue::Primitive(Primitive::Nothing) => Bson::Null,
|
||||||
Value::Primitive(Primitive::String(s)) => Bson::String(s.clone()),
|
UntaggedValue::Primitive(Primitive::String(s)) => Bson::String(s.clone()),
|
||||||
Value::Primitive(Primitive::ColumnPath(path)) => Bson::Array(
|
UntaggedValue::Primitive(Primitive::ColumnPath(path)) => Bson::Array(
|
||||||
path.iter()
|
path.iter()
|
||||||
.map(|x| match &x.item {
|
.map(|x| match &x.unspanned {
|
||||||
RawPathMember::String(string) => Ok(Bson::String(string.clone())),
|
UnspannedPathMember::String(string) => Ok(Bson::String(string.clone())),
|
||||||
RawPathMember::Int(int) => Ok(Bson::I64(
|
UnspannedPathMember::Int(int) => Ok(Bson::I64(
|
||||||
int.tagged(&v.tag).coerce_into("converting to BSON")?,
|
int.tagged(&v.tag).coerce_into("converting to BSON")?,
|
||||||
)),
|
)),
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<Bson>, ShellError>>()?,
|
.collect::<Result<Vec<Bson>, ShellError>>()?,
|
||||||
),
|
),
|
||||||
Value::Primitive(Primitive::Pattern(p)) => Bson::String(p.clone()),
|
UntaggedValue::Primitive(Primitive::Pattern(p)) => Bson::String(p.clone()),
|
||||||
Value::Primitive(Primitive::Path(s)) => Bson::String(s.display().to_string()),
|
UntaggedValue::Primitive(Primitive::Path(s)) => Bson::String(s.display().to_string()),
|
||||||
Value::Table(l) => Bson::Array(
|
UntaggedValue::Table(l) => Bson::Array(
|
||||||
l.iter()
|
l.iter()
|
||||||
.map(|x| value_to_bson_value(x))
|
.map(|x| value_to_bson_value(x))
|
||||||
.collect::<Result<_, _>>()?,
|
.collect::<Result<_, _>>()?,
|
||||||
),
|
),
|
||||||
Value::Block(_) => Bson::Null,
|
UntaggedValue::Block(_) => Bson::Null,
|
||||||
Value::Error(e) => return Err(e.clone()),
|
UntaggedValue::Error(e) => return Err(e.clone()),
|
||||||
Value::Primitive(Primitive::Binary(b)) => Bson::Binary(BinarySubtype::Generic, b.clone()),
|
UntaggedValue::Primitive(Primitive::Binary(b)) => {
|
||||||
Value::Row(o) => object_value_to_bson(o)?,
|
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<Bson, ShellError> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_binary_subtype<'a>(tagged_value: &'a Tagged<Value>) -> Result<BinarySubtype, ShellError> {
|
fn get_binary_subtype<'a>(tagged_value: &'a Value) -> Result<BinarySubtype, ShellError> {
|
||||||
match tagged_value.item() {
|
match &tagged_value.value {
|
||||||
Value::Primitive(Primitive::String(s)) => Ok(match s.as_ref() {
|
UntaggedValue::Primitive(Primitive::String(s)) => Ok(match s.as_ref() {
|
||||||
"generic" => BinarySubtype::Generic,
|
"generic" => BinarySubtype::Generic,
|
||||||
"function" => BinarySubtype::Function,
|
"function" => BinarySubtype::Function,
|
||||||
"binary_old" => BinarySubtype::BinaryOld,
|
"binary_old" => BinarySubtype::BinaryOld,
|
||||||
@ -182,7 +184,7 @@ fn get_binary_subtype<'a>(tagged_value: &'a Tagged<Value>) -> Result<BinarySubty
|
|||||||
"md5" => BinarySubtype::Md5,
|
"md5" => BinarySubtype::Md5,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}),
|
}),
|
||||||
Value::Primitive(Primitive::Int(i)) => Ok(BinarySubtype::UserDefined(
|
UntaggedValue::Primitive(Primitive::Int(i)) => Ok(BinarySubtype::UserDefined(
|
||||||
i.tagged(&tagged_value.tag)
|
i.tagged(&tagged_value.tag)
|
||||||
.coerce_into("converting to BSON binary subtype")?,
|
.coerce_into("converting to BSON binary subtype")?,
|
||||||
)),
|
)),
|
||||||
@ -246,12 +248,14 @@ fn bson_value_to_bytes(bson: Bson, tag: Tag) -> Result<Vec<u8>, ShellError> {
|
|||||||
fn to_bson(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
fn to_bson(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
let args = args.evaluate_once(registry)?;
|
let args = args.evaluate_once(registry)?;
|
||||||
let name_tag = args.name_tag();
|
let name_tag = args.name_tag();
|
||||||
|
let name_span = name_tag.span;
|
||||||
|
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let input: Vec<Tagged<Value>> = args.input.values.collect().await;
|
let input: Vec<Value> = args.input.values.collect().await;
|
||||||
|
|
||||||
let to_process_input = if input.len() > 1 {
|
let to_process_input = if input.len() > 1 {
|
||||||
let tag = input[0].tag.clone();
|
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 {
|
} else if input.len() == 1 {
|
||||||
input
|
input
|
||||||
} else {
|
} else {
|
||||||
@ -261,16 +265,18 @@ fn to_bson(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream
|
|||||||
for value in to_process_input {
|
for value in to_process_input {
|
||||||
match value_to_bson_value(&value) {
|
match value_to_bson_value(&value) {
|
||||||
Ok(bson_value) => {
|
Ok(bson_value) => {
|
||||||
|
let value_span = value.tag.span;
|
||||||
|
|
||||||
match bson_value_to_bytes(bson_value, name_tag.clone()) {
|
match bson_value_to_bytes(bson_value, name_tag.clone()) {
|
||||||
Ok(x) => yield ReturnSuccess::value(
|
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(
|
_ => yield Err(ShellError::labeled_error_with_secondary(
|
||||||
"Expected a table with BSON-compatible structure.tag() from pipeline",
|
"Expected a table with BSON-compatible structure.tag() from pipeline",
|
||||||
"requires BSON-compatible input",
|
"requires BSON-compatible input",
|
||||||
&name_tag,
|
name_span,
|
||||||
"originates from here".to_string(),
|
"originates from here".to_string(),
|
||||||
value.tag(),
|
value_span,
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ pub struct ToCSV;
|
|||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct ToCSVArgs {
|
pub struct ToCSVArgs {
|
||||||
headerless: bool,
|
headerless: bool,
|
||||||
separator: Option<Tagged<Value>>,
|
separator: Option<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WholeStreamCommand for ToCSV {
|
impl WholeStreamCommand for ToCSV {
|
||||||
@ -44,8 +44,8 @@ fn to_csv(
|
|||||||
runnable_context: RunnableContext,
|
runnable_context: RunnableContext,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let sep = match separator {
|
let sep = match separator {
|
||||||
Some(Tagged {
|
Some(Value {
|
||||||
item: Value::Primitive(Primitive::String(s)),
|
value: UntaggedValue::Primitive(Primitive::String(s)),
|
||||||
tag,
|
tag,
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
|
@ -2,15 +2,16 @@ use crate::data::{Primitive, Value};
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use csv::WriterBuilder;
|
use csv::WriterBuilder;
|
||||||
use indexmap::{indexset, IndexSet};
|
use indexmap::{indexset, IndexSet};
|
||||||
|
use nu_source::Spanned;
|
||||||
|
|
||||||
fn from_value_to_delimited_string(
|
fn from_value_to_delimited_string(
|
||||||
tagged_value: &Tagged<Value>,
|
tagged_value: &Value,
|
||||||
separator: char,
|
separator: char,
|
||||||
) -> Result<String, ShellError> {
|
) -> Result<String, ShellError> {
|
||||||
let v = &tagged_value.item;
|
let v = &tagged_value.value;
|
||||||
|
|
||||||
match v {
|
match v {
|
||||||
Value::Row(o) => {
|
UntaggedValue::Row(o) => {
|
||||||
let mut wtr = WriterBuilder::new()
|
let mut wtr = WriterBuilder::new()
|
||||||
.delimiter(separator as u8)
|
.delimiter(separator as u8)
|
||||||
.from_writer(vec![]);
|
.from_writer(vec![]);
|
||||||
@ -41,7 +42,7 @@ fn from_value_to_delimited_string(
|
|||||||
)
|
)
|
||||||
})?);
|
})?);
|
||||||
}
|
}
|
||||||
Value::Table(list) => {
|
UntaggedValue::Table(list) => {
|
||||||
let mut wtr = WriterBuilder::new()
|
let mut wtr = WriterBuilder::new()
|
||||||
.delimiter(separator as u8)
|
.delimiter(separator as u8)
|
||||||
.from_writer(vec![]);
|
.from_writer(vec![]);
|
||||||
@ -54,7 +55,7 @@ fn from_value_to_delimited_string(
|
|||||||
for l in list {
|
for l in list {
|
||||||
let mut row = vec![];
|
let mut row = vec![];
|
||||||
for desc in &merged_descriptors {
|
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) => {
|
Some(s) => {
|
||||||
row.push(to_string_tagged_value(&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<Value> ?
|
// NOTE: could this be useful more widely and implemented on Value ?
|
||||||
pub fn clone_tagged_value(v: &Tagged<Value>) -> Tagged<Value> {
|
pub fn clone_tagged_value(v: &Value) -> Value {
|
||||||
match &v.item {
|
match &v.value {
|
||||||
Value::Primitive(Primitive::String(s)) => Value::Primitive(Primitive::String(s.clone())),
|
UntaggedValue::Primitive(Primitive::String(s)) => {
|
||||||
Value::Primitive(Primitive::Nothing) => Value::Primitive(Primitive::Nothing),
|
UntaggedValue::Primitive(Primitive::String(s.clone()))
|
||||||
Value::Primitive(Primitive::Boolean(b)) => Value::Primitive(Primitive::Boolean(b.clone())),
|
}
|
||||||
Value::Primitive(Primitive::Decimal(f)) => Value::Primitive(Primitive::Decimal(f.clone())),
|
UntaggedValue::Primitive(Primitive::Nothing) => {
|
||||||
Value::Primitive(Primitive::Int(i)) => Value::Primitive(Primitive::Int(i.clone())),
|
UntaggedValue::Primitive(Primitive::Nothing)
|
||||||
Value::Primitive(Primitive::Path(x)) => Value::Primitive(Primitive::Path(x.clone())),
|
}
|
||||||
Value::Primitive(Primitive::Bytes(b)) => Value::Primitive(Primitive::Bytes(b.clone())),
|
UntaggedValue::Primitive(Primitive::Boolean(b)) => {
|
||||||
Value::Primitive(Primitive::Date(d)) => Value::Primitive(Primitive::Date(d.clone())),
|
UntaggedValue::Primitive(Primitive::Boolean(b.clone()))
|
||||||
Value::Row(o) => Value::Row(o.clone()),
|
}
|
||||||
Value::Table(l) => Value::Table(l.clone()),
|
UntaggedValue::Primitive(Primitive::Decimal(f)) => {
|
||||||
Value::Block(_) => Value::Primitive(Primitive::Nothing),
|
UntaggedValue::Primitive(Primitive::Decimal(f.clone()))
|
||||||
_ => Value::Primitive(Primitive::Nothing),
|
}
|
||||||
|
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<Value> ?
|
// NOTE: could this be useful more widely and implemented on Value ?
|
||||||
fn to_string_tagged_value(v: &Tagged<Value>) -> Result<String, ShellError> {
|
fn to_string_tagged_value(v: &Value) -> Result<String, ShellError> {
|
||||||
match &v.item {
|
match &v.value {
|
||||||
Value::Primitive(Primitive::Date(d)) => Ok(d.to_string()),
|
UntaggedValue::Primitive(Primitive::Date(d)) => Ok(d.to_string()),
|
||||||
Value::Primitive(Primitive::Bytes(b)) => {
|
UntaggedValue::Primitive(Primitive::Bytes(b)) => {
|
||||||
let tmp = format!("{}", b);
|
let tmp = format!("{}", b);
|
||||||
Ok(tmp)
|
Ok(tmp)
|
||||||
}
|
}
|
||||||
Value::Primitive(Primitive::Boolean(_)) => Ok(v.as_string()?),
|
UntaggedValue::Primitive(Primitive::Boolean(_)) => Ok(v.as_string()?),
|
||||||
Value::Primitive(Primitive::Decimal(_)) => Ok(v.as_string()?),
|
UntaggedValue::Primitive(Primitive::Decimal(_)) => Ok(v.as_string()?),
|
||||||
Value::Primitive(Primitive::Int(_)) => Ok(v.as_string()?),
|
UntaggedValue::Primitive(Primitive::Int(_)) => Ok(v.as_string()?),
|
||||||
Value::Primitive(Primitive::Path(_)) => Ok(v.as_string()?),
|
UntaggedValue::Primitive(Primitive::Path(_)) => Ok(v.as_string()?),
|
||||||
Value::Table(_) => return Ok(String::from("[Table]")),
|
UntaggedValue::Table(_) => return Ok(String::from("[Table]")),
|
||||||
Value::Row(_) => return Ok(String::from("[Row]")),
|
UntaggedValue::Row(_) => return Ok(String::from("[Row]")),
|
||||||
Value::Primitive(Primitive::String(s)) => return Ok(s.to_string()),
|
UntaggedValue::Primitive(Primitive::String(s)) => return Ok(s.to_string()),
|
||||||
_ => {
|
_ => {
|
||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"Unexpected value",
|
"Unexpected value",
|
||||||
@ -129,7 +146,7 @@ fn to_string_tagged_value(v: &Tagged<Value>) -> Result<String, ShellError> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge_descriptors(values: &[Tagged<Value>]) -> Vec<Spanned<String>> {
|
fn merge_descriptors(values: &[Value]) -> Vec<Spanned<String>> {
|
||||||
let mut ret: Vec<Spanned<String>> = vec![];
|
let mut ret: Vec<Spanned<String>> = vec![];
|
||||||
let mut seen: IndexSet<String> = indexset! {};
|
let mut seen: IndexSet<String> = indexset! {};
|
||||||
for value in values {
|
for value in values {
|
||||||
@ -150,13 +167,14 @@ pub fn to_delimited_data(
|
|||||||
RunnableContext { input, name, .. }: RunnableContext,
|
RunnableContext { input, name, .. }: RunnableContext,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let name_tag = name;
|
let name_tag = name;
|
||||||
|
let name_span = name_tag.span;
|
||||||
|
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let input: Vec<Tagged<Value>> = input.values.collect().await;
|
let input: Vec<Value> = input.values.collect().await;
|
||||||
|
|
||||||
let to_process_input = if input.len() > 1 {
|
let to_process_input = if input.len() > 1 {
|
||||||
let tag = input[0].tag.clone();
|
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 {
|
} else if input.len() == 1 {
|
||||||
input
|
input
|
||||||
} else {
|
} else {
|
||||||
@ -171,7 +189,7 @@ pub fn to_delimited_data(
|
|||||||
} else {
|
} else {
|
||||||
x
|
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);
|
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(
|
yield Err(ShellError::labeled_error_with_secondary(
|
||||||
expected,
|
expected,
|
||||||
requires,
|
requires,
|
||||||
&name_tag,
|
name_span,
|
||||||
"originates from here".to_string(),
|
"originates from here".to_string(),
|
||||||
value.tag(),
|
value.tag.span,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
use crate::commands::WholeStreamCommand;
|
||||||
use crate::data::{Primitive, Value};
|
use crate::data::base::{Primitive, UntaggedValue, Value};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::RawPathMember;
|
use crate::UnspannedPathMember;
|
||||||
|
|
||||||
pub struct ToJSON;
|
pub struct ToJSON;
|
||||||
|
|
||||||
@ -27,35 +27,40 @@ impl WholeStreamCommand for ToJSON {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value_to_json_value(v: &Tagged<Value>) -> Result<serde_json::Value, ShellError> {
|
pub fn value_to_json_value(v: &Value) -> Result<serde_json::Value, ShellError> {
|
||||||
Ok(match v.item() {
|
Ok(match &v.value {
|
||||||
Value::Primitive(Primitive::Boolean(b)) => serde_json::Value::Bool(*b),
|
UntaggedValue::Primitive(Primitive::Boolean(b)) => serde_json::Value::Bool(*b),
|
||||||
Value::Primitive(Primitive::Bytes(b)) => serde_json::Value::Number(
|
UntaggedValue::Primitive(Primitive::Bytes(b)) => serde_json::Value::Number(
|
||||||
serde_json::Number::from(b.to_u64().expect("What about really big numbers")),
|
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))
|
serde_json::Value::Number(serde_json::Number::from(*secs))
|
||||||
}
|
}
|
||||||
Value::Primitive(Primitive::Date(d)) => serde_json::Value::String(d.to_string()),
|
UntaggedValue::Primitive(Primitive::Date(d)) => serde_json::Value::String(d.to_string()),
|
||||||
Value::Primitive(Primitive::EndOfStream) => serde_json::Value::Null,
|
UntaggedValue::Primitive(Primitive::EndOfStream) => serde_json::Value::Null,
|
||||||
Value::Primitive(Primitive::BeginningOfStream) => serde_json::Value::Null,
|
UntaggedValue::Primitive(Primitive::BeginningOfStream) => serde_json::Value::Null,
|
||||||
Value::Primitive(Primitive::Decimal(f)) => serde_json::Value::Number(
|
UntaggedValue::Primitive(Primitive::Decimal(f)) => serde_json::Value::Number(
|
||||||
serde_json::Number::from_f64(
|
serde_json::Number::from_f64(
|
||||||
f.to_f64().expect("TODO: What about really big decimals?"),
|
f.to_f64().expect("TODO: What about really big decimals?"),
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
),
|
),
|
||||||
Value::Primitive(Primitive::Int(i)) => serde_json::Value::Number(serde_json::Number::from(
|
UntaggedValue::Primitive(Primitive::Int(i)) => {
|
||||||
CoerceInto::<i64>::coerce_into(i.tagged(&v.tag), "converting to JSON number")?,
|
serde_json::Value::Number(serde_json::Number::from(CoerceInto::<i64>::coerce_into(
|
||||||
)),
|
i.tagged(&v.tag),
|
||||||
Value::Primitive(Primitive::Nothing) => serde_json::Value::Null,
|
"converting to JSON number",
|
||||||
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::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()
|
path.iter()
|
||||||
.map(|x| match &x.item {
|
.map(|x| match &x.unspanned {
|
||||||
RawPathMember::String(string) => Ok(serde_json::Value::String(string.clone())),
|
UnspannedPathMember::String(string) => {
|
||||||
RawPathMember::Int(int) => Ok(serde_json::Value::Number(
|
Ok(serde_json::Value::String(string.clone()))
|
||||||
|
}
|
||||||
|
UnspannedPathMember::Int(int) => Ok(serde_json::Value::Number(
|
||||||
serde_json::Number::from(CoerceInto::<i64>::coerce_into(
|
serde_json::Number::from(CoerceInto::<i64>::coerce_into(
|
||||||
int.tagged(&v.tag),
|
int.tagged(&v.tag),
|
||||||
"converting to JSON number",
|
"converting to JSON number",
|
||||||
@ -64,19 +69,21 @@ pub fn value_to_json_value(v: &Tagged<Value>) -> Result<serde_json::Value, Shell
|
|||||||
})
|
})
|
||||||
.collect::<Result<Vec<serde_json::Value>, ShellError>>()?,
|
.collect::<Result<Vec<serde_json::Value>, 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)?),
|
UntaggedValue::Table(l) => serde_json::Value::Array(json_list(l)?),
|
||||||
Value::Error(e) => return Err(e.clone()),
|
UntaggedValue::Error(e) => return Err(e.clone()),
|
||||||
Value::Block(_) => serde_json::Value::Null,
|
UntaggedValue::Block(_) => serde_json::Value::Null,
|
||||||
Value::Primitive(Primitive::Binary(b)) => serde_json::Value::Array(
|
UntaggedValue::Primitive(Primitive::Binary(b)) => serde_json::Value::Array(
|
||||||
b.iter()
|
b.iter()
|
||||||
.map(|x| {
|
.map(|x| {
|
||||||
serde_json::Value::Number(serde_json::Number::from_f64(*x as f64).unwrap())
|
serde_json::Value::Number(serde_json::Number::from_f64(*x as f64).unwrap())
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
Value::Row(o) => {
|
UntaggedValue::Row(o) => {
|
||||||
let mut m = serde_json::Map::new();
|
let mut m = serde_json::Map::new();
|
||||||
for (k, v) in o.entries.iter() {
|
for (k, v) in o.entries.iter() {
|
||||||
m.insert(k.clone(), value_to_json_value(v)?);
|
m.insert(k.clone(), value_to_json_value(v)?);
|
||||||
@ -86,7 +93,7 @@ pub fn value_to_json_value(v: &Tagged<Value>) -> Result<serde_json::Value, Shell
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn json_list(input: &Vec<Tagged<Value>>) -> Result<Vec<serde_json::Value>, ShellError> {
|
fn json_list(input: &Vec<Value>) -> Result<Vec<serde_json::Value>, ShellError> {
|
||||||
let mut out = vec![];
|
let mut out = vec![];
|
||||||
|
|
||||||
for value in input {
|
for value in input {
|
||||||
@ -99,12 +106,13 @@ fn json_list(input: &Vec<Tagged<Value>>) -> Result<Vec<serde_json::Value>, Shell
|
|||||||
fn to_json(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
fn to_json(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
let args = args.evaluate_once(registry)?;
|
let args = args.evaluate_once(registry)?;
|
||||||
let name_tag = args.name_tag();
|
let name_tag = args.name_tag();
|
||||||
|
let name_span = name_tag.span;
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let input: Vec<Tagged<Value>> = args.input.values.collect().await;
|
let input: Vec<Value> = args.input.values.collect().await;
|
||||||
|
|
||||||
let to_process_input = if input.len() > 1 {
|
let to_process_input = if input.len() > 1 {
|
||||||
let tag = input[0].tag.clone();
|
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 {
|
} else if input.len() == 1 {
|
||||||
input
|
input
|
||||||
} else {
|
} else {
|
||||||
@ -114,16 +122,18 @@ fn to_json(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream
|
|||||||
for value in to_process_input {
|
for value in to_process_input {
|
||||||
match value_to_json_value(&value) {
|
match value_to_json_value(&value) {
|
||||||
Ok(json_value) => {
|
Ok(json_value) => {
|
||||||
|
let value_span = value.tag.span;
|
||||||
|
|
||||||
match serde_json::to_string(&json_value) {
|
match serde_json::to_string(&json_value) {
|
||||||
Ok(x) => yield ReturnSuccess::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(
|
_ => yield Err(ShellError::labeled_error_with_secondary(
|
||||||
"Expected a table with JSON-compatible structure.tag() from pipeline",
|
"Expected a table with JSON-compatible structure.tag() from pipeline",
|
||||||
"requires JSON-compatible input",
|
"requires JSON-compatible input",
|
||||||
&name_tag,
|
name_span,
|
||||||
"originates from here".to_string(),
|
"originates from here".to_string(),
|
||||||
value.tag(),
|
value_span,
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,9 +69,9 @@ fn comma_concat(acc: String, current: String) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_columns(rows: &Vec<Tagged<Value>>) -> Result<String, std::io::Error> {
|
fn get_columns(rows: &Vec<Value>) -> Result<String, std::io::Error> {
|
||||||
match &rows[0].item {
|
match &rows[0].value {
|
||||||
Value::Row(d) => Ok(d
|
UntaggedValue::Row(d) => Ok(d
|
||||||
.entries
|
.entries
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(k, _v)| k.clone())
|
.map(|(k, _v)| k.clone())
|
||||||
@ -84,8 +84,8 @@ fn get_columns(rows: &Vec<Tagged<Value>>) -> Result<String, std::io::Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn nu_value_to_sqlite_string(v: Value) -> String {
|
fn nu_value_to_sqlite_string(v: Value) -> String {
|
||||||
match v {
|
match &v.value {
|
||||||
Value::Primitive(p) => match p {
|
UntaggedValue::Primitive(p) => match p {
|
||||||
Primitive::Nothing => "NULL".into(),
|
Primitive::Nothing => "NULL".into(),
|
||||||
Primitive::Int(i) => format!("{}", i),
|
Primitive::Int(i) => format!("{}", i),
|
||||||
Primitive::Duration(u) => format!("{}", u),
|
Primitive::Duration(u) => format!("{}", u),
|
||||||
@ -106,15 +106,15 @@ fn nu_value_to_sqlite_string(v: Value) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_insert_values(rows: Vec<Tagged<Value>>) -> Result<String, std::io::Error> {
|
fn get_insert_values(rows: Vec<Value>) -> Result<String, std::io::Error> {
|
||||||
let values: Result<Vec<_>, _> = rows
|
let values: Result<Vec<_>, _> = rows
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|value| match value.item {
|
.map(|value| match value.value {
|
||||||
Value::Row(d) => Ok(format!(
|
UntaggedValue::Row(d) => Ok(format!(
|
||||||
"({})",
|
"({})",
|
||||||
d.entries
|
d.entries
|
||||||
.iter()
|
.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)
|
.fold("".to_string(), comma_concat)
|
||||||
)),
|
)),
|
||||||
_ => Err(std::io::Error::new(
|
_ => Err(std::io::Error::new(
|
||||||
@ -129,8 +129,8 @@ fn get_insert_values(rows: Vec<Tagged<Value>>) -> Result<String, std::io::Error>
|
|||||||
|
|
||||||
fn generate_statements(table: Dictionary) -> Result<(String, String), std::io::Error> {
|
fn generate_statements(table: Dictionary) -> Result<(String, String), std::io::Error> {
|
||||||
let table_name = match table.entries.get("table_name") {
|
let table_name = match table.entries.get("table_name") {
|
||||||
Some(Tagged {
|
Some(Value {
|
||||||
item: Value::Primitive(Primitive::String(table_name)),
|
value: UntaggedValue::Primitive(Primitive::String(table_name)),
|
||||||
..
|
..
|
||||||
}) => 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") {
|
let (columns, insert_values) = match table.entries.get("table_values") {
|
||||||
Some(Tagged {
|
Some(Value {
|
||||||
item: Value::Table(l),
|
value: UntaggedValue::Table(l),
|
||||||
..
|
..
|
||||||
}) => (get_columns(l), get_insert_values(l.to_vec())),
|
}) => (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))
|
Ok((create, insert))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sqlite_input_stream_to_bytes(
|
fn sqlite_input_stream_to_bytes(values: Vec<Value>) -> Result<Value, std::io::Error> {
|
||||||
values: Vec<Tagged<Value>>,
|
|
||||||
) -> Result<Tagged<Value>, std::io::Error> {
|
|
||||||
// FIXME: should probably write a sqlite virtual filesystem
|
// FIXME: should probably write a sqlite virtual filesystem
|
||||||
// that will allow us to use bytes as a file to avoid this
|
// that will allow us to use bytes as a file to avoid this
|
||||||
// write out, but this will require C code. Might be
|
// 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();
|
let tag = values[0].tag.clone();
|
||||||
for value in values.into_iter() {
|
for value in values.into_iter() {
|
||||||
match value.item() {
|
match &value.value {
|
||||||
Value::Row(d) => {
|
UntaggedValue::Row(d) => {
|
||||||
let (create, insert) = generate_statements(d.to_owned())?;
|
let (create, insert) = generate_statements(d.to_owned())?;
|
||||||
match conn
|
match conn
|
||||||
.execute(&create, NO_PARAMS)
|
.execute(&create, NO_PARAMS)
|
||||||
@ -197,14 +195,14 @@ fn sqlite_input_stream_to_bytes(
|
|||||||
}
|
}
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
tempfile.read_to_end(&mut out)?;
|
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<OutputStream, ShellError> {
|
fn to_sqlite(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
let args = args.evaluate_once(registry)?;
|
let args = args.evaluate_once(registry)?;
|
||||||
let name_tag = args.name_tag();
|
let name_tag = args.name_tag();
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let input: Vec<Tagged<Value>> = args.input.values.collect().await;
|
let input: Vec<Value> = args.input.values.collect().await;
|
||||||
|
|
||||||
match sqlite_input_stream_to_bytes(input) {
|
match sqlite_input_stream_to_bytes(input) {
|
||||||
Ok(out) => yield ReturnSuccess::value(out),
|
Ok(out) => yield ReturnSuccess::value(out),
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
use crate::commands::WholeStreamCommand;
|
||||||
use crate::data::{Primitive, Value};
|
use crate::data::{Primitive, Value};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::RawPathMember;
|
use crate::UnspannedPathMember;
|
||||||
|
|
||||||
pub struct ToTOML;
|
pub struct ToTOML;
|
||||||
|
|
||||||
@ -27,33 +27,37 @@ impl WholeStreamCommand for ToTOML {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value_to_toml_value(v: &Tagged<Value>) -> Result<toml::Value, ShellError> {
|
pub fn value_to_toml_value(v: &Value) -> Result<toml::Value, ShellError> {
|
||||||
Ok(match v.item() {
|
Ok(match &v.value {
|
||||||
Value::Primitive(Primitive::Boolean(b)) => toml::Value::Boolean(*b),
|
UntaggedValue::Primitive(Primitive::Boolean(b)) => toml::Value::Boolean(*b),
|
||||||
Value::Primitive(Primitive::Bytes(b)) => toml::Value::Integer(*b as i64),
|
UntaggedValue::Primitive(Primitive::Bytes(b)) => toml::Value::Integer(*b as i64),
|
||||||
Value::Primitive(Primitive::Duration(d)) => toml::Value::Integer(*d as i64),
|
UntaggedValue::Primitive(Primitive::Duration(d)) => toml::Value::Integer(*d as i64),
|
||||||
Value::Primitive(Primitive::Date(d)) => toml::Value::String(d.to_string()),
|
UntaggedValue::Primitive(Primitive::Date(d)) => toml::Value::String(d.to_string()),
|
||||||
Value::Primitive(Primitive::EndOfStream) => {
|
UntaggedValue::Primitive(Primitive::EndOfStream) => {
|
||||||
toml::Value::String("<End of Stream>".to_string())
|
toml::Value::String("<End of Stream>".to_string())
|
||||||
}
|
}
|
||||||
Value::Primitive(Primitive::BeginningOfStream) => {
|
UntaggedValue::Primitive(Primitive::BeginningOfStream) => {
|
||||||
toml::Value::String("<Beginning of Stream>".to_string())
|
toml::Value::String("<Beginning of Stream>".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")?)
|
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")?)
|
toml::Value::Integer(i.tagged(&v.tag).coerce_into("converting to TOML integer")?)
|
||||||
}
|
}
|
||||||
Value::Primitive(Primitive::Nothing) => toml::Value::String("<Nothing>".to_string()),
|
UntaggedValue::Primitive(Primitive::Nothing) => {
|
||||||
Value::Primitive(Primitive::Pattern(s)) => toml::Value::String(s.clone()),
|
toml::Value::String("<Nothing>".to_string())
|
||||||
Value::Primitive(Primitive::String(s)) => toml::Value::String(s.clone()),
|
}
|
||||||
Value::Primitive(Primitive::Path(s)) => toml::Value::String(s.display().to_string()),
|
UntaggedValue::Primitive(Primitive::Pattern(s)) => toml::Value::String(s.clone()),
|
||||||
Value::Primitive(Primitive::ColumnPath(path)) => toml::Value::Array(
|
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()
|
path.iter()
|
||||||
.map(|x| match &x.item {
|
.map(|x| match &x.unspanned {
|
||||||
RawPathMember::String(string) => Ok(toml::Value::String(string.clone())),
|
UnspannedPathMember::String(string) => Ok(toml::Value::String(string.clone())),
|
||||||
RawPathMember::Int(int) => Ok(toml::Value::Integer(
|
UnspannedPathMember::Int(int) => Ok(toml::Value::Integer(
|
||||||
int.tagged(&v.tag)
|
int.tagged(&v.tag)
|
||||||
.coerce_into("converting to TOML integer")?,
|
.coerce_into("converting to TOML integer")?,
|
||||||
)),
|
)),
|
||||||
@ -61,13 +65,13 @@ pub fn value_to_toml_value(v: &Tagged<Value>) -> Result<toml::Value, ShellError>
|
|||||||
.collect::<Result<Vec<toml::Value>, ShellError>>()?,
|
.collect::<Result<Vec<toml::Value>, ShellError>>()?,
|
||||||
),
|
),
|
||||||
|
|
||||||
Value::Table(l) => toml::Value::Array(collect_values(l)?),
|
UntaggedValue::Table(l) => toml::Value::Array(collect_values(l)?),
|
||||||
Value::Error(e) => return Err(e.clone()),
|
UntaggedValue::Error(e) => return Err(e.clone()),
|
||||||
Value::Block(_) => toml::Value::String("<Block>".to_string()),
|
UntaggedValue::Block(_) => toml::Value::String("<Block>".to_string()),
|
||||||
Value::Primitive(Primitive::Binary(b)) => {
|
UntaggedValue::Primitive(Primitive::Binary(b)) => {
|
||||||
toml::Value::Array(b.iter().map(|x| toml::Value::Integer(*x as i64)).collect())
|
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();
|
let mut m = toml::map::Map::new();
|
||||||
for (k, v) in o.entries.iter() {
|
for (k, v) in o.entries.iter() {
|
||||||
m.insert(k.clone(), value_to_toml_value(v)?);
|
m.insert(k.clone(), value_to_toml_value(v)?);
|
||||||
@ -77,7 +81,7 @@ pub fn value_to_toml_value(v: &Tagged<Value>) -> Result<toml::Value, ShellError>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_values(input: &Vec<Tagged<Value>>) -> Result<Vec<toml::Value>, ShellError> {
|
fn collect_values(input: &Vec<Value>) -> Result<Vec<toml::Value>, ShellError> {
|
||||||
let mut out = vec![];
|
let mut out = vec![];
|
||||||
|
|
||||||
for value in input {
|
for value in input {
|
||||||
@ -90,12 +94,13 @@ fn collect_values(input: &Vec<Tagged<Value>>) -> Result<Vec<toml::Value>, ShellE
|
|||||||
fn to_toml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
fn to_toml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
let args = args.evaluate_once(registry)?;
|
let args = args.evaluate_once(registry)?;
|
||||||
let name_tag = args.name_tag();
|
let name_tag = args.name_tag();
|
||||||
|
let name_span = name_tag.span;
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let input: Vec<Tagged<Value>> = args.input.values.collect().await;
|
let input: Vec<Value> = args.input.values.collect().await;
|
||||||
|
|
||||||
let to_process_input = if input.len() > 1 {
|
let to_process_input = if input.len() > 1 {
|
||||||
let tag = input[0].tag.clone();
|
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 {
|
} else if input.len() == 1 {
|
||||||
input
|
input
|
||||||
} else {
|
} else {
|
||||||
@ -103,18 +108,19 @@ fn to_toml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream
|
|||||||
};
|
};
|
||||||
|
|
||||||
for value in to_process_input {
|
for value in to_process_input {
|
||||||
|
let value_span = value.tag.span;
|
||||||
match value_to_toml_value(&value) {
|
match value_to_toml_value(&value) {
|
||||||
Ok(toml_value) => {
|
Ok(toml_value) => {
|
||||||
match toml::to_string(&toml_value) {
|
match toml::to_string(&toml_value) {
|
||||||
Ok(x) => yield ReturnSuccess::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(
|
_ => yield Err(ShellError::labeled_error_with_secondary(
|
||||||
"Expected a table with TOML-compatible structure.tag() from pipeline",
|
"Expected a table with TOML-compatible structure.tag() from pipeline",
|
||||||
"requires TOML-compatible input",
|
"requires TOML-compatible input",
|
||||||
&name_tag,
|
name_span,
|
||||||
"originates from here".to_string(),
|
"originates from here".to_string(),
|
||||||
value.tag(),
|
value_span,
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,11 +32,11 @@ fn to_url(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream,
|
|||||||
let input = args.input;
|
let input = args.input;
|
||||||
|
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let input: Vec<Tagged<Value>> = input.values.collect().await;
|
let input: Vec<Value> = input.values.collect().await;
|
||||||
|
|
||||||
for value in input {
|
for value in input {
|
||||||
match value {
|
match value {
|
||||||
Tagged { item: Value::Row(row), .. } => {
|
Value { value: UntaggedValue::Row(row), .. } => {
|
||||||
let mut row_vec = vec![];
|
let mut row_vec = vec![];
|
||||||
for (k,v) in row.entries {
|
for (k,v) in row.entries {
|
||||||
match v.as_string() {
|
match v.as_string() {
|
||||||
@ -57,7 +57,7 @@ fn to_url(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream,
|
|||||||
|
|
||||||
match serde_urlencoded::to_string(row_vec) {
|
match serde_urlencoded::to_string(row_vec) {
|
||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
yield ReturnSuccess::value(Value::string(s).tagged(&tag));
|
yield ReturnSuccess::value(UntaggedValue::string(s).into_value(&tag));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
yield Err(ShellError::labeled_error(
|
yield Err(ShellError::labeled_error(
|
||||||
@ -68,13 +68,13 @@ fn to_url(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Tagged { tag: value_tag, .. } => {
|
Value { tag: value_tag, .. } => {
|
||||||
yield Err(ShellError::labeled_error_with_secondary(
|
yield Err(ShellError::labeled_error_with_secondary(
|
||||||
"Expected a table from pipeline",
|
"Expected a table from pipeline",
|
||||||
"requires table input",
|
"requires table input",
|
||||||
&tag,
|
&tag,
|
||||||
"value originates from here",
|
"value originates from here",
|
||||||
value_tag,
|
value_tag.span,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
use crate::commands::WholeStreamCommand;
|
||||||
use crate::data::{Primitive, Value};
|
use crate::data::{Primitive, Value};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::RawPathMember;
|
use crate::UnspannedPathMember;
|
||||||
|
|
||||||
pub struct ToYAML;
|
pub struct ToYAML;
|
||||||
|
|
||||||
@ -27,36 +27,39 @@ impl WholeStreamCommand for ToYAML {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value_to_yaml_value(v: &Tagged<Value>) -> Result<serde_yaml::Value, ShellError> {
|
pub fn value_to_yaml_value(v: &Value) -> Result<serde_yaml::Value, ShellError> {
|
||||||
Ok(match v.item() {
|
Ok(match &v.value {
|
||||||
Value::Primitive(Primitive::Boolean(b)) => serde_yaml::Value::Bool(*b),
|
UntaggedValue::Primitive(Primitive::Boolean(b)) => serde_yaml::Value::Bool(*b),
|
||||||
Value::Primitive(Primitive::Bytes(b)) => {
|
UntaggedValue::Primitive(Primitive::Bytes(b)) => {
|
||||||
serde_yaml::Value::Number(serde_yaml::Number::from(b.to_f64().unwrap()))
|
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()))
|
serde_yaml::Value::Number(serde_yaml::Number::from(secs.to_f64().unwrap()))
|
||||||
}
|
}
|
||||||
Value::Primitive(Primitive::Date(d)) => serde_yaml::Value::String(d.to_string()),
|
UntaggedValue::Primitive(Primitive::Date(d)) => serde_yaml::Value::String(d.to_string()),
|
||||||
Value::Primitive(Primitive::EndOfStream) => serde_yaml::Value::Null,
|
UntaggedValue::Primitive(Primitive::EndOfStream) => serde_yaml::Value::Null,
|
||||||
Value::Primitive(Primitive::BeginningOfStream) => serde_yaml::Value::Null,
|
UntaggedValue::Primitive(Primitive::BeginningOfStream) => serde_yaml::Value::Null,
|
||||||
Value::Primitive(Primitive::Decimal(f)) => {
|
UntaggedValue::Primitive(Primitive::Decimal(f)) => {
|
||||||
serde_yaml::Value::Number(serde_yaml::Number::from(f.to_f64().unwrap()))
|
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(
|
UntaggedValue::Primitive(Primitive::Int(i)) => {
|
||||||
CoerceInto::<i64>::coerce_into(i.tagged(&v.tag), "converting to YAML number")?,
|
serde_yaml::Value::Number(serde_yaml::Number::from(CoerceInto::<i64>::coerce_into(
|
||||||
)),
|
i.tagged(&v.tag),
|
||||||
Value::Primitive(Primitive::Nothing) => serde_yaml::Value::Null,
|
"converting to YAML number",
|
||||||
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::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![];
|
let mut out = vec![];
|
||||||
|
|
||||||
for member in path.iter() {
|
for member in path.iter() {
|
||||||
match &member.item {
|
match &member.unspanned {
|
||||||
RawPathMember::String(string) => {
|
UnspannedPathMember::String(string) => {
|
||||||
out.push(serde_yaml::Value::String(string.clone()))
|
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::<i64>::coerce_into(
|
serde_yaml::Number::from(CoerceInto::<i64>::coerce_into(
|
||||||
int.tagged(&member.span),
|
int.tagged(&member.span),
|
||||||
"converting to YAML number",
|
"converting to YAML number",
|
||||||
@ -67,9 +70,11 @@ pub fn value_to_yaml_value(v: &Tagged<Value>) -> Result<serde_yaml::Value, Shell
|
|||||||
|
|
||||||
serde_yaml::Value::Sequence(out)
|
serde_yaml::Value::Sequence(out)
|
||||||
}
|
}
|
||||||
Value::Primitive(Primitive::Path(s)) => 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![];
|
let mut out = vec![];
|
||||||
|
|
||||||
for value in l {
|
for value in l {
|
||||||
@ -78,14 +83,14 @@ pub fn value_to_yaml_value(v: &Tagged<Value>) -> Result<serde_yaml::Value, Shell
|
|||||||
|
|
||||||
serde_yaml::Value::Sequence(out)
|
serde_yaml::Value::Sequence(out)
|
||||||
}
|
}
|
||||||
Value::Error(e) => return Err(e.clone()),
|
UntaggedValue::Error(e) => return Err(e.clone()),
|
||||||
Value::Block(_) => serde_yaml::Value::Null,
|
UntaggedValue::Block(_) => serde_yaml::Value::Null,
|
||||||
Value::Primitive(Primitive::Binary(b)) => serde_yaml::Value::Sequence(
|
UntaggedValue::Primitive(Primitive::Binary(b)) => serde_yaml::Value::Sequence(
|
||||||
b.iter()
|
b.iter()
|
||||||
.map(|x| serde_yaml::Value::Number(serde_yaml::Number::from(*x)))
|
.map(|x| serde_yaml::Value::Number(serde_yaml::Number::from(*x)))
|
||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
Value::Row(o) => {
|
UntaggedValue::Row(o) => {
|
||||||
let mut m = serde_yaml::Mapping::new();
|
let mut m = serde_yaml::Mapping::new();
|
||||||
for (k, v) in o.entries.iter() {
|
for (k, v) in o.entries.iter() {
|
||||||
m.insert(
|
m.insert(
|
||||||
@ -101,12 +106,14 @@ pub fn value_to_yaml_value(v: &Tagged<Value>) -> Result<serde_yaml::Value, Shell
|
|||||||
fn to_yaml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
fn to_yaml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
let args = args.evaluate_once(registry)?;
|
let args = args.evaluate_once(registry)?;
|
||||||
let name_tag = args.name_tag();
|
let name_tag = args.name_tag();
|
||||||
|
let name_span = name_tag.span;
|
||||||
|
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
let input: Vec<Tagged<Value>> = args.input.values.collect().await;
|
let input: Vec<Value> = args.input.values.collect().await;
|
||||||
|
|
||||||
let to_process_input = if input.len() > 1 {
|
let to_process_input = if input.len() > 1 {
|
||||||
let tag = input[0].tag.clone();
|
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 {
|
} else if input.len() == 1 {
|
||||||
input
|
input
|
||||||
} else {
|
} else {
|
||||||
@ -114,18 +121,20 @@ fn to_yaml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream
|
|||||||
};
|
};
|
||||||
|
|
||||||
for value in to_process_input {
|
for value in to_process_input {
|
||||||
|
let value_span = value.tag.span;
|
||||||
|
|
||||||
match value_to_yaml_value(&value) {
|
match value_to_yaml_value(&value) {
|
||||||
Ok(yaml_value) => {
|
Ok(yaml_value) => {
|
||||||
match serde_yaml::to_string(&yaml_value) {
|
match serde_yaml::to_string(&yaml_value) {
|
||||||
Ok(x) => yield ReturnSuccess::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(
|
_ => yield Err(ShellError::labeled_error_with_secondary(
|
||||||
"Expected a table with YAML-compatible structure.tag() from pipeline",
|
"Expected a table with YAML-compatible structure.tag() from pipeline",
|
||||||
"requires YAML-compatible input",
|
"requires YAML-compatible input",
|
||||||
&name_tag,
|
name_span,
|
||||||
"originates from here".to_string(),
|
"originates from here".to_string(),
|
||||||
value.tag(),
|
value_span,
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
use crate::commands::WholeStreamCommand;
|
||||||
use crate::data::Value;
|
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ fn trim(args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream,
|
|||||||
.values
|
.values
|
||||||
.map(move |v| {
|
.map(move |v| {
|
||||||
let string = String::extract(&v)?;
|
let string = String::extract(&v)?;
|
||||||
ReturnSuccess::value(Value::string(string.trim()).tagged(v.tag()))
|
ReturnSuccess::value(UntaggedValue::string(string.trim()).into_value(v.tag()))
|
||||||
})
|
})
|
||||||
.to_output_stream())
|
.to_output_stream())
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
use crate::commands::WholeStreamCommand;
|
||||||
use crate::data::{Dictionary, Value};
|
use crate::data::Dictionary;
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::parser::registry::Signature;
|
use crate::parser::registry::Signature;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
@ -36,9 +36,9 @@ pub fn date(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStrea
|
|||||||
let mut indexmap = IndexMap::new();
|
let mut indexmap = IndexMap::new();
|
||||||
indexmap.insert(
|
indexmap.insert(
|
||||||
"version".to_string(),
|
"version".to_string(),
|
||||||
Value::string(clap::crate_version!()).tagged(&tag),
|
UntaggedValue::string(clap::crate_version!()).into_value(&tag),
|
||||||
);
|
);
|
||||||
|
|
||||||
let value = Value::Row(Dictionary::from(indexmap)).tagged(&tag);
|
let value = UntaggedValue::Row(Dictionary::from(indexmap)).into_value(&tag);
|
||||||
Ok(OutputStream::one(value))
|
Ok(OutputStream::one(value))
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::commands::WholeStreamCommand;
|
use crate::commands::WholeStreamCommand;
|
||||||
use crate::data::Value;
|
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
@ -41,8 +41,8 @@ pub fn what(
|
|||||||
pin_mut!(values);
|
pin_mut!(values);
|
||||||
|
|
||||||
while let Some(row) = values.next().await {
|
while let Some(row) = values.next().await {
|
||||||
let name = row.format_leaf().pretty_debug().plain_string(100000);
|
let name = row.format_leaf().plain_string(100000);
|
||||||
yield ReturnSuccess::value(Value::string(name).tagged(Tag::unknown_anchor(row.tag.span)));
|
yield ReturnSuccess::value(UntaggedValue::string(name).into_value(Tag::unknown_anchor(row.tag.span)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -28,13 +28,13 @@ impl PerItemCommand for Where {
|
|||||||
call_info: &CallInfo,
|
call_info: &CallInfo,
|
||||||
_registry: ®istry::CommandRegistry,
|
_registry: ®istry::CommandRegistry,
|
||||||
_raw_args: &RawCommandArgs,
|
_raw_args: &RawCommandArgs,
|
||||||
input: Tagged<Value>,
|
input: Value,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let input_clone = input.clone();
|
let input_clone = input.clone();
|
||||||
let condition = call_info.args.expect_nth(0)?;
|
let condition = call_info.args.expect_nth(0)?;
|
||||||
let stream = match condition {
|
let stream = match condition {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Block(block),
|
value: UntaggedValue::Block(block),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let result = block.invoke(&input_clone);
|
let result = block.invoke(&input_clone);
|
||||||
@ -49,7 +49,7 @@ impl PerItemCommand for Where {
|
|||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Tagged { tag, .. } => {
|
Value { tag, .. } => {
|
||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"Expected a condition",
|
"Expected a condition",
|
||||||
"where needs a condition",
|
"where needs a condition",
|
||||||
|
@ -42,17 +42,18 @@ pub fn which(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStre
|
|||||||
if let Some(v) = &args.call_info.args.positional {
|
if let Some(v) = &args.call_info.args.positional {
|
||||||
if v.len() > 0 {
|
if v.len() > 0 {
|
||||||
match &v[0] {
|
match &v[0] {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Primitive(Primitive::String(s)),
|
value: UntaggedValue::Primitive(Primitive::String(s)),
|
||||||
tag,
|
tag,
|
||||||
} => match which::which(&s) {
|
} => match which::which(&s) {
|
||||||
Ok(ok) => {
|
Ok(ok) => {
|
||||||
which_out
|
which_out.push_back(
|
||||||
.push_back(Value::Primitive(Primitive::Path(ok)).tagged(tag.clone()));
|
UntaggedValue::Primitive(Primitive::Path(ok)).into_value(tag.clone()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
Tagged { tag, .. } => {
|
Value { tag, .. } => {
|
||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"Expected a filename to find",
|
"Expected a filename to find",
|
||||||
"needs a filename",
|
"needs a filename",
|
||||||
|
@ -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::parser::{hir, hir::syntax_shape::ExpandContext};
|
||||||
use crate::prelude::*;
|
use crate::shell::shell_manager::ShellManager;
|
||||||
|
use crate::stream::{InputStream, OutputStream};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use serde::{Deserialize, Serialize};
|
use nu_source::Tag;
|
||||||
|
use nu_source::Text;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
use std::sync::{Arc, Mutex};
|
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)]
|
#[derive(Clone)]
|
||||||
pub struct CommandRegistry {
|
pub struct CommandRegistry {
|
||||||
registry: Arc<Mutex<IndexMap<String, Arc<Command>>>>,
|
registry: Arc<Mutex<IndexMap<String, Arc<Command>>>>,
|
||||||
|
@ -4,7 +4,6 @@ pub(crate) mod config;
|
|||||||
pub(crate) mod dict;
|
pub(crate) mod dict;
|
||||||
pub(crate) mod files;
|
pub(crate) mod files;
|
||||||
pub(crate) mod into;
|
pub(crate) mod into;
|
||||||
pub(crate) mod meta;
|
|
||||||
pub(crate) mod types;
|
pub(crate) mod types;
|
||||||
|
|
||||||
pub(crate) use base::{Primitive, Value};
|
pub(crate) use base::{Primitive, Value};
|
||||||
|
626
src/data/base.rs
626
src/data/base.rs
@ -3,19 +3,19 @@ mod property_get;
|
|||||||
pub(crate) mod shape;
|
pub(crate) mod shape;
|
||||||
|
|
||||||
use crate::context::CommandRegistry;
|
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::data::TaggedDictBuilder;
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::evaluate::{evaluate_baseline_expr, Scope};
|
use crate::evaluate::{evaluate_baseline_expr, Scope};
|
||||||
use crate::parser::hir::path::{ColumnPath, PathMember};
|
use crate::parser::hir::path::{ColumnPath, PathMember};
|
||||||
use crate::parser::{hir, Operator};
|
use crate::parser::{hir, Operator};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::Text;
|
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use chrono_humanize::Humanize;
|
use chrono_humanize::Humanize;
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
use nu_source::{AnchorLocation, PrettyDebug, SpannedItem, Tagged, TaggedItem, Text};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
@ -171,12 +171,12 @@ impl Primitive {
|
|||||||
&members
|
&members
|
||||||
.next()
|
.next()
|
||||||
.expect("BUG: column path with zero members")
|
.expect("BUG: column path with zero members")
|
||||||
.to_string(),
|
.display(),
|
||||||
);
|
);
|
||||||
|
|
||||||
for member in members {
|
for member in members {
|
||||||
f.push_str(".");
|
f.push_str(".");
|
||||||
f.push_str(&member.to_string())
|
f.push_str(&member.display())
|
||||||
}
|
}
|
||||||
|
|
||||||
f
|
f
|
||||||
@ -232,11 +232,11 @@ pub struct Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Block {
|
impl Block {
|
||||||
pub fn invoke(&self, value: &Tagged<Value>) -> Result<Tagged<Value>, ShellError> {
|
pub fn invoke(&self, value: &Value) -> Result<Value, ShellError> {
|
||||||
let scope = Scope::new(value.clone());
|
let scope = Scope::new(value.clone());
|
||||||
|
|
||||||
if self.expressions.len() == 0 {
|
if self.expressions.len() == 0 {
|
||||||
return Ok(Value::nothing().tagged(&self.tag));
|
return Ok(UntaggedValue::nothing().into_value(&self.tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut last = None;
|
let mut last = None;
|
||||||
@ -263,10 +263,10 @@ impl Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Serialize, Deserialize)]
|
||||||
pub enum Value {
|
pub enum UntaggedValue {
|
||||||
Primitive(Primitive),
|
Primitive(Primitive),
|
||||||
Row(crate::data::Dictionary),
|
Row(crate::data::Dictionary),
|
||||||
Table(Vec<Tagged<Value>>),
|
Table(Vec<Value>),
|
||||||
|
|
||||||
// Errors are a type of value too
|
// Errors are a type of value too
|
||||||
Error(ShellError),
|
Error(ShellError),
|
||||||
@ -274,191 +274,104 @@ pub enum Value {
|
|||||||
Block(Block),
|
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<UntaggedValue> 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 {
|
impl ShellTypeName for Value {
|
||||||
fn type_name(&self) -> &'static str {
|
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<UntaggedValue> for Number {
|
||||||
|
fn into(self) -> UntaggedValue {
|
||||||
match self {
|
match self {
|
||||||
Value::Primitive(p) => p.type_name(),
|
Number::Int(int) => UntaggedValue::int(int),
|
||||||
Value::Row(_) => "row",
|
Number::Decimal(decimal) => UntaggedValue::decimal(decimal),
|
||||||
Value::Table(_) => "table",
|
|
||||||
Value::Error(_) => "error",
|
|
||||||
Value::Block(_) => "block",
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<Value> for Number {
|
impl Into<UntaggedValue> for &Number {
|
||||||
fn into(self) -> Value {
|
fn into(self) -> UntaggedValue {
|
||||||
match self {
|
match self {
|
||||||
Number::Int(int) => Value::int(int),
|
Number::Int(int) => UntaggedValue::int(int.clone()),
|
||||||
Number::Decimal(decimal) => Value::decimal(decimal),
|
Number::Decimal(decimal) => UntaggedValue::decimal(decimal.clone()),
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<Value> for &Number {
|
|
||||||
fn into(self) -> Value {
|
|
||||||
match self {
|
|
||||||
Number::Int(int) => Value::int(int.clone()),
|
|
||||||
Number::Decimal(decimal) => Value::decimal(decimal.clone()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Tagged<Value> {
|
|
||||||
pub fn tagged_type_name(&self) -> Tagged<String> {
|
|
||||||
let name = self.type_name().to_string();
|
|
||||||
name.tagged(self.tag())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Tagged<&Value> {
|
|
||||||
pub fn tagged_type_name(&self) -> Tagged<String> {
|
|
||||||
let name = self.type_name().to_string();
|
|
||||||
name.tagged(self.tag())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::convert::TryFrom<&Tagged<Value>> for Block {
|
|
||||||
type Error = ShellError;
|
|
||||||
|
|
||||||
fn try_from(value: &Tagged<Value>) -> Result<Block, ShellError> {
|
|
||||||
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<Value>> for i64 {
|
|
||||||
type Error = ShellError;
|
|
||||||
|
|
||||||
fn try_from(value: &Tagged<Value>) -> Result<i64, ShellError> {
|
|
||||||
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<Value>> for String {
|
|
||||||
type Error = ShellError;
|
|
||||||
|
|
||||||
fn try_from(value: &Tagged<Value>) -> Result<String, ShellError> {
|
|
||||||
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<Value>> for Vec<u8> {
|
|
||||||
type Error = ShellError;
|
|
||||||
|
|
||||||
fn try_from(value: &Tagged<Value>) -> Result<Vec<u8>, 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<Value>> for &'a crate::data::Dictionary {
|
|
||||||
type Error = ShellError;
|
|
||||||
|
|
||||||
fn try_from(value: &'a Tagged<Value>) -> 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<Option<&Tagged<Value>>> for Switch {
|
|
||||||
type Error = ShellError;
|
|
||||||
|
|
||||||
fn try_from(value: Option<&Tagged<Value>>) -> Result<Switch, ShellError> {
|
|
||||||
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()),
|
|
||||||
)),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Value {
|
impl Value {
|
||||||
pub fn data_descriptors(&self) -> Vec<String> {
|
pub fn anchor(&self) -> Option<AnchorLocation> {
|
||||||
match self {
|
self.tag.anchor()
|
||||||
Value::Primitive(_) => vec![],
|
}
|
||||||
Value::Row(columns) => columns
|
|
||||||
.entries
|
pub fn anchor_name(&self) -> Option<String> {
|
||||||
.keys()
|
self.tag.anchor_name()
|
||||||
.into_iter()
|
}
|
||||||
.map(|x| x.to_string())
|
|
||||||
.collect(),
|
pub fn tag(&self) -> Tag {
|
||||||
Value::Block(_) => vec![],
|
self.tag.clone()
|
||||||
Value::Table(_) => vec![],
|
}
|
||||||
Value::Error(_) => vec![],
|
|
||||||
|
pub fn into_parts(self) -> (UntaggedValue, Tag) {
|
||||||
|
(self.value, self.tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn as_path(&self) -> Result<PathBuf, ShellError> {
|
||||||
|
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> {
|
pub fn tagged_type_name(&self) -> Tagged<String> {
|
||||||
match self {
|
let name = self.type_name().to_string();
|
||||||
p @ Value::Primitive(_) => MaybeOwned::Borrowed(p),
|
name.tagged(self.tag.clone())
|
||||||
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<Column>) -> 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(crate) fn compare(
|
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<Block, ShellError> {
|
||||||
|
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<i64, ShellError> {
|
||||||
|
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<String, ShellError> {
|
||||||
|
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<u8> {
|
||||||
|
type Error = ShellError;
|
||||||
|
|
||||||
|
fn try_from(value: &Value) -> Result<Vec<u8>, 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<Option<&Value>> for Switch {
|
||||||
|
type Error = ShellError;
|
||||||
|
|
||||||
|
fn try_from(value: Option<&Value>) -> Result<Switch, ShellError> {
|
||||||
|
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<Tag>) -> 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<Tag>) -> Value {
|
||||||
|
Value {
|
||||||
|
value: self,
|
||||||
|
tag: tag.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn data_descriptors(&self) -> Vec<String> {
|
||||||
|
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<Column>) -> 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 {
|
pub(crate) fn is_true(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Value::Primitive(Primitive::Boolean(true)) => true,
|
UntaggedValue::Primitive(Primitive::Boolean(true)) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -504,90 +581,97 @@ impl Value {
|
|||||||
|
|
||||||
pub(crate) fn is_none(&self) -> bool {
|
pub(crate) fn is_none(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Value::Primitive(Primitive::Nothing) => true,
|
UntaggedValue::Primitive(Primitive::Nothing) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_error(&self) -> bool {
|
pub(crate) fn is_error(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Value::Error(_err) => true,
|
UntaggedValue::Error(_err) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn expect_error(&self) -> ShellError {
|
pub(crate) fn expect_error(&self) -> ShellError {
|
||||||
match self {
|
match self {
|
||||||
Value::Error(err) => err.clone(),
|
UntaggedValue::Error(err) => err.clone(),
|
||||||
_ => panic!("Don't call expect_error without first calling is_error"),
|
_ => 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)]
|
#[allow(unused)]
|
||||||
pub fn row(entries: IndexMap<String, Tagged<Value>>) -> Value {
|
pub fn row(entries: IndexMap<String, Value>) -> UntaggedValue {
|
||||||
Value::Row(entries.into())
|
UntaggedValue::Row(entries.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn table(list: &Vec<Tagged<Value>>) -> Value {
|
pub fn table(list: &Vec<Value>) -> UntaggedValue {
|
||||||
Value::Table(list.to_vec())
|
UntaggedValue::Table(list.to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn string(s: impl Into<String>) -> Value {
|
pub fn string(s: impl Into<String>) -> UntaggedValue {
|
||||||
Value::Primitive(Primitive::String(s.into()))
|
UntaggedValue::Primitive(Primitive::String(s.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn column_path(s: Vec<impl Into<PathMember>>) -> Value {
|
pub fn column_path(s: Vec<impl Into<PathMember>>) -> UntaggedValue {
|
||||||
Value::Primitive(Primitive::ColumnPath(ColumnPath::new(
|
UntaggedValue::Primitive(Primitive::ColumnPath(ColumnPath::new(
|
||||||
s.into_iter().map(|p| p.into()).collect(),
|
s.into_iter().map(|p| p.into()).collect(),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn int(i: impl Into<BigInt>) -> Value {
|
pub fn int(i: impl Into<BigInt>) -> UntaggedValue {
|
||||||
Value::Primitive(Primitive::Int(i.into()))
|
UntaggedValue::Primitive(Primitive::Int(i.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pattern(s: impl Into<String>) -> Value {
|
pub fn pattern(s: impl Into<String>) -> UntaggedValue {
|
||||||
Value::Primitive(Primitive::String(s.into()))
|
UntaggedValue::Primitive(Primitive::String(s.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn path(s: impl Into<PathBuf>) -> Value {
|
pub fn path(s: impl Into<PathBuf>) -> UntaggedValue {
|
||||||
Value::Primitive(Primitive::Path(s.into()))
|
UntaggedValue::Primitive(Primitive::Path(s.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bytes(s: impl Into<u64>) -> Value {
|
pub fn bytes(s: impl Into<u64>) -> UntaggedValue {
|
||||||
Value::Primitive(Primitive::Bytes(s.into()))
|
UntaggedValue::Primitive(Primitive::Bytes(s.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decimal(s: impl Into<BigDecimal>) -> Value {
|
pub fn decimal(s: impl Into<BigDecimal>) -> UntaggedValue {
|
||||||
Value::Primitive(Primitive::Decimal(s.into()))
|
UntaggedValue::Primitive(Primitive::Decimal(s.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn binary(binary: Vec<u8>) -> Value {
|
pub fn binary(binary: Vec<u8>) -> UntaggedValue {
|
||||||
Value::Primitive(Primitive::Binary(binary))
|
UntaggedValue::Primitive(Primitive::Binary(binary))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn number(s: impl Into<Number>) -> Value {
|
pub fn number(s: impl Into<Number>) -> UntaggedValue {
|
||||||
let num = s.into();
|
let num = s.into();
|
||||||
|
|
||||||
match num {
|
match num {
|
||||||
Number::Int(int) => Value::int(int),
|
Number::Int(int) => UntaggedValue::int(int),
|
||||||
Number::Decimal(decimal) => Value::decimal(decimal),
|
Number::Decimal(decimal) => UntaggedValue::decimal(decimal),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn boolean(s: impl Into<bool>) -> Value {
|
pub fn boolean(s: impl Into<bool>) -> UntaggedValue {
|
||||||
Value::Primitive(Primitive::Boolean(s.into()))
|
UntaggedValue::Primitive(Primitive::Boolean(s.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn duration(secs: u64) -> Value {
|
pub fn duration(secs: u64) -> UntaggedValue {
|
||||||
Value::Primitive(Primitive::Duration(secs))
|
UntaggedValue::Primitive(Primitive::Duration(secs))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn system_date(s: SystemTime) -> Value {
|
pub fn system_date(s: SystemTime) -> UntaggedValue {
|
||||||
Value::Primitive(Primitive::Date(s.into()))
|
UntaggedValue::Primitive(Primitive::Date(s.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn date_from_str(s: Tagged<&str>) -> Result<Value, ShellError> {
|
pub fn date_from_str(s: Tagged<&str>) -> Result<UntaggedValue, ShellError> {
|
||||||
let date = DateTime::parse_from_rfc3339(s.item).map_err(|err| {
|
let date = DateTime::parse_from_rfc3339(s.item).map_err(|err| {
|
||||||
ShellError::labeled_error(
|
ShellError::labeled_error(
|
||||||
&format!("Date parse error: {}", err),
|
&format!("Date parse error: {}", err),
|
||||||
@ -598,43 +682,30 @@ impl Value {
|
|||||||
|
|
||||||
let date = date.with_timezone(&chrono::offset::Utc);
|
let date = date.with_timezone(&chrono::offset::Utc);
|
||||||
|
|
||||||
Ok(Value::Primitive(Primitive::Date(date)))
|
Ok(UntaggedValue::Primitive(Primitive::Date(date)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn nothing() -> Value {
|
pub fn nothing() -> UntaggedValue {
|
||||||
Value::Primitive(Primitive::Nothing)
|
UntaggedValue::Primitive(Primitive::Nothing)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tagged<Value> {
|
pub(crate) fn select_fields(obj: &Value, fields: &[String], tag: impl Into<Tag>) -> Value {
|
||||||
pub(crate) fn as_path(&self) -> Result<PathBuf, ShellError> {
|
|
||||||
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<Tag>) -> Tagged<Value> {
|
|
||||||
let mut out = TaggedDictBuilder::new(tag);
|
let mut out = TaggedDictBuilder::new(tag);
|
||||||
|
|
||||||
let descs = obj.data_descriptors();
|
let descs = obj.data_descriptors();
|
||||||
|
|
||||||
for field in fields {
|
for field in fields {
|
||||||
match descs.iter().find(|d| *d == field) {
|
match descs.iter().find(|d| *d == field) {
|
||||||
None => out.insert(field, Value::nothing()),
|
None => out.insert_untagged(field, UntaggedValue::nothing()),
|
||||||
Some(desc) => out.insert(desc.clone(), obj.get_data(desc).borrow().clone()),
|
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<Tag>) -> Tagged<Value> {
|
pub(crate) fn reject_fields(obj: &Value, fields: &[String], tag: impl Into<Tag>) -> Value {
|
||||||
let mut out = TaggedDictBuilder::new(tag);
|
let mut out = TaggedDictBuilder::new(tag);
|
||||||
|
|
||||||
let descs = obj.data_descriptors();
|
let descs = obj.data_descriptors();
|
||||||
@ -643,11 +714,11 @@ pub(crate) fn reject_fields(obj: &Value, fields: &[String], tag: impl Into<Tag>)
|
|||||||
if fields.iter().any(|field| *field == desc) {
|
if fields.iter().any(|field| *field == desc) {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} 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 {
|
enum CompareValues {
|
||||||
@ -680,8 +751,10 @@ fn coerce_compare(
|
|||||||
left: &Value,
|
left: &Value,
|
||||||
right: &Value,
|
right: &Value,
|
||||||
) -> Result<CompareValues, (&'static str, &'static str)> {
|
) -> Result<CompareValues, (&'static str, &'static str)> {
|
||||||
match (left, right) {
|
match (&left.value, &right.value) {
|
||||||
(Value::Primitive(left), Value::Primitive(right)) => coerce_compare_primitive(left, right),
|
(UntaggedValue::Primitive(left), UntaggedValue::Primitive(right)) => {
|
||||||
|
coerce_compare_primitive(left, right)
|
||||||
|
}
|
||||||
|
|
||||||
_ => Err((left.type_name(), right.type_name())),
|
_ => Err((left.type_name(), right.type_name())),
|
||||||
}
|
}
|
||||||
@ -719,28 +792,29 @@ fn coerce_compare_primitive(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::data::meta::*;
|
use super::UntaggedValue;
|
||||||
use crate::parser::hir::path::PathMember;
|
use crate::parser::hir::path::PathMember;
|
||||||
use crate::ColumnPath as ColumnPathValue;
|
use crate::ColumnPath as ColumnPathValue;
|
||||||
use crate::ShellError;
|
use crate::ShellError;
|
||||||
use crate::Value;
|
use crate::Value;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
use nu_source::*;
|
||||||
use num_bigint::BigInt;
|
use num_bigint::BigInt;
|
||||||
|
|
||||||
fn string(input: impl Into<String>) -> Tagged<Value> {
|
fn string(input: impl Into<String>) -> Value {
|
||||||
Value::string(input.into()).tagged_unknown()
|
UntaggedValue::string(input.into()).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn int(input: impl Into<BigInt>) -> Tagged<Value> {
|
fn int(input: impl Into<BigInt>) -> Value {
|
||||||
Value::int(input.into()).tagged_unknown()
|
UntaggedValue::int(input.into()).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn row(entries: IndexMap<String, Tagged<Value>>) -> Tagged<Value> {
|
fn row(entries: IndexMap<String, Value>) -> Value {
|
||||||
Value::row(entries).tagged_unknown()
|
UntaggedValue::row(entries).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn table(list: &Vec<Tagged<Value>>) -> Tagged<Value> {
|
fn table(list: &Vec<Value>) -> Value {
|
||||||
Value::table(list).tagged_unknown()
|
UntaggedValue::table(list).into_untagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error_callback(
|
fn error_callback(
|
||||||
@ -749,7 +823,7 @@ mod tests {
|
|||||||
move |(_obj_source, _column_path_tried, _err)| ShellError::unimplemented(reason)
|
move |(_obj_source, _column_path_tried, _err)| ShellError::unimplemented(reason)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn column_path(paths: &Vec<Tagged<Value>>) -> Tagged<ColumnPathValue> {
|
fn column_path(paths: &Vec<Value>) -> Tagged<ColumnPathValue> {
|
||||||
table(&paths.iter().cloned().collect())
|
table(&paths.iter().cloned().collect())
|
||||||
.as_column_path()
|
.as_column_path()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -757,9 +831,10 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn gets_matching_field_from_a_row() {
|
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")])
|
"amigos".into() => table(&vec![string("andres"),string("jonathan"),string("yehuda")])
|
||||||
});
|
})
|
||||||
|
.into_untagged_value();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
row.get_data_by_key("amigos".spanned_unknown()).unwrap(),
|
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 (version, tag) = string("0.4.0").into_parts();
|
||||||
|
|
||||||
let value = Value::row(indexmap! {
|
let value = UntaggedValue::row(indexmap! {
|
||||||
"package".into() =>
|
"package".into() =>
|
||||||
row(indexmap! {
|
row(indexmap! {
|
||||||
"name".into() => string("nu"),
|
"name".into() => string("nu"),
|
||||||
@ -787,7 +862,7 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*value
|
*value
|
||||||
.tagged(tag)
|
.into_value(tag)
|
||||||
.get_data_by_column_path(&field_path, Box::new(error_callback("package.version")))
|
.get_data_by_column_path(&field_path, Box::new(error_callback("package.version")))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
version
|
version
|
||||||
@ -800,7 +875,7 @@ mod tests {
|
|||||||
|
|
||||||
let (_, tag) = string("Andrés N. Robalino").into_parts();
|
let (_, tag) = string("Andrés N. Robalino").into_parts();
|
||||||
|
|
||||||
let value = Value::row(indexmap! {
|
let value = UntaggedValue::row(indexmap! {
|
||||||
"package".into() => row(indexmap! {
|
"package".into() => row(indexmap! {
|
||||||
"name".into() => string("nu"),
|
"name".into() => string("nu"),
|
||||||
"version".into() => string("0.4.0"),
|
"version".into() => string("0.4.0"),
|
||||||
@ -814,7 +889,7 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
value
|
value
|
||||||
.tagged(tag)
|
.into_value(tag)
|
||||||
.get_data_by_column_path(
|
.get_data_by_column_path(
|
||||||
&field_path,
|
&field_path,
|
||||||
Box::new(error_callback("package.authors.name"))
|
Box::new(error_callback("package.authors.name"))
|
||||||
@ -834,7 +909,7 @@ mod tests {
|
|||||||
|
|
||||||
let (_, tag) = string("Andrés N. Robalino").into_parts();
|
let (_, tag) = string("Andrés N. Robalino").into_parts();
|
||||||
|
|
||||||
let value = Value::row(indexmap! {
|
let value = UntaggedValue::row(indexmap! {
|
||||||
"package".into() => row(indexmap! {
|
"package".into() => row(indexmap! {
|
||||||
"name".into() => string("nu"),
|
"name".into() => string("nu"),
|
||||||
"version".into() => string("0.4.0"),
|
"version".into() => string("0.4.0"),
|
||||||
@ -848,10 +923,10 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*value
|
*value
|
||||||
.tagged(tag)
|
.into_value(tag)
|
||||||
.get_data_by_column_path(&field_path, Box::new(error_callback("package.authors.0")))
|
.get_data_by_column_path(&field_path, Box::new(error_callback("package.authors.0")))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
Value::row(indexmap! {
|
UntaggedValue::row(indexmap! {
|
||||||
"name".into() => string("Andrés N. Robalino")
|
"name".into() => string("Andrés N. Robalino")
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -863,7 +938,7 @@ mod tests {
|
|||||||
|
|
||||||
let (_, tag) = string("Andrés N. Robalino").into_parts();
|
let (_, tag) = string("Andrés N. Robalino").into_parts();
|
||||||
|
|
||||||
let value = Value::row(indexmap! {
|
let value = UntaggedValue::row(indexmap! {
|
||||||
"package".into() => row(indexmap! {
|
"package".into() => row(indexmap! {
|
||||||
"name".into() => string("nu"),
|
"name".into() => string("nu"),
|
||||||
"version".into() => string("0.4.0"),
|
"version".into() => string("0.4.0"),
|
||||||
@ -877,13 +952,13 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*value
|
*value
|
||||||
.tagged(tag)
|
.into_value(tag)
|
||||||
.get_data_by_column_path(
|
.get_data_by_column_path(
|
||||||
&field_path,
|
&field_path,
|
||||||
Box::new(error_callback("package.authors.\"0\""))
|
Box::new(error_callback("package.authors.\"0\""))
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
Value::row(indexmap! {
|
UntaggedValue::row(indexmap! {
|
||||||
"name".into() => string("Andrés N. Robalino")
|
"name".into() => string("Andrés N. Robalino")
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -893,7 +968,7 @@ mod tests {
|
|||||||
fn replaces_matching_field_from_a_row() {
|
fn replaces_matching_field_from_a_row() {
|
||||||
let field_path = column_path(&vec![string("amigos")]);
|
let field_path = column_path(&vec![string("amigos")]);
|
||||||
|
|
||||||
let sample = Value::row(indexmap! {
|
let sample = UntaggedValue::row(indexmap! {
|
||||||
"amigos".into() => table(&vec![
|
"amigos".into() => table(&vec![
|
||||||
string("andres"),
|
string("andres"),
|
||||||
string("jonathan"),
|
string("jonathan"),
|
||||||
@ -901,10 +976,10 @@ mod tests {
|
|||||||
]),
|
]),
|
||||||
});
|
});
|
||||||
|
|
||||||
let (replacement, tag) = string("jonas").into_parts();
|
let replacement = string("jonas");
|
||||||
|
|
||||||
let actual = sample
|
let actual = sample
|
||||||
.tagged(tag)
|
.into_untagged_value()
|
||||||
.replace_data_at_column_path(&field_path, replacement)
|
.replace_data_at_column_path(&field_path, replacement)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -919,7 +994,7 @@ mod tests {
|
|||||||
string("los.3.caballeros"),
|
string("los.3.caballeros"),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let sample = Value::row(indexmap! {
|
let sample = UntaggedValue::row(indexmap! {
|
||||||
"package".into() => row(indexmap! {
|
"package".into() => row(indexmap! {
|
||||||
"authors".into() => row(indexmap! {
|
"authors".into() => row(indexmap! {
|
||||||
"los.3.mosqueteros".into() => table(&vec![string("andres::yehuda::jonathan")]),
|
"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
|
let actual = sample
|
||||||
.tagged(tag.clone())
|
.into_value(tag.clone())
|
||||||
.replace_data_at_column_path(&field_path, replacement.clone())
|
.replace_data_at_column_path(&field_path, replacement.clone())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
actual,
|
actual,
|
||||||
Value::row(indexmap! {
|
UntaggedValue::row(indexmap! {
|
||||||
"package".into() => row(indexmap! {
|
"package".into() => row(indexmap! {
|
||||||
"authors".into() => row(indexmap! {
|
"authors".into() => row(indexmap! {
|
||||||
"los.3.mosqueteros".into() => table(&vec![string("andres::yehuda::jonathan")]),
|
"los.3.mosqueteros".into() => table(&vec![string("andres::yehuda::jonathan")]),
|
||||||
"los.3.amigos".into() => table(&vec![string("andres::yehuda::jonathan")]),
|
"los.3.amigos".into() => table(&vec![string("andres::yehuda::jonathan")]),
|
||||||
"los.3.caballeros".into() => replacement.tagged(&tag)})})})
|
"los.3.caballeros".into() => replacement.clone()})})})
|
||||||
.tagged(tag)
|
.into_value(tag)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
@ -955,7 +1031,7 @@ mod tests {
|
|||||||
string("nu.version.arepa"),
|
string("nu.version.arepa"),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let sample = Value::row(indexmap! {
|
let sample = UntaggedValue::row(indexmap! {
|
||||||
"shell_policy".into() => row(indexmap! {
|
"shell_policy".into() => row(indexmap! {
|
||||||
"releases".into() => table(&vec![
|
"releases".into() => table(&vec![
|
||||||
row(indexmap! {
|
row(indexmap! {
|
||||||
@ -977,24 +1053,24 @@ mod tests {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
let (replacement, tag) = row(indexmap! {
|
let replacement = row(indexmap! {
|
||||||
"code".into() => string("0.5.0"),
|
"code".into() => string("0.5.0"),
|
||||||
"tag_line".into() => string("CABALLEROS")
|
"tag_line".into() => string("CABALLEROS")
|
||||||
})
|
});
|
||||||
.into_parts();
|
let tag = replacement.tag.clone();
|
||||||
|
|
||||||
let actual = sample
|
let actual = sample
|
||||||
.tagged(tag.clone())
|
.into_value(tag.clone())
|
||||||
.replace_data_at_column_path(&field_path, replacement.clone())
|
.replace_data_at_column_path(&field_path, replacement.clone())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
actual,
|
actual,
|
||||||
Value::row(indexmap! {
|
UntaggedValue::row(indexmap! {
|
||||||
"shell_policy".into() => row(indexmap! {
|
"shell_policy".into() => row(indexmap! {
|
||||||
"releases".into() => table(&vec![
|
"releases".into() => table(&vec![
|
||||||
row(indexmap! {
|
row(indexmap! {
|
||||||
"nu.version.arepa".into() => replacement.tagged(&tag)
|
"nu.version.arepa".into() => replacement
|
||||||
}),
|
}),
|
||||||
row(indexmap! {
|
row(indexmap! {
|
||||||
"nu.version.taco".into() => row(indexmap! {
|
"nu.version.taco".into() => row(indexmap! {
|
||||||
@ -1008,7 +1084,7 @@ mod tests {
|
|||||||
})
|
})
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
}).tagged(&tag)
|
}).into_value(&tag)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,54 +1,6 @@
|
|||||||
use crate::data::base::Primitive;
|
use crate::data::base::Primitive;
|
||||||
use crate::prelude::*;
|
use crate::traits::PrettyType;
|
||||||
use crate::traits::DebugDocBuilder as b;
|
use nu_source::{b, DebugDocBuilder, PrettyDebug};
|
||||||
use pretty::{BoxAllocator, DocAllocator};
|
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
impl FormatDebug for Tagged<Value> {
|
|
||||||
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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PrettyType for Primitive {
|
impl PrettyType for Primitive {
|
||||||
fn pretty_type(&self) -> DebugDocBuilder {
|
fn pretty_type(&self) -> DebugDocBuilder {
|
||||||
@ -72,14 +24,14 @@ impl PrettyType for Primitive {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PrettyDebug for Primitive {
|
impl PrettyDebug for Primitive {
|
||||||
fn pretty_debug(&self) -> DebugDocBuilder {
|
fn pretty(&self) -> DebugDocBuilder {
|
||||||
match self {
|
match self {
|
||||||
Primitive::Nothing => b::primitive("nothing"),
|
Primitive::Nothing => b::primitive("nothing"),
|
||||||
Primitive::Int(int) => prim(format_args!("{}", int)),
|
Primitive::Int(int) => prim(format_args!("{}", int)),
|
||||||
Primitive::Decimal(decimal) => prim(format_args!("{}", decimal)),
|
Primitive::Decimal(decimal) => prim(format_args!("{}", decimal)),
|
||||||
Primitive::Bytes(bytes) => primitive_doc(bytes, "bytesize"),
|
Primitive::Bytes(bytes) => primitive_doc(bytes, "bytesize"),
|
||||||
Primitive::String(string) => prim(string),
|
Primitive::String(string) => prim(string),
|
||||||
Primitive::ColumnPath(path) => path.pretty_debug(),
|
Primitive::ColumnPath(path) => path.pretty(),
|
||||||
Primitive::Pattern(pattern) => primitive_doc(pattern, "pattern"),
|
Primitive::Pattern(pattern) => primitive_doc(pattern, "pattern"),
|
||||||
Primitive::Boolean(boolean) => match boolean {
|
Primitive::Boolean(boolean) => match boolean {
|
||||||
true => b::primitive("$yes"),
|
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 {
|
fn prim(name: impl std::fmt::Debug) -> DebugDocBuilder {
|
||||||
b::primitive(format!("{:?}", name))
|
b::primitive(format!("{:?}", name))
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,17 @@
|
|||||||
use crate::errors::ExpectedRange;
|
use crate::errors::ExpectedRange;
|
||||||
use crate::parser::hir::path::{PathMember, RawPathMember};
|
use crate::parser::hir::path::{PathMember, UnspannedPathMember};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::ColumnPath;
|
use crate::ColumnPath;
|
||||||
use crate::SpannedTypeName;
|
use crate::SpannedTypeName;
|
||||||
|
use nu_source::{Spanned, SpannedItem, Tagged};
|
||||||
|
|
||||||
impl Tagged<Value> {
|
impl Value {
|
||||||
pub(crate) fn get_data_by_member(
|
pub(crate) fn get_data_by_member(&self, name: &PathMember) -> Result<Value, ShellError> {
|
||||||
&self,
|
match &self.value {
|
||||||
name: &PathMember,
|
|
||||||
) -> Result<Tagged<Value>, ShellError> {
|
|
||||||
match &self.item {
|
|
||||||
// If the value is a row, the member is a column name
|
// 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
|
// 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))
|
.get_data_by_key(string[..].spanned(name.span))
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
ShellError::missing_property(
|
ShellError::missing_property(
|
||||||
@ -23,62 +21,65 @@ impl Tagged<Value> {
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
// If the member is a number, it's an error
|
// 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),
|
"row".spanned(self.tag.span),
|
||||||
name.span,
|
name.span,
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
|
|
||||||
// If the value is a table
|
// If the value is a table
|
||||||
Value::Table(l) => match &name.item {
|
UntaggedValue::Table(l) => {
|
||||||
// If the member is a string, map over the member
|
match &name.unspanned {
|
||||||
RawPathMember::String(string) => {
|
// If the member is a string, map over the member
|
||||||
let mut out = vec![];
|
UnspannedPathMember::String(string) => {
|
||||||
|
let mut out = vec![];
|
||||||
|
|
||||||
for item in l {
|
for item in l {
|
||||||
match item {
|
match item {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Row(o),
|
value: UntaggedValue::Row(o),
|
||||||
..
|
..
|
||||||
} => match o.get_data_by_key(string[..].spanned(name.span)) {
|
} => match o.get_data_by_key(string[..].spanned(name.span)) {
|
||||||
Some(v) => out.push(v),
|
Some(v) => out.push(v),
|
||||||
None => {}
|
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 {
|
match self.get_data_by_index(index.spanned(self.tag.span)) {
|
||||||
Err(ShellError::missing_property(
|
Some(v) => Ok(v.clone()),
|
||||||
"table".spanned(self.tag.span),
|
None => Err(ShellError::range_error(
|
||||||
string.spanned(name.span),
|
0..(l.len()),
|
||||||
))
|
&int.spanned(name.span),
|
||||||
} else {
|
"indexing",
|
||||||
Ok(Value::Table(out).tagged(Tag::new(self.anchor(), name.span)))
|
)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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(
|
other => Err(ShellError::type_error(
|
||||||
"row or table",
|
"row or table",
|
||||||
other.spanned(self.tag.span).spanned_type_name(),
|
other.type_name().spanned(self.tag.span),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,7 +88,7 @@ impl Tagged<Value> {
|
|||||||
&self,
|
&self,
|
||||||
path: &ColumnPath,
|
path: &ColumnPath,
|
||||||
callback: Box<dyn FnOnce((&Value, &PathMember, ShellError)) -> ShellError>,
|
callback: Box<dyn FnOnce((&Value, &PathMember, ShellError)) -> ShellError>,
|
||||||
) -> Result<Tagged<Value>, ShellError> {
|
) -> Result<Value, ShellError> {
|
||||||
let mut current = self.clone();
|
let mut current = self.clone();
|
||||||
|
|
||||||
for p in path.iter() {
|
for p in path.iter() {
|
||||||
@ -102,19 +103,20 @@ impl Tagged<Value> {
|
|||||||
Ok(current)
|
Ok(current)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_data_at_path(&self, path: &str, new_value: Value) -> Option<Tagged<Value>> {
|
pub fn insert_data_at_path(&self, path: &str, new_value: Value) -> Option<Value> {
|
||||||
let mut new_obj = self.clone();
|
let mut new_obj = self.clone();
|
||||||
|
|
||||||
let split_path: Vec<_> = path.split(".").collect();
|
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;
|
let mut current = o;
|
||||||
|
|
||||||
if split_path.len() == 1 {
|
if split_path.len() == 1 {
|
||||||
// Special case for inserting at the top level
|
// Special case for inserting at the top level
|
||||||
current
|
current.entries.insert(
|
||||||
.entries
|
path.to_string(),
|
||||||
.insert(path.to_string(), new_value.tagged(&self.tag));
|
new_value.value.clone().into_value(&self.tag),
|
||||||
|
);
|
||||||
return Some(new_obj);
|
return Some(new_obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,11 +124,11 @@ impl Tagged<Value> {
|
|||||||
match current.entries.get_mut(split_path[idx]) {
|
match current.entries.get_mut(split_path[idx]) {
|
||||||
Some(next) => {
|
Some(next) => {
|
||||||
if idx == (split_path.len() - 2) {
|
if idx == (split_path.len() - 2) {
|
||||||
match &mut next.item {
|
match &mut next.value {
|
||||||
Value::Row(o) => {
|
UntaggedValue::Row(o) => {
|
||||||
o.entries.insert(
|
o.entries.insert(
|
||||||
split_path[idx + 1].to_string(),
|
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<Value> {
|
|||||||
|
|
||||||
return Some(new_obj.clone());
|
return Some(new_obj.clone());
|
||||||
} else {
|
} else {
|
||||||
match next.item {
|
match next.value {
|
||||||
Value::Row(ref mut o) => {
|
UntaggedValue::Row(ref mut o) => {
|
||||||
current = o;
|
current = o;
|
||||||
}
|
}
|
||||||
_ => return None,
|
_ => return None,
|
||||||
@ -153,28 +155,28 @@ impl Tagged<Value> {
|
|||||||
pub fn insert_data_at_member(
|
pub fn insert_data_at_member(
|
||||||
&mut self,
|
&mut self,
|
||||||
member: &PathMember,
|
member: &PathMember,
|
||||||
new_value: Tagged<Value>,
|
new_value: Value,
|
||||||
) -> Result<(), ShellError> {
|
) -> Result<(), ShellError> {
|
||||||
match &mut self.item {
|
match &mut self.value {
|
||||||
Value::Row(dict) => match &member.item {
|
UntaggedValue::Row(dict) => match &member.unspanned {
|
||||||
RawPathMember::String(key) => Ok({
|
UnspannedPathMember::String(key) => Ok({
|
||||||
dict.insert_data_at_key(key, new_value);
|
dict.insert_data_at_key(key, new_value);
|
||||||
}),
|
}),
|
||||||
RawPathMember::Int(_) => Err(ShellError::type_error(
|
UnspannedPathMember::Int(_) => Err(ShellError::type_error(
|
||||||
"column name",
|
"column name",
|
||||||
"integer".spanned(member.span),
|
"integer".spanned(member.span),
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
Value::Table(array) => match &member.item {
|
UntaggedValue::Table(array) => match &member.unspanned {
|
||||||
RawPathMember::String(_) => Err(ShellError::type_error(
|
UnspannedPathMember::String(_) => Err(ShellError::type_error(
|
||||||
"list index",
|
"list index",
|
||||||
"string".spanned(member.span),
|
"string".spanned(member.span),
|
||||||
)),
|
)),
|
||||||
RawPathMember::Int(int) => Ok({
|
UnspannedPathMember::Int(int) => Ok({
|
||||||
let int = int.to_usize().ok_or_else(|| {
|
let int = int.to_usize().ok_or_else(|| {
|
||||||
ShellError::range_error(
|
ShellError::range_error(
|
||||||
ExpectedRange::Usize,
|
ExpectedRange::Usize,
|
||||||
&"bigger number".tagged(member.span),
|
&"bigger number".spanned(member.span),
|
||||||
"inserting into a list",
|
"inserting into a list",
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
@ -182,12 +184,12 @@ impl Tagged<Value> {
|
|||||||
insert_data_at_index(array, int.tagged(member.span), new_value.clone())?;
|
insert_data_at_index(array, int.tagged(member.span), new_value.clone())?;
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
other => match &member.item {
|
other => match &member.unspanned {
|
||||||
RawPathMember::String(_) => Err(ShellError::type_error(
|
UnspannedPathMember::String(_) => Err(ShellError::type_error(
|
||||||
"row",
|
"row",
|
||||||
other.type_name().spanned(self.span()),
|
other.type_name().spanned(self.span()),
|
||||||
)),
|
)),
|
||||||
RawPathMember::Int(_) => Err(ShellError::type_error(
|
UnspannedPathMember::Int(_) => Err(ShellError::type_error(
|
||||||
"table",
|
"table",
|
||||||
other.type_name().spanned(self.span()),
|
other.type_name().spanned(self.span()),
|
||||||
)),
|
)),
|
||||||
@ -198,25 +200,22 @@ impl Tagged<Value> {
|
|||||||
pub fn insert_data_at_column_path(
|
pub fn insert_data_at_column_path(
|
||||||
&self,
|
&self,
|
||||||
split_path: &ColumnPath,
|
split_path: &ColumnPath,
|
||||||
new_value: Tagged<Value>,
|
new_value: Value,
|
||||||
) -> Result<Tagged<Value>, ShellError> {
|
) -> Result<Value, ShellError> {
|
||||||
let (last, front) = split_path.split_last();
|
let (last, front) = split_path.split_last();
|
||||||
let mut original = self.clone();
|
let mut original = self.clone();
|
||||||
|
|
||||||
let mut current: &mut Tagged<Value> = &mut original;
|
let mut current: &mut Value = &mut original;
|
||||||
|
|
||||||
for member in front {
|
for member in front {
|
||||||
let type_name = current.spanned_type_name();
|
let type_name = current.spanned_type_name();
|
||||||
|
|
||||||
current = current
|
current = current.get_mut_data_by_member(&member).ok_or_else(|| {
|
||||||
.item
|
ShellError::missing_property(
|
||||||
.get_mut_data_by_member(&member)
|
member.plain_string(std::usize::MAX).spanned(member.span),
|
||||||
.ok_or_else(|| {
|
type_name,
|
||||||
ShellError::missing_property(
|
)
|
||||||
member.plain_string(std::usize::MAX).spanned(member.span),
|
})?
|
||||||
type_name,
|
|
||||||
)
|
|
||||||
})?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
current.insert_data_at_member(&last, new_value)?;
|
current.insert_data_at_member(&last, new_value)?;
|
||||||
@ -228,16 +227,16 @@ impl Tagged<Value> {
|
|||||||
&self,
|
&self,
|
||||||
split_path: &ColumnPath,
|
split_path: &ColumnPath,
|
||||||
replaced_value: Value,
|
replaced_value: Value,
|
||||||
) -> Option<Tagged<Value>> {
|
) -> Option<Value> {
|
||||||
let mut new_obj: Tagged<Value> = self.clone();
|
let mut new_obj: Value = self.clone();
|
||||||
let mut current = &mut new_obj;
|
let mut current = &mut new_obj;
|
||||||
let split_path = split_path.members();
|
let split_path = split_path.members();
|
||||||
|
|
||||||
for idx in 0..split_path.len() {
|
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) => {
|
Some(next) => {
|
||||||
if idx == (split_path.len() - 1) {
|
if idx == (split_path.len() - 1) {
|
||||||
*next = replaced_value.tagged(&self.tag);
|
*next = replaced_value.value.into_value(&self.tag);
|
||||||
return Some(new_obj);
|
return Some(new_obj);
|
||||||
} else {
|
} else {
|
||||||
current = next;
|
current = next;
|
||||||
@ -253,8 +252,8 @@ impl Tagged<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_column_path(&self) -> Result<Tagged<ColumnPath>, ShellError> {
|
pub fn as_column_path(&self) -> Result<Tagged<ColumnPath>, ShellError> {
|
||||||
match &self.item {
|
match &self.value {
|
||||||
Value::Table(table) => {
|
UntaggedValue::Table(table) => {
|
||||||
let mut out: Vec<PathMember> = vec![];
|
let mut out: Vec<PathMember> = vec![];
|
||||||
|
|
||||||
for item in table {
|
for item in table {
|
||||||
@ -264,7 +263,7 @@ impl Tagged<Value> {
|
|||||||
Ok(ColumnPath::new(out).tagged(&self.tag))
|
Ok(ColumnPath::new(out).tagged(&self.tag))
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Primitive(Primitive::ColumnPath(path)) => {
|
UntaggedValue::Primitive(Primitive::ColumnPath(path)) => {
|
||||||
Ok(path.clone().tagged(self.tag.clone()))
|
Ok(path.clone().tagged(self.tag.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,8 +275,8 @@ impl Tagged<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_path_member(&self) -> Result<PathMember, ShellError> {
|
pub fn as_path_member(&self) -> Result<PathMember, ShellError> {
|
||||||
match &self.item {
|
match &self.value {
|
||||||
Value::Primitive(primitive) => match primitive {
|
UntaggedValue::Primitive(primitive) => match primitive {
|
||||||
Primitive::Int(int) => Ok(PathMember::int(int.clone(), self.tag.span)),
|
Primitive::Int(int) => Ok(PathMember::int(int.clone(), self.tag.span)),
|
||||||
Primitive::String(string) => Ok(PathMember::string(string, self.tag.span)),
|
Primitive::String(string) => Ok(PathMember::string(string, self.tag.span)),
|
||||||
other => Err(ShellError::type_error(
|
other => Err(ShellError::type_error(
|
||||||
@ -293,13 +292,13 @@ impl Tagged<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_string(&self) -> Result<String, ShellError> {
|
pub fn as_string(&self) -> Result<String, ShellError> {
|
||||||
match &self.item {
|
match &self.value {
|
||||||
Value::Primitive(Primitive::String(s)) => Ok(s.clone()),
|
UntaggedValue::Primitive(Primitive::String(s)) => Ok(s.clone()),
|
||||||
Value::Primitive(Primitive::Boolean(x)) => Ok(format!("{}", x)),
|
UntaggedValue::Primitive(Primitive::Boolean(x)) => Ok(format!("{}", x)),
|
||||||
Value::Primitive(Primitive::Decimal(x)) => Ok(format!("{}", x)),
|
UntaggedValue::Primitive(Primitive::Decimal(x)) => Ok(format!("{}", x)),
|
||||||
Value::Primitive(Primitive::Int(x)) => Ok(format!("{}", x)),
|
UntaggedValue::Primitive(Primitive::Int(x)) => Ok(format!("{}", x)),
|
||||||
Value::Primitive(Primitive::Bytes(x)) => Ok(format!("{}", x)),
|
UntaggedValue::Primitive(Primitive::Bytes(x)) => Ok(format!("{}", x)),
|
||||||
Value::Primitive(Primitive::Path(x)) => Ok(format!("{}", x.display())),
|
UntaggedValue::Primitive(Primitive::Path(x)) => Ok(format!("{}", x.display())),
|
||||||
// TODO: this should definitely be more general with better errors
|
// TODO: this should definitely be more general with better errors
|
||||||
other => Err(ShellError::labeled_error(
|
other => Err(ShellError::labeled_error(
|
||||||
"Expected string",
|
"Expected string",
|
||||||
@ -311,14 +310,14 @@ impl Tagged<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn insert_data_at_index(
|
fn insert_data_at_index(
|
||||||
list: &mut Vec<Tagged<Value>>,
|
list: &mut Vec<Value>,
|
||||||
index: Tagged<usize>,
|
index: Tagged<usize>,
|
||||||
new_value: Tagged<Value>,
|
new_value: Value,
|
||||||
) -> Result<(), ShellError> {
|
) -> Result<(), ShellError> {
|
||||||
if list.len() >= index.item {
|
if list.len() >= index.item {
|
||||||
Err(ShellError::range_error(
|
Err(ShellError::range_error(
|
||||||
0..(list.len()),
|
0..(list.len()),
|
||||||
&format_args!("{}", index.item).tagged(index.tag.clone()),
|
&format_args!("{}", index.item).spanned(index.tag.span),
|
||||||
"insert at index",
|
"insert at index",
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
@ -328,41 +327,51 @@ fn insert_data_at_index(
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Value {
|
impl Value {
|
||||||
pub(crate) fn get_data_by_index(&self, idx: Spanned<usize>) -> Option<Tagged<Value>> {
|
pub fn get_data(&self, desc: &String) -> MaybeOwned<'_, Value> {
|
||||||
match self {
|
match &self.value {
|
||||||
Value::Table(value_set) => {
|
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<usize>) -> Option<Value> {
|
||||||
|
match &self.value {
|
||||||
|
UntaggedValue::Table(value_set) => {
|
||||||
let value = value_set.get(idx.item)?;
|
let value = value_set.get(idx.item)?;
|
||||||
Some(
|
Some(
|
||||||
value
|
value
|
||||||
.item
|
.value
|
||||||
.clone()
|
.clone()
|
||||||
.tagged(Tag::new(value.anchor(), idx.span)),
|
.into_value(Tag::new(value.anchor(), idx.span)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_data_by_key(&self, name: Spanned<&str>) -> Option<Tagged<Value>> {
|
pub(crate) fn get_data_by_key(&self, name: Spanned<&str>) -> Option<Value> {
|
||||||
match self {
|
match &self.value {
|
||||||
Value::Row(o) => o.get_data_by_key(name),
|
UntaggedValue::Row(o) => o.get_data_by_key(name),
|
||||||
Value::Table(l) => {
|
UntaggedValue::Table(l) => {
|
||||||
let mut out = vec![];
|
let mut out = vec![];
|
||||||
for item in l {
|
for item in l {
|
||||||
match item {
|
match item {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Row(o),
|
value: UntaggedValue::Row(o),
|
||||||
..
|
..
|
||||||
} => match o.get_data_by_key(name) {
|
} => match o.get_data_by_key(name) {
|
||||||
Some(v) => out.push(v),
|
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 {
|
if out.len() > 0 {
|
||||||
Some(Value::Table(out).tagged(name.span))
|
Some(UntaggedValue::Table(out).into_value(name.span))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -371,21 +380,18 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_mut_data_by_member(
|
pub(crate) fn get_mut_data_by_member(&mut self, name: &PathMember) -> Option<&mut Value> {
|
||||||
&mut self,
|
match &mut self.value {
|
||||||
name: &PathMember,
|
UntaggedValue::Row(o) => match &name.unspanned {
|
||||||
) -> Option<&mut Tagged<Value>> {
|
UnspannedPathMember::String(string) => o.get_mut_data_by_key(&string),
|
||||||
match self {
|
UnspannedPathMember::Int(_) => None,
|
||||||
Value::Row(o) => match &name.item {
|
|
||||||
RawPathMember::String(string) => o.get_mut_data_by_key(&string),
|
|
||||||
RawPathMember::Int(_) => None,
|
|
||||||
},
|
},
|
||||||
Value::Table(l) => match &name.item {
|
UntaggedValue::Table(l) => match &name.unspanned {
|
||||||
RawPathMember::String(string) => {
|
UnspannedPathMember::String(string) => {
|
||||||
for item in l {
|
for item in l {
|
||||||
match item {
|
match item {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Row(o),
|
value: UntaggedValue::Row(o),
|
||||||
..
|
..
|
||||||
} => match o.get_mut_data_by_key(&string) {
|
} => match o.get_mut_data_by_key(&string) {
|
||||||
Some(v) => return Some(v),
|
Some(v) => return Some(v),
|
||||||
@ -396,7 +402,7 @@ impl Value {
|
|||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
RawPathMember::Int(int) => {
|
UnspannedPathMember::Int(int) => {
|
||||||
let index = int.to_usize()?;
|
let index = int.to_usize()?;
|
||||||
l.get_mut(index)
|
l.get_mut(index)
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
use crate::data::base::{Block, ColumnPath};
|
use crate::data::base::{Block, ColumnPath};
|
||||||
use crate::data::dict::Dictionary;
|
use crate::data::dict::Dictionary;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::traits::{DebugDocBuilder as b, PrettyDebug};
|
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use chrono_humanize::Humanize;
|
use chrono_humanize::Humanize;
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
use nu_source::DebugDoc;
|
||||||
|
use nu_source::{b, PrettyDebug};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
@ -76,7 +77,7 @@ impl TypeShape {
|
|||||||
|
|
||||||
for (key, value) in dictionary.entries.iter() {
|
for (key, value) in dictionary.entries.iter() {
|
||||||
let column = Column::String(key.clone());
|
let column = Column::String(key.clone());
|
||||||
map.insert(column, TypeShape::from_value(&value.item));
|
map.insert(column, TypeShape::from_value(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeShape::Row(map)
|
TypeShape::Row(map)
|
||||||
@ -92,19 +93,19 @@ impl TypeShape {
|
|||||||
TypeShape::Table(vec)
|
TypeShape::Table(vec)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_value(value: &Value) -> TypeShape {
|
pub fn from_value<'a>(value: impl Into<&'a UntaggedValue>) -> TypeShape {
|
||||||
match value {
|
match value.into() {
|
||||||
Value::Primitive(p) => TypeShape::from_primitive(p),
|
UntaggedValue::Primitive(p) => TypeShape::from_primitive(p),
|
||||||
Value::Row(row) => TypeShape::from_dictionary(row),
|
UntaggedValue::Row(row) => TypeShape::from_dictionary(row),
|
||||||
Value::Table(table) => TypeShape::from_table(table.iter().map(|i| &i.item)),
|
UntaggedValue::Table(table) => TypeShape::from_table(table.iter()),
|
||||||
Value::Error(_) => TypeShape::Error,
|
UntaggedValue::Error(_) => TypeShape::Error,
|
||||||
Value::Block(_) => TypeShape::Block,
|
UntaggedValue::Block(_) => TypeShape::Block,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrettyDebug for TypeShape {
|
impl PrettyDebug for TypeShape {
|
||||||
fn pretty_debug(&self) -> DebugDocBuilder {
|
fn pretty(&self) -> DebugDocBuilder {
|
||||||
match self {
|
match self {
|
||||||
TypeShape::Nothing => ty("nothing"),
|
TypeShape::Nothing => ty("nothing"),
|
||||||
TypeShape::Int => ty("integer"),
|
TypeShape::Int => ty("integer"),
|
||||||
@ -128,7 +129,7 @@ impl PrettyDebug for TypeShape {
|
|||||||
(b::key(match key {
|
(b::key(match key {
|
||||||
Column::String(string) => string.clone(),
|
Column::String(string) => string.clone(),
|
||||||
Column::Value => "<value>".to_string(),
|
Column::Value => "<value>".to_string(),
|
||||||
}) + b::delimit("(", ty.pretty_debug(), ")").as_kind())
|
}) + b::delimit("(", ty.pretty(), ")").as_kind())
|
||||||
.nest()
|
.nest()
|
||||||
}),
|
}),
|
||||||
b::space(),
|
b::space(),
|
||||||
@ -186,11 +187,11 @@ struct DebugEntry<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PrettyDebug for DebugEntry<'a> {
|
impl<'a> PrettyDebug for DebugEntry<'a> {
|
||||||
fn pretty_debug(&self) -> DebugDocBuilder {
|
fn pretty(&self) -> DebugDocBuilder {
|
||||||
(b::key(match self.key {
|
(b::key(match self.key {
|
||||||
Column::String(string) => string.clone(),
|
Column::String(string) => string.clone(),
|
||||||
Column::Value => format!("<value>"),
|
Column::Value => format!("<value>"),
|
||||||
}) + 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() {
|
for (key, value) in dictionary.entries.iter() {
|
||||||
let column = Column::String(key.clone());
|
let column = Column::String(key.clone());
|
||||||
map.insert(column, InlineShape::from_value(&value.item));
|
map.insert(column, InlineShape::from_value(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
InlineShape::Row(map)
|
InlineShape::Row(map)
|
||||||
@ -272,22 +273,23 @@ impl InlineShape {
|
|||||||
InlineShape::Table(vec)
|
InlineShape::Table(vec)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_value(value: &Value) -> InlineShape {
|
pub fn from_value<'a>(value: impl Into<&'a UntaggedValue>) -> InlineShape {
|
||||||
match value {
|
match value.into() {
|
||||||
Value::Primitive(p) => InlineShape::from_primitive(p),
|
UntaggedValue::Primitive(p) => InlineShape::from_primitive(p),
|
||||||
Value::Row(row) => InlineShape::from_dictionary(row),
|
UntaggedValue::Row(row) => InlineShape::from_dictionary(row),
|
||||||
Value::Table(table) => InlineShape::from_table(table.iter().map(|i| &i.item)),
|
UntaggedValue::Table(table) => InlineShape::from_table(table.iter()),
|
||||||
Value::Error(_) => InlineShape::Error,
|
UntaggedValue::Error(_) => InlineShape::Error,
|
||||||
Value::Block(_) => InlineShape::Block,
|
UntaggedValue::Block(_) => InlineShape::Block,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn format_for_column(self, column: impl Into<Column>) -> FormatInlineShape {
|
#[allow(unused)]
|
||||||
// FormatInlineShape {
|
pub fn format_for_column(self, column: impl Into<Column>) -> FormatInlineShape {
|
||||||
// shape: self,
|
FormatInlineShape {
|
||||||
// column: Some(column.into()),
|
shape: self,
|
||||||
// }
|
column: Some(column.into()),
|
||||||
// }
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn format(self) -> FormatInlineShape {
|
pub fn format(self) -> FormatInlineShape {
|
||||||
FormatInlineShape {
|
FormatInlineShape {
|
||||||
@ -298,7 +300,7 @@ impl InlineShape {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PrettyDebug for FormatInlineShape {
|
impl PrettyDebug for FormatInlineShape {
|
||||||
fn pretty_debug(&self) -> DebugDocBuilder {
|
fn pretty(&self) -> DebugDocBuilder {
|
||||||
let column = &self.column;
|
let column = &self.column;
|
||||||
|
|
||||||
match &self.shape {
|
match &self.shape {
|
||||||
@ -323,10 +325,9 @@ impl PrettyDebug for FormatInlineShape {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
InlineShape::String(string) => b::primitive(format!("{}", string)),
|
InlineShape::String(string) => b::primitive(format!("{}", string)),
|
||||||
InlineShape::ColumnPath(path) => b::intersperse(
|
InlineShape::ColumnPath(path) => {
|
||||||
path.iter().map(|member| member.pretty_debug()),
|
b::intersperse(path.iter().map(|member| member.pretty()), b::keyword("."))
|
||||||
b::keyword("."),
|
}
|
||||||
),
|
|
||||||
InlineShape::Pattern(pattern) => b::primitive(pattern),
|
InlineShape::Pattern(pattern) => b::primitive(pattern),
|
||||||
InlineShape::Boolean(boolean) => b::primitive(match (boolean, column) {
|
InlineShape::Boolean(boolean) => b::primitive(match (boolean, column) {
|
||||||
(true, None) => format!("Yes"),
|
(true, None) => format!("Yes"),
|
||||||
@ -485,15 +486,15 @@ impl Value {
|
|||||||
|
|
||||||
impl Shape {
|
impl Shape {
|
||||||
pub fn for_value(value: &Value) -> Shape {
|
pub fn for_value(value: &Value) -> Shape {
|
||||||
match value {
|
match &value.value {
|
||||||
Value::Primitive(p) => Shape::Primitive(p.type_name()),
|
UntaggedValue::Primitive(p) => Shape::Primitive(p.type_name()),
|
||||||
Value::Row(row) => Shape::for_dict(row),
|
UntaggedValue::Row(row) => Shape::for_dict(row),
|
||||||
Value::Table(table) => Shape::Table {
|
UntaggedValue::Table(table) => Shape::Table {
|
||||||
from: 0,
|
from: 0,
|
||||||
to: table.len(),
|
to: table.len(),
|
||||||
},
|
},
|
||||||
Value::Error(error) => Shape::Error(error.clone()),
|
UntaggedValue::Error(error) => Shape::Error(error.clone()),
|
||||||
Value::Block(block) => Shape::Block(block.clone()),
|
UntaggedValue::Block(block) => Shape::Block(block.clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -558,7 +559,7 @@ impl Shape {
|
|||||||
.expect("Writing into a Vec can't fail");
|
.expect("Writing into a Vec can't fail");
|
||||||
let string = String::from_utf8_lossy(&out);
|
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]);
|
.or_insert_with(|| vec![row]);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_values(&self) -> Vec<Tagged<Value>> {
|
pub fn to_values(&self) -> Vec<Value> {
|
||||||
if self.shapes.len() == 1 {
|
if self.shapes.len() == 1 {
|
||||||
let shape = self.shapes.keys().nth(0).unwrap();
|
let shape = self.shapes.keys().nth(0).unwrap();
|
||||||
|
|
||||||
vec![dict! {
|
vec![dict! {
|
||||||
"type" => shape.to_value(),
|
"type" => shape.to_value(),
|
||||||
"rows" => Value::string("all")
|
"rows" => UntaggedValue::string("all")
|
||||||
}]
|
}]
|
||||||
} else {
|
} else {
|
||||||
self.shapes
|
self.shapes
|
||||||
@ -598,7 +599,7 @@ impl Shapes {
|
|||||||
|
|
||||||
dict! {
|
dict! {
|
||||||
"type" => shape.to_value(),
|
"type" => shape.to_value(),
|
||||||
"rows" => Value::string(format!("[ {} ]", rows))
|
"rows" => UntaggedValue::string(format!("[ {} ]", rows))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -4,43 +4,43 @@ use crate::parser::registry::{NamedType, PositionalType, Signature};
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
pub(crate) fn command_dict(command: Arc<Command>, tag: impl Into<Tag>) -> Tagged<Value> {
|
pub(crate) fn command_dict(command: Arc<Command>, tag: impl Into<Tag>) -> Value {
|
||||||
let tag = tag.into();
|
let tag = tag.into();
|
||||||
|
|
||||||
let mut cmd_dict = TaggedDictBuilder::new(&tag);
|
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",
|
"type",
|
||||||
Value::string(match command.deref() {
|
UntaggedValue::string(match command.deref() {
|
||||||
Command::WholeStream(_) => "Command",
|
Command::WholeStream(_) => "Command",
|
||||||
Command::PerItem(_) => "Filter",
|
Command::PerItem(_) => "Filter",
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
cmd_dict.insert_tagged("signature", signature_dict(command.signature(), tag));
|
cmd_dict.insert_value("signature", signature_dict(command.signature(), tag));
|
||||||
cmd_dict.insert("usage", Value::string(command.usage()));
|
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<Tag>) -> Tagged<Value> {
|
fn for_spec(name: &str, ty: &str, required: bool, tag: impl Into<Tag>) -> Value {
|
||||||
let tag = tag.into();
|
let tag = tag.into();
|
||||||
|
|
||||||
let mut spec = TaggedDictBuilder::new(tag);
|
let mut spec = TaggedDictBuilder::new(tag);
|
||||||
|
|
||||||
spec.insert("name", Value::string(name));
|
spec.insert_untagged("name", UntaggedValue::string(name));
|
||||||
spec.insert("type", Value::string(ty));
|
spec.insert_untagged("type", UntaggedValue::string(ty));
|
||||||
spec.insert(
|
spec.insert_untagged(
|
||||||
"required",
|
"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<Tag>) -> Tagged<Value> {
|
fn signature_dict(signature: Signature, tag: impl Into<Tag>) -> Value {
|
||||||
let tag = tag.into();
|
let tag = tag.into();
|
||||||
let mut sig = TaggedListBuilder::new(&tag);
|
let mut sig = TaggedListBuilder::new(&tag);
|
||||||
|
|
||||||
@ -50,21 +50,21 @@ fn signature_dict(signature: Signature, tag: impl Into<Tag>) -> Tagged<Value> {
|
|||||||
PositionalType::Optional(_, _) => false,
|
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 {
|
if let Some(_) = signature.rest_positional {
|
||||||
let is_required = false;
|
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() {
|
for (name, ty) in signature.named.iter() {
|
||||||
match ty.0 {
|
match ty.0 {
|
||||||
NamedType::Mandatory(_) => sig.insert_tagged(for_spec(name, "flag", true, &tag)),
|
NamedType::Mandatory(_) => sig.push_value(for_spec(name, "flag", true, &tag)),
|
||||||
NamedType::Optional(_) => sig.insert_tagged(for_spec(name, "flag", false, &tag)),
|
NamedType::Optional(_) => sig.push_value(for_spec(name, "flag", false, &tag)),
|
||||||
NamedType::Switch => sig.insert_tagged(for_spec(name, "switch", false, &tag)),
|
NamedType::Switch => sig.push_value(for_spec(name, "switch", false, &tag)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sig.into_tagged_value()
|
sig.into_value()
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ use std::path::{Path, PathBuf};
|
|||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
struct Config {
|
struct Config {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
extra: IndexMap<String, Tagged<Value>>,
|
extra: IndexMap<String, Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const APP_INFO: AppInfo = AppInfo {
|
pub const APP_INFO: AppInfo = AppInfo {
|
||||||
@ -61,7 +61,7 @@ pub fn app_path(app_data_type: AppDataType, display: &str) -> Result<PathBuf, Sh
|
|||||||
pub fn read(
|
pub fn read(
|
||||||
tag: impl Into<Tag>,
|
tag: impl Into<Tag>,
|
||||||
at: &Option<PathBuf>,
|
at: &Option<PathBuf>,
|
||||||
) -> Result<IndexMap<String, Tagged<Value>>, ShellError> {
|
) -> Result<IndexMap<String, Value>, ShellError> {
|
||||||
let filename = default_path()?;
|
let filename = default_path()?;
|
||||||
|
|
||||||
let filename = match at {
|
let filename = match at {
|
||||||
@ -94,8 +94,8 @@ pub fn read(
|
|||||||
|
|
||||||
let value = convert_toml_value_to_nu_value(&parsed, tag);
|
let value = convert_toml_value_to_nu_value(&parsed, tag);
|
||||||
let tag = value.tag();
|
let tag = value.tag();
|
||||||
match value.item {
|
match value.value {
|
||||||
Value::Row(Dictionary { entries }) => Ok(entries),
|
UntaggedValue::Row(Dictionary { entries }) => Ok(entries),
|
||||||
other => Err(ShellError::type_error(
|
other => Err(ShellError::type_error(
|
||||||
"Dictionary",
|
"Dictionary",
|
||||||
other.type_name().spanned(tag.span),
|
other.type_name().spanned(tag.span),
|
||||||
@ -103,14 +103,11 @@ pub fn read(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn config(tag: impl Into<Tag>) -> Result<IndexMap<String, Tagged<Value>>, ShellError> {
|
pub(crate) fn config(tag: impl Into<Tag>) -> Result<IndexMap<String, Value>, ShellError> {
|
||||||
read(tag, &None)
|
read(tag, &None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(
|
pub fn write(config: &IndexMap<String, Value>, at: &Option<PathBuf>) -> Result<(), ShellError> {
|
||||||
config: &IndexMap<String, Tagged<Value>>,
|
|
||||||
at: &Option<PathBuf>,
|
|
||||||
) -> Result<(), ShellError> {
|
|
||||||
let filename = &mut default_path()?;
|
let filename = &mut default_path()?;
|
||||||
let filename = match at {
|
let filename = match at {
|
||||||
None => filename,
|
None => filename,
|
||||||
@ -121,8 +118,9 @@ pub fn write(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let contents =
|
let contents = value_to_toml_value(
|
||||||
value_to_toml_value(&Value::Row(Dictionary::new(config.clone())).tagged_unknown())?;
|
&UntaggedValue::Row(Dictionary::new(config.clone())).into_untagged_value(),
|
||||||
|
)?;
|
||||||
|
|
||||||
let contents = toml::to_string(&contents)?;
|
let contents = toml::to_string(&contents)?;
|
||||||
|
|
||||||
|
117
src/data/dict.rs
117
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::prelude::*;
|
||||||
use crate::traits::{DebugDocBuilder as b, PrettyDebug};
|
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use getset::Getters;
|
use getset::Getters;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
use nu_source::Spanned;
|
||||||
|
use nu_source::{b, PrettyDebug};
|
||||||
use pretty::{BoxAllocator, DocAllocator};
|
use pretty::{BoxAllocator, DocAllocator};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::cmp::{Ordering, PartialOrd};
|
use std::cmp::{Ordering, PartialOrd};
|
||||||
@ -11,41 +12,23 @@ use std::cmp::{Ordering, PartialOrd};
|
|||||||
#[derive(Debug, Default, Eq, PartialEq, Serialize, Deserialize, Clone, Getters, new)]
|
#[derive(Debug, Default, Eq, PartialEq, Serialize, Deserialize, Clone, Getters, new)]
|
||||||
pub struct Dictionary {
|
pub struct Dictionary {
|
||||||
#[get = "pub"]
|
#[get = "pub"]
|
||||||
pub entries: IndexMap<String, Tagged<Value>>,
|
pub entries: IndexMap<String, Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, new)]
|
#[derive(Debug, new)]
|
||||||
struct DebugEntry<'a> {
|
struct DebugEntry<'a> {
|
||||||
key: &'a str,
|
key: &'a str,
|
||||||
value: &'a Tagged<Value>,
|
value: &'a Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PrettyDebug for DebugEntry<'a> {
|
impl<'a> PrettyDebug for DebugEntry<'a> {
|
||||||
fn pretty_debug(&self) -> DebugDocBuilder {
|
fn pretty(&self) -> DebugDocBuilder {
|
||||||
(b::key(self.key.to_string()) + b::equals() + self.value.item.pretty_debug().as_value())
|
(b::key(self.key.to_string()) + b::equals() + self.value.pretty().as_value()).group()
|
||||||
.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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrettyDebug for Dictionary {
|
impl PrettyDebug for Dictionary {
|
||||||
fn pretty_debug(&self) -> DebugDocBuilder {
|
fn pretty(&self) -> DebugDocBuilder {
|
||||||
BoxAllocator
|
BoxAllocator
|
||||||
.text("(")
|
.text("(")
|
||||||
.append(
|
.append(
|
||||||
@ -73,15 +56,15 @@ impl PartialOrd for Dictionary {
|
|||||||
return this.partial_cmp(&that);
|
return this.partial_cmp(&that);
|
||||||
}
|
}
|
||||||
|
|
||||||
let this: 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().map(|v| v.item()).collect();
|
let that: Vec<&Value> = self.entries.values().collect();
|
||||||
|
|
||||||
this.partial_cmp(&that)
|
this.partial_cmp(&that)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<IndexMap<String, Tagged<Value>>> for Dictionary {
|
impl From<IndexMap<String, Value>> for Dictionary {
|
||||||
fn from(input: IndexMap<String, Tagged<Value>>) -> Dictionary {
|
fn from(input: IndexMap<String, Value>) -> Dictionary {
|
||||||
let mut out = IndexMap::default();
|
let mut out = IndexMap::default();
|
||||||
|
|
||||||
for (key, value) in input {
|
for (key, value) in input {
|
||||||
@ -101,8 +84,8 @@ impl Ord for Dictionary {
|
|||||||
return this.cmp(&that);
|
return this.cmp(&that);
|
||||||
}
|
}
|
||||||
|
|
||||||
let this: 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().map(|v| v.item()).collect();
|
let that: Vec<&Value> = self.entries.values().collect();
|
||||||
|
|
||||||
this.cmp(&that)
|
this.cmp(&that)
|
||||||
}
|
}
|
||||||
@ -116,8 +99,8 @@ impl PartialOrd<Value> for Dictionary {
|
|||||||
|
|
||||||
impl PartialEq<Value> for Dictionary {
|
impl PartialEq<Value> for Dictionary {
|
||||||
fn eq(&self, other: &Value) -> bool {
|
fn eq(&self, other: &Value) -> bool {
|
||||||
match other {
|
match &other.value {
|
||||||
Value::Row(d) => self == d,
|
UntaggedValue::Row(d) => self == d,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,7 +110,9 @@ impl Dictionary {
|
|||||||
pub fn get_data(&self, desc: &String) -> MaybeOwned<'_, Value> {
|
pub fn get_data(&self, desc: &String) -> MaybeOwned<'_, Value> {
|
||||||
match self.entries.get(desc) {
|
match self.entries.get(desc) {
|
||||||
Some(v) => MaybeOwned::Borrowed(v),
|
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()
|
self.entries.keys()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_data_by_key(&self, name: Spanned<&str>) -> Option<Tagged<Value>> {
|
pub(crate) fn get_data_by_key(&self, name: Spanned<&str>) -> Option<Value> {
|
||||||
let result = self
|
let result = self
|
||||||
.entries
|
.entries
|
||||||
.iter()
|
.iter()
|
||||||
@ -144,13 +129,13 @@ impl Dictionary {
|
|||||||
|
|
||||||
Some(
|
Some(
|
||||||
result
|
result
|
||||||
.item
|
.value
|
||||||
.clone()
|
.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<Value>> {
|
pub(crate) fn get_mut_data_by_key(&mut self, name: &str) -> Option<&mut Value> {
|
||||||
match self
|
match self
|
||||||
.entries
|
.entries
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
@ -161,7 +146,7 @@ impl Dictionary {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn insert_data_at_key(&mut self, name: &str, value: Tagged<Value>) {
|
pub(crate) fn insert_data_at_key(&mut self, name: &str, value: Value) {
|
||||||
self.entries.insert(name.to_string(), value);
|
self.entries.insert(name.to_string(), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,7 +154,7 @@ impl Dictionary {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TaggedListBuilder {
|
pub struct TaggedListBuilder {
|
||||||
tag: Tag,
|
tag: Tag,
|
||||||
pub list: Vec<Tagged<Value>>,
|
pub list: Vec<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TaggedListBuilder {
|
impl TaggedListBuilder {
|
||||||
@ -180,29 +165,33 @@ impl TaggedListBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push(&mut self, value: impl Into<Value>) {
|
pub fn push_value(&mut self, value: impl Into<Value>) {
|
||||||
self.list.push(value.into().tagged(&self.tag));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert_tagged(&mut self, value: impl Into<Tagged<Value>>) {
|
|
||||||
self.list.push(value.into());
|
self.list.push(value.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_tagged_value(self) -> Tagged<Value> {
|
pub fn push_untagged(&mut self, value: impl Into<UntaggedValue>) {
|
||||||
Value::Table(self.list).tagged(self.tag)
|
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<TaggedListBuilder> for Tagged<Value> {
|
impl From<TaggedListBuilder> for Value {
|
||||||
fn from(input: TaggedListBuilder) -> Tagged<Value> {
|
fn from(input: TaggedListBuilder) -> Value {
|
||||||
input.into_tagged_value()
|
input.into_value()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TaggedDictBuilder {
|
pub struct TaggedDictBuilder {
|
||||||
tag: Tag,
|
tag: Tag,
|
||||||
dict: IndexMap<String, Tagged<Value>>,
|
dict: IndexMap<String, Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TaggedDictBuilder {
|
impl TaggedDictBuilder {
|
||||||
@ -213,10 +202,10 @@ impl TaggedDictBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(tag: impl Into<Tag>, block: impl FnOnce(&mut TaggedDictBuilder)) -> Tagged<Value> {
|
pub fn build(tag: impl Into<Tag>, block: impl FnOnce(&mut TaggedDictBuilder)) -> Value {
|
||||||
let mut builder = TaggedDictBuilder::new(tag);
|
let mut builder = TaggedDictBuilder::new(tag);
|
||||||
block(&mut builder);
|
block(&mut builder);
|
||||||
builder.into_tagged_value()
|
builder.into_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_capacity(tag: impl Into<Tag>, n: usize) -> TaggedDictBuilder {
|
pub fn with_capacity(tag: impl Into<Tag>, n: usize) -> TaggedDictBuilder {
|
||||||
@ -226,20 +215,22 @@ impl TaggedDictBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, key: impl Into<String>, value: impl Into<Value>) {
|
pub fn insert_untagged(&mut self, key: impl Into<String>, value: impl Into<UntaggedValue>) {
|
||||||
self.dict.insert(key.into(), value.into().tagged(&self.tag));
|
self.dict
|
||||||
|
.insert(key.into(), value.into().into_value(&self.tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_tagged(&mut self, key: impl Into<String>, value: impl Into<Tagged<Value>>) {
|
pub fn insert_value(&mut self, key: impl Into<String>, value: impl Into<Value>) {
|
||||||
self.dict.insert(key.into(), value.into());
|
self.dict.insert(key.into(), value.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_tagged_value(self) -> Tagged<Value> {
|
pub fn into_value(self) -> Value {
|
||||||
self.into_tagged_dict().map(Value::Row)
|
let tag = self.tag.clone();
|
||||||
|
self.into_untagged_value().into_value(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_tagged_dict(self) -> Tagged<Dictionary> {
|
pub fn into_untagged_value(self) -> UntaggedValue {
|
||||||
Dictionary { entries: self.dict }.tagged(self.tag)
|
UntaggedValue::Row(Dictionary { entries: self.dict })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
@ -247,8 +238,8 @@ impl TaggedDictBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<TaggedDictBuilder> for Tagged<Value> {
|
impl From<TaggedDictBuilder> for Value {
|
||||||
fn from(input: TaggedDictBuilder) -> Tagged<Value> {
|
fn from(input: TaggedDictBuilder) -> Value {
|
||||||
input.into_tagged_value()
|
input.into_value()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,9 +14,9 @@ pub(crate) fn dir_entry_dict(
|
|||||||
metadata: &std::fs::Metadata,
|
metadata: &std::fs::Metadata,
|
||||||
tag: impl Into<Tag>,
|
tag: impl Into<Tag>,
|
||||||
full: bool,
|
full: bool,
|
||||||
) -> Result<Tagged<Value>, ShellError> {
|
) -> Result<Value, ShellError> {
|
||||||
let mut dict = TaggedDictBuilder::new(tag);
|
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() {
|
let kind = if metadata.is_dir() {
|
||||||
FileType::Directory
|
FileType::Directory
|
||||||
@ -26,38 +26,41 @@ pub(crate) fn dir_entry_dict(
|
|||||||
FileType::Symlink
|
FileType::Symlink
|
||||||
};
|
};
|
||||||
|
|
||||||
dict.insert("type", Value::string(format!("{:?}", kind)));
|
dict.insert_untagged("type", UntaggedValue::string(format!("{:?}", kind)));
|
||||||
|
|
||||||
if full {
|
if full {
|
||||||
dict.insert(
|
dict.insert_untagged(
|
||||||
"readonly",
|
"readonly",
|
||||||
Value::boolean(metadata.permissions().readonly()),
|
UntaggedValue::boolean(metadata.permissions().readonly()),
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
use std::os::unix::fs::PermissionsExt;
|
use std::os::unix::fs::PermissionsExt;
|
||||||
let mode = metadata.permissions().mode();
|
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() {
|
match metadata.created() {
|
||||||
Ok(c) => dict.insert("created", Value::system_date(c)),
|
Ok(c) => dict.insert_untagged("created", UntaggedValue::system_date(c)),
|
||||||
Err(_) => {}
|
Err(_) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
match metadata.accessed() {
|
match metadata.accessed() {
|
||||||
Ok(a) => dict.insert("accessed", Value::system_date(a)),
|
Ok(a) => dict.insert_untagged("accessed", UntaggedValue::system_date(a)),
|
||||||
Err(_) => {}
|
Err(_) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
match metadata.modified() {
|
match metadata.modified() {
|
||||||
Ok(m) => dict.insert("modified", Value::system_date(m)),
|
Ok(m) => dict.insert_untagged("modified", UntaggedValue::system_date(m)),
|
||||||
Err(_) => {}
|
Err(_) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(dict.into_tagged_value())
|
Ok(dict.into_value())
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,13 @@
|
|||||||
use crate::data::{Primitive, Value};
|
use crate::data::base::{Primitive, UntaggedValue};
|
||||||
use crate::prelude::*;
|
|
||||||
|
|
||||||
impl From<Primitive> for Value {
|
impl From<Primitive> for UntaggedValue {
|
||||||
fn from(input: Primitive) -> Value {
|
fn from(input: Primitive) -> UntaggedValue {
|
||||||
Value::Primitive(input)
|
UntaggedValue::Primitive(input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<String> for Value {
|
impl From<String> for UntaggedValue {
|
||||||
fn from(input: String) -> Value {
|
fn from(input: String) -> UntaggedValue {
|
||||||
Value::Primitive(Primitive::String(input))
|
UntaggedValue::Primitive(Primitive::String(input))
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Into<Value>> Tagged<T> {
|
|
||||||
pub fn into_tagged_value(self) -> Tagged<Value> {
|
|
||||||
let value_tag = self.tag();
|
|
||||||
let value = self.item.into();
|
|
||||||
value.tagged(value_tag)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,27 +3,27 @@ use crate::prelude::*;
|
|||||||
use itertools::join;
|
use itertools::join;
|
||||||
use sysinfo::ProcessExt;
|
use sysinfo::ProcessExt;
|
||||||
|
|
||||||
pub(crate) fn process_dict(proc: &sysinfo::Process, tag: impl Into<Tag>) -> Tagged<Value> {
|
pub(crate) fn process_dict(proc: &sysinfo::Process, tag: impl Into<Tag>) -> Value {
|
||||||
let mut dict = TaggedDictBuilder::new(tag);
|
let mut dict = TaggedDictBuilder::new(tag);
|
||||||
|
|
||||||
let cmd = proc.cmd();
|
let cmd = proc.cmd();
|
||||||
|
|
||||||
let cmd_value = if cmd.len() == 0 {
|
let cmd_value = if cmd.len() == 0 {
|
||||||
Value::nothing()
|
UntaggedValue::nothing()
|
||||||
} else {
|
} else {
|
||||||
Value::string(join(cmd, ""))
|
UntaggedValue::string(join(cmd, ""))
|
||||||
};
|
};
|
||||||
|
|
||||||
dict.insert("pid", Value::int(proc.pid() as i64));
|
dict.insert("pid", UntaggedValue::int(proc.pid() as i64));
|
||||||
dict.insert("status", Value::string(proc.status().to_string()));
|
dict.insert("status", UntaggedValue::string(proc.status().to_string()));
|
||||||
dict.insert("cpu", Value::number(proc.cpu_usage()));
|
dict.insert("cpu", UntaggedValue::number(proc.cpu_usage()));
|
||||||
|
|
||||||
match cmd_value {
|
match cmd_value {
|
||||||
Value::Primitive(Primitive::Nothing) => {
|
UntaggedValue::Primitive(Primitive::Nothing) => {
|
||||||
dict.insert("name", Value::string(proc.name()));
|
dict.insert("name", UntaggedValue::string(proc.name()));
|
||||||
}
|
}
|
||||||
_ => dict.insert("name", cmd_value),
|
_ => dict.insert("name", cmd_value),
|
||||||
}
|
}
|
||||||
|
|
||||||
dict.into_tagged_value()
|
dict.into_value()
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
use nu_source::Tagged;
|
||||||
|
|
||||||
pub trait ExtractType: Sized {
|
pub trait ExtractType: Sized {
|
||||||
fn extract(value: &Tagged<Value>) -> Result<Self, ShellError>;
|
fn extract(value: &Value) -> Result<Self, ShellError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ExtractType> ExtractType for Tagged<T> {
|
impl<T: ExtractType> ExtractType for Tagged<T> {
|
||||||
fn extract(value: &Tagged<Value>) -> Result<Tagged<T>, ShellError> {
|
fn extract(value: &Value) -> Result<Tagged<T>, ShellError> {
|
||||||
let name = std::any::type_name::<T>();
|
let name = std::any::type_name::<T>();
|
||||||
trace!("<Tagged> Extracting {:?} for Tagged<{}>", value, name);
|
trace!("<Tagged> Extracting {:?} for Tagged<{}>", value, name);
|
||||||
|
|
||||||
@ -15,16 +16,16 @@ impl<T: ExtractType> ExtractType for Tagged<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ExtractType for bool {
|
impl ExtractType for bool {
|
||||||
fn extract(value: &Tagged<Value>) -> Result<bool, ShellError> {
|
fn extract(value: &Value) -> Result<bool, ShellError> {
|
||||||
trace!("Extracting {:?} for bool", value);
|
trace!("Extracting {:?} for bool", value);
|
||||||
|
|
||||||
match &value {
|
match &value {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Primitive(Primitive::Boolean(b)),
|
value: UntaggedValue::Primitive(Primitive::Boolean(b)),
|
||||||
..
|
..
|
||||||
} => Ok(*b),
|
} => Ok(*b),
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Primitive(Primitive::Nothing),
|
value: UntaggedValue::Primitive(Primitive::Nothing),
|
||||||
..
|
..
|
||||||
} => Ok(false),
|
} => Ok(false),
|
||||||
other => Err(ShellError::type_error(
|
other => Err(ShellError::type_error(
|
||||||
@ -36,12 +37,12 @@ impl ExtractType for bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ExtractType for std::path::PathBuf {
|
impl ExtractType for std::path::PathBuf {
|
||||||
fn extract(value: &Tagged<Value>) -> Result<std::path::PathBuf, ShellError> {
|
fn extract(value: &Value) -> Result<std::path::PathBuf, ShellError> {
|
||||||
trace!("Extracting {:?} for PathBuf", value);
|
trace!("Extracting {:?} for PathBuf", value);
|
||||||
|
|
||||||
match &value {
|
match &value {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Primitive(Primitive::Path(p)),
|
value: UntaggedValue::Primitive(Primitive::Path(p)),
|
||||||
..
|
..
|
||||||
} => Ok(p.clone()),
|
} => Ok(p.clone()),
|
||||||
other => Err(ShellError::type_error(
|
other => Err(ShellError::type_error(
|
||||||
@ -53,12 +54,12 @@ impl ExtractType for std::path::PathBuf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ExtractType for i64 {
|
impl ExtractType for i64 {
|
||||||
fn extract(value: &Tagged<Value>) -> Result<i64, ShellError> {
|
fn extract(value: &Value) -> Result<i64, ShellError> {
|
||||||
trace!("Extracting {:?} for i64", value);
|
trace!("Extracting {:?} for i64", value);
|
||||||
|
|
||||||
match &value {
|
match &value {
|
||||||
&Tagged {
|
&Value {
|
||||||
item: Value::Primitive(Primitive::Int(int)),
|
value: UntaggedValue::Primitive(Primitive::Int(int)),
|
||||||
..
|
..
|
||||||
} => Ok(int.tagged(&value.tag).coerce_into("converting to i64")?),
|
} => Ok(int.tagged(&value.tag).coerce_into("converting to i64")?),
|
||||||
other => Err(ShellError::type_error(
|
other => Err(ShellError::type_error(
|
||||||
@ -70,12 +71,12 @@ impl ExtractType for i64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ExtractType for u64 {
|
impl ExtractType for u64 {
|
||||||
fn extract(value: &Tagged<Value>) -> Result<u64, ShellError> {
|
fn extract(value: &Value) -> Result<u64, ShellError> {
|
||||||
trace!("Extracting {:?} for u64", value);
|
trace!("Extracting {:?} for u64", value);
|
||||||
|
|
||||||
match &value {
|
match &value {
|
||||||
&Tagged {
|
&Value {
|
||||||
item: Value::Primitive(Primitive::Int(int)),
|
value: UntaggedValue::Primitive(Primitive::Int(int)),
|
||||||
..
|
..
|
||||||
} => Ok(int.tagged(&value.tag).coerce_into("converting to u64")?),
|
} => Ok(int.tagged(&value.tag).coerce_into("converting to u64")?),
|
||||||
other => Err(ShellError::type_error(
|
other => Err(ShellError::type_error(
|
||||||
@ -87,12 +88,12 @@ impl ExtractType for u64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ExtractType for String {
|
impl ExtractType for String {
|
||||||
fn extract(value: &Tagged<Value>) -> Result<String, ShellError> {
|
fn extract(value: &Value) -> Result<String, ShellError> {
|
||||||
trace!("Extracting {:?} for String", value);
|
trace!("Extracting {:?} for String", value);
|
||||||
|
|
||||||
match value {
|
match value {
|
||||||
Tagged {
|
Value {
|
||||||
item: Value::Primitive(Primitive::String(string)),
|
value: UntaggedValue::Primitive(Primitive::String(string)),
|
||||||
..
|
..
|
||||||
} => Ok(string.clone()),
|
} => Ok(string.clone()),
|
||||||
other => Err(ShellError::type_error(
|
other => Err(ShellError::type_error(
|
||||||
|
@ -1,29 +1,29 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
use crate::parser::parse::parser::TracableContext;
|
|
||||||
use ansi_term::Color;
|
use ansi_term::Color;
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use language_reporting::{Diagnostic, Label, Severity};
|
use language_reporting::{Diagnostic, Label, Severity};
|
||||||
|
use nu_source::{Spanned, TracableContext};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
|
// TODO: Spanned<T> -> HasSpanAndItem<T> ?
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash, Serialize, Deserialize)]
|
||||||
pub enum Description {
|
pub enum Description {
|
||||||
Source(Spanned<String>),
|
Source(Spanned<String>),
|
||||||
Synthetic(String),
|
Synthetic(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Into<String>> Into<Description> for Spanned<T> {
|
|
||||||
fn into(self) -> Description {
|
|
||||||
Description::Source(self.map(|s| s.into()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Description {
|
impl Description {
|
||||||
|
fn from_spanned(item: Spanned<impl Into<String>>) -> Description {
|
||||||
|
Description::Source(item.map(|s| s.into()))
|
||||||
|
}
|
||||||
|
|
||||||
fn into_label(self) -> Result<Label<Span>, String> {
|
fn into_label(self) -> Result<Label<Span>, String> {
|
||||||
match self {
|
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),
|
Description::Synthetic(s) => Err(s),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -106,12 +106,6 @@ pub struct ShellError {
|
|||||||
cause: Option<Box<ProximateShellError>>,
|
cause: Option<Box<ProximateShellError>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
impl serde::de::Error for ShellError {
|
||||||
fn custom<T>(msg: T) -> Self
|
fn custom<T>(msg: T) -> Self
|
||||||
where
|
where
|
||||||
@ -138,8 +132,8 @@ impl ShellError {
|
|||||||
expr: Spanned<impl Into<String>>,
|
expr: Spanned<impl Into<String>>,
|
||||||
) -> ShellError {
|
) -> ShellError {
|
||||||
ProximateShellError::MissingProperty {
|
ProximateShellError::MissingProperty {
|
||||||
subpath: subpath.into(),
|
subpath: Description::from_spanned(subpath),
|
||||||
expr: expr.into(),
|
expr: Description::from_spanned(expr),
|
||||||
}
|
}
|
||||||
.start()
|
.start()
|
||||||
}
|
}
|
||||||
@ -149,7 +143,7 @@ impl ShellError {
|
|||||||
integer: impl Into<Span>,
|
integer: impl Into<Span>,
|
||||||
) -> ShellError {
|
) -> ShellError {
|
||||||
ProximateShellError::InvalidIntegerIndex {
|
ProximateShellError::InvalidIntegerIndex {
|
||||||
subpath: subpath.into(),
|
subpath: Description::from_spanned(subpath),
|
||||||
integer: integer.into(),
|
integer: integer.into(),
|
||||||
}
|
}
|
||||||
.start()
|
.start()
|
||||||
@ -172,12 +166,12 @@ impl ShellError {
|
|||||||
|
|
||||||
pub(crate) fn range_error(
|
pub(crate) fn range_error(
|
||||||
expected: impl Into<ExpectedRange>,
|
expected: impl Into<ExpectedRange>,
|
||||||
actual: &Tagged<impl fmt::Debug>,
|
actual: &Spanned<impl fmt::Debug>,
|
||||||
operation: impl Into<String>,
|
operation: impl Into<String>,
|
||||||
) -> ShellError {
|
) -> ShellError {
|
||||||
ProximateShellError::RangeError {
|
ProximateShellError::RangeError {
|
||||||
kind: expected.into(),
|
kind: expected.into(),
|
||||||
actual_kind: format!("{:?}", actual.item).spanned(actual.span()),
|
actual_kind: format!("{:?}", actual.item).spanned(actual.span),
|
||||||
operation: operation.into(),
|
operation: operation.into(),
|
||||||
}
|
}
|
||||||
.start()
|
.start()
|
||||||
@ -201,14 +195,6 @@ impl ShellError {
|
|||||||
.start()
|
.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn missing_value(span: Option<Span>, reason: impl Into<String>) -> ShellError {
|
|
||||||
ProximateShellError::MissingValue {
|
|
||||||
span,
|
|
||||||
reason: reason.into(),
|
|
||||||
}
|
|
||||||
.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn argument_error(
|
pub(crate) fn argument_error(
|
||||||
command: Spanned<impl Into<String>>,
|
command: Spanned<impl Into<String>>,
|
||||||
kind: ArgumentError,
|
kind: ArgumentError,
|
||||||
@ -404,28 +390,28 @@ impl ShellError {
|
|||||||
pub fn labeled_error(
|
pub fn labeled_error(
|
||||||
msg: impl Into<String>,
|
msg: impl Into<String>,
|
||||||
label: impl Into<String>,
|
label: impl Into<String>,
|
||||||
tag: impl Into<Tag>,
|
span: impl Into<Span>,
|
||||||
) -> ShellError {
|
) -> ShellError {
|
||||||
ShellError::diagnostic(
|
ShellError::diagnostic(
|
||||||
Diagnostic::new(Severity::Error, msg.into())
|
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(
|
pub fn labeled_error_with_secondary(
|
||||||
msg: impl Into<String>,
|
msg: impl Into<String>,
|
||||||
primary_label: impl Into<String>,
|
primary_label: impl Into<String>,
|
||||||
primary_span: impl Into<Tag>,
|
primary_span: impl Into<Span>,
|
||||||
secondary_label: impl Into<String>,
|
secondary_label: impl Into<String>,
|
||||||
secondary_span: impl Into<Tag>,
|
secondary_span: impl Into<Span>,
|
||||||
) -> ShellError {
|
) -> ShellError {
|
||||||
ShellError::diagnostic(
|
ShellError::diagnostic(
|
||||||
Diagnostic::new_error(msg.into())
|
Diagnostic::new_error(msg.into())
|
||||||
.with_label(
|
.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(
|
.with_label(
|
||||||
Label::new_secondary(secondary_span.into().span)
|
Label::new_secondary(secondary_span.into())
|
||||||
.with_message(secondary_label.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)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ShellDiagnostic {
|
pub struct ShellDiagnostic {
|
||||||
pub(crate) diagnostic: Diagnostic<Span>,
|
pub(crate) diagnostic: Diagnostic<Span>,
|
||||||
@ -690,18 +669,6 @@ impl std::convert::From<Box<dyn std::error::Error + Send + Sync>> for ShellError
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ShellErrorUtils<T> {
|
|
||||||
fn unwrap_error(self, desc: impl Into<String>) -> Result<T, ShellError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> ShellErrorUtils<Tagged<T>> for Option<Tagged<T>> {
|
|
||||||
fn unwrap_error(self, desc: impl Into<String>) -> Result<Tagged<T>, ShellError> {
|
|
||||||
match self {
|
|
||||||
Some(value) => Ok(value),
|
|
||||||
None => Err(ShellError::missing_value(None, desc.into())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub trait CoerceInto<U> {
|
pub trait CoerceInto<U> {
|
||||||
fn coerce_into(self, operation: impl Into<String>) -> Result<U, ShellError>;
|
fn coerce_into(self, operation: impl Into<String>) -> Result<U, ShellError>;
|
||||||
}
|
}
|
||||||
@ -718,26 +685,26 @@ macro_rules! ranged_int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CoerceInto<$ty> for Tagged<BigInt> {
|
impl CoerceInto<$ty> for nu_source::Tagged<BigInt> {
|
||||||
fn coerce_into(self, operation: impl Into<String>) -> Result<$ty, ShellError> {
|
fn coerce_into(self, operation: impl Into<String>) -> Result<$ty, ShellError> {
|
||||||
match self.$op() {
|
match self.$op() {
|
||||||
Some(v) => Ok(v),
|
Some(v) => Ok(v),
|
||||||
None => Err(ShellError::range_error(
|
None => Err(ShellError::range_error(
|
||||||
$ty::to_expected_range(),
|
$ty::to_expected_range(),
|
||||||
&self,
|
&self.item.spanned(self.tag.span),
|
||||||
operation.into(),
|
operation.into(),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CoerceInto<$ty> for Tagged<&BigInt> {
|
impl CoerceInto<$ty> for nu_source::Tagged<&BigInt> {
|
||||||
fn coerce_into(self, operation: impl Into<String>) -> Result<$ty, ShellError> {
|
fn coerce_into(self, operation: impl Into<String>) -> Result<$ty, ShellError> {
|
||||||
match self.$op() {
|
match self.$op() {
|
||||||
Some(v) => Ok(v),
|
Some(v) => Ok(v),
|
||||||
None => Err(ShellError::range_error(
|
None => Err(ShellError::range_error(
|
||||||
$ty::to_expected_range(),
|
$ty::to_expected_range(),
|
||||||
&self,
|
&self.item.spanned(self.tag.span),
|
||||||
operation.into(),
|
operation.into(),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
@ -763,26 +730,26 @@ macro_rules! ranged_decimal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CoerceInto<$ty> for Tagged<BigDecimal> {
|
impl CoerceInto<$ty> for nu_source::Tagged<BigDecimal> {
|
||||||
fn coerce_into(self, operation: impl Into<String>) -> Result<$ty, ShellError> {
|
fn coerce_into(self, operation: impl Into<String>) -> Result<$ty, ShellError> {
|
||||||
match self.$op() {
|
match self.$op() {
|
||||||
Some(v) => Ok(v),
|
Some(v) => Ok(v),
|
||||||
None => Err(ShellError::range_error(
|
None => Err(ShellError::range_error(
|
||||||
$ty::to_expected_range(),
|
$ty::to_expected_range(),
|
||||||
&self,
|
&self.item.spanned(self.tag.span),
|
||||||
operation.into(),
|
operation.into(),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CoerceInto<$ty> for Tagged<&BigDecimal> {
|
impl CoerceInto<$ty> for nu_source::Tagged<&BigDecimal> {
|
||||||
fn coerce_into(self, operation: impl Into<String>) -> Result<$ty, ShellError> {
|
fn coerce_into(self, operation: impl Into<String>) -> Result<$ty, ShellError> {
|
||||||
match self.$op() {
|
match self.$op() {
|
||||||
Some(v) => Ok(v),
|
Some(v) => Ok(v),
|
||||||
None => Err(ShellError::range_error(
|
None => Err(ShellError::range_error(
|
||||||
$ty::to_expected_range(),
|
$ty::to_expected_range(),
|
||||||
&self,
|
&self.item.spanned(self.tag.span),
|
||||||
operation.into(),
|
operation.into(),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user