diff --git a/Cargo.lock b/Cargo.lock index 54b4e3ba3a..0af4f60b95 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,9 +35,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b412394828b7ca486b362f300b762d8e43dafd6f0d727b63f1cd2ade207c6cef" +checksum = "9267dff192e68f3399525901e709a48c1d3982c9c072fa32f2127a0cb0babf14" [[package]] name = "app_dirs" @@ -855,6 +855,15 @@ dependencies = [ "termcolor", ] +[[package]] +name = "erased-serde" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beee4bc16478a1b26f2e80ad819a52d24745e292f521a63c16eea5f74b7eb60" +dependencies = [ + "serde 1.0.103", +] + [[package]] name = "failure" version = "0.1.6" @@ -1082,6 +1091,17 @@ dependencies = [ "syn", ] +[[package]] +name = "ghost" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a36606a68532b5640dc86bb1f33c64b45c4682aad4c50f3937b317ea387f3d6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "git2" version = "0.10.2" @@ -1388,6 +1408,28 @@ dependencies = [ "adler32", ] +[[package]] +name = "inventory" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4cece20baea71d9f3435e7bbe9adf4765f091c5fe404975f844006964a71299" +dependencies = [ + "ctor", + "ghost", + "inventory-impl", +] + +[[package]] +name = "inventory-impl" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2869bf972e998977b1cb87e60df70341d48e48dca0823f534feb91ea44adaf9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "iovec" version = "0.1.4" @@ -1540,9 +1582,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.65" +version = "0.2.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" +checksum = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" [[package]] name = "libgit2-sys" @@ -1880,6 +1922,10 @@ dependencies = [ "nom 5.0.1", "nom-tracable", "nom_locate", + "nu-build", + "nu-errors", + "nu-parser", + "nu-protocol", "nu-source", "num-bigint", "num-traits 0.2.10", @@ -1891,6 +1937,7 @@ dependencies = [ "pretty_env_logger", "prettytable-rs", "ptree", + "query_interface", "rawkey", "regex", "roxmltree", @@ -1917,12 +1964,105 @@ dependencies = [ "textwrap", "toml 0.5.5", "trash", + "typetag", "umask", "unicode-xid", "url", "which", ] +[[package]] +name = "nu-build" +version = "0.1.0" +dependencies = [ + "lazy_static 1.4.0", + "serde 1.0.103", + "serde_json", + "toml 0.5.5", +] + +[[package]] +name = "nu-errors" +version = "0.1.0" +dependencies = [ + "ansi_term 0.12.1", + "bigdecimal", + "derive-new", + "language-reporting", + "nom 5.0.1", + "nom_locate", + "nu-build", + "nu-source", + "num-bigint", + "num-traits 0.2.10", + "serde 1.0.103", + "serde_json", + "serde_yaml", + "subprocess", + "toml 0.5.5", +] + +[[package]] +name = "nu-parser" +version = "0.1.0" +dependencies = [ + "ansi_term 0.12.1", + "bigdecimal", + "cfg-if", + "derive-new", + "getset", + "indexmap", + "itertools 0.8.2", + "language-reporting", + "log", + "nom 5.0.1", + "nom-tracable", + "nom_locate", + "nu-build", + "nu-errors", + "nu-protocol", + "nu-source", + "num-bigint", + "num-traits 0.2.10", + "pretty", + "pretty_assertions", + "pretty_env_logger", + "ptree", + "serde 1.0.103", + "shellexpand", + "termcolor", + "unicode-xid", +] + +[[package]] +name = "nu-protocol" +version = "0.1.0" +dependencies = [ + "ansi_term 0.12.1", + "bigdecimal", + "chrono", + "derive-new", + "getset", + "indexmap", + "language-reporting", + "nom 5.0.1", + "nom-tracable", + "nom_locate", + "nu-build", + "nu-errors", + "nu-source", + "num-bigint", + "num-traits 0.2.10", + "query_interface", + "serde 1.0.103", + "serde_bytes", + "serde_json", + "serde_yaml", + "subprocess", + "toml 0.5.5", + "typetag", +] + [[package]] name = "nu-source" version = "0.1.0" @@ -1932,11 +2072,26 @@ dependencies = [ "language-reporting", "nom-tracable", "nom_locate", + "nu-build", "pretty", "serde 1.0.103", "termcolor", ] +[[package]] +name = "nu-textview" +version = "0.1.0" +dependencies = [ + "ansi_term 0.12.1", + "crossterm", + "nu", + "nu-build", + "nu-protocol", + "nu-source", + "syntect", + "url", +] + [[package]] name = "num-bigint" version = "0.2.3" @@ -2298,6 +2453,12 @@ dependencies = [ "tint", ] +[[package]] +name = "query_interface" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c0f0046284eebb86b68f93f9677d499034f88e15ca01021ceea32c4d3c3693" + [[package]] name = "quick-error" version = "1.2.2" @@ -2942,9 +3103,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.8" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "661641ea2aa15845cddeb97dad000d22070bb5c1fb456b96c1cba883ec691e92" +checksum = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238" dependencies = [ "proc-macro2", "quote", @@ -3150,6 +3311,30 @@ version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" +[[package]] +name = "typetag" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ebb2c484029d695fb68a06d80e1536c68d491b3e0cf874c66abed255e831cfe" +dependencies = [ + "erased-serde", + "inventory", + "lazy_static 1.4.0", + "serde 1.0.103", + "typetag-impl", +] + +[[package]] +name = "typetag-impl" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63fd4799e4d0ec5cf0b055ebb8e2c3a657bbf76a84f6edc77ca60780e000204" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "umask" version = "0.1.8" @@ -3251,9 +3436,9 @@ checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" [[package]] name = "vcpkg" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33dd455d0f96e90a75803cfeb7f948768c08d70a6de9a8d2362461935698bf95" +checksum = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168" [[package]] name = "vec_map" diff --git a/Cargo.toml b/Cargo.toml index c2f6785a9e..eb11e61680 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,13 +13,18 @@ documentation = "https://book.nushell.sh" [workspace] -members = ["crates/nu-source"] +members = ["crates/nu-errors", "crates/nu-source", "crates/nu-textview", "crates/nu-protocol", "crates/nu-parser", "crates/nu-build"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] nu-source = { version = "0.1.0", path = "./crates/nu-source" } +nu-protocol = { version = "0.1.0", path = "./crates/nu-protocol" } +nu-errors = { version = "0.1.0", path = "./crates/nu-errors" } +nu-parser = { version = "0.1.0", path = "./crates/nu-parser" } +query_interface = "0.3.5" +typetag = "0.1.4" rustyline = "5.0.4" chrono = { version = "0.4.9", features = ["serde"] } derive-new = "0.5.8" @@ -103,9 +108,8 @@ image = { version = "0.22.2", default_features = false, features = ["png_codec", starship = { version = "0.26.4", optional = true} [features] -default = ["textview", "sys", "ps"] +default = ["sys", "ps"] raw-key = ["rawkey", "neso"] -textview = ["syntect", "onig_sys", "crossterm"] binaryview = ["image", "crossterm"] sys = ["heim", "battery"] ps = ["heim"] @@ -122,6 +126,7 @@ pretty_assertions = "0.6.1" [build-dependencies] toml = "0.5.5" serde = { version = "1.0.102", features = ["derive"] } +nu-build = { version = "0.1.0", path = "./crates/nu-build" } [lib] name = "nu" @@ -191,11 +196,6 @@ name = "nu_plugin_binaryview" path = "src/plugins/binaryview.rs" required-features = ["binaryview"] -[[bin]] -name = "nu_plugin_textview" -path = "src/plugins/textview.rs" -required-features = ["textview"] - [[bin]] name = "nu_plugin_docker" path = "src/plugins/docker.rs" diff --git a/build.rs b/build.rs index 44a55f9573..b7511cfc6a 100644 --- a/build.rs +++ b/build.rs @@ -1,39 +1,3 @@ -use serde::Deserialize; -use std::collections::HashMap; -use std::collections::HashSet; -use std::env; -use std::path::Path; - -#[derive(Deserialize)] -struct Feature { - #[allow(unused)] - description: String, - enabled: bool, -} - fn main() -> Result<(), Box> { - let input = env::var("CARGO_MANIFEST_DIR").unwrap(); - let all_on = env::var("NUSHELL_ENABLE_ALL_FLAGS").is_ok(); - let flags: HashSet = env::var("NUSHELL_ENABLE_FLAGS") - .map(|s| s.split(",").map(|s| s.to_string()).collect()) - .unwrap_or_else(|_| HashSet::new()); - - if all_on && !flags.is_empty() { - println!( - "cargo:warning={}", - "Both NUSHELL_ENABLE_ALL_FLAGS and NUSHELL_ENABLE_FLAGS were set. You don't need both." - ); - } - - let path = Path::new(&input).join("features.toml"); - - let toml: HashMap = toml::from_str(&std::fs::read_to_string(path)?)?; - - for (key, value) in toml.iter() { - if value.enabled == true || all_on || flags.contains(key) { - println!("cargo:rustc-cfg={}", key); - } - } - - Ok(()) + nu_build::build() } diff --git a/crates/nu-build/Cargo.toml b/crates/nu-build/Cargo.toml new file mode 100644 index 0000000000..66a6ffbbe0 --- /dev/null +++ b/crates/nu-build/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "nu-build" +version = "0.1.0" +authors = ["Yehuda Katz "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde = { version = "1.0.102", features = ["derive"] } +lazy_static = "1.2.0" +serde_json = "1.0.35" +toml = "0.5.5" diff --git a/crates/nu-build/src/lib.rs b/crates/nu-build/src/lib.rs new file mode 100644 index 0000000000..1689dfd11f --- /dev/null +++ b/crates/nu-build/src/lib.rs @@ -0,0 +1,82 @@ +use lazy_static::lazy_static; +use serde::Deserialize; +use std::collections::BTreeMap; +use std::collections::HashMap; +use std::collections::HashSet; +use std::env; +use std::path::{Path, PathBuf}; +use std::sync::Mutex; + +lazy_static! { + static ref WORKSPACES: Mutex> = Mutex::new(BTreeMap::new()); +} + +// got from https://github.com/mitsuhiko/insta/blob/b113499249584cb650150d2d01ed96ee66db6b30/src/runtime.rs#L67-L88 + +fn get_cargo_workspace(manifest_dir: &str) -> Option<&Path> { + let mut workspaces = WORKSPACES.lock().unwrap(); + if let Some(rv) = workspaces.get(manifest_dir) { + Some(rv) + } else { + #[derive(Deserialize)] + struct Manifest { + workspace_root: String, + } + let output = std::process::Command::new(env!("CARGO")) + .arg("metadata") + .arg("--format-version=1") + .current_dir(manifest_dir) + .output() + .unwrap(); + let manifest: Manifest = serde_json::from_slice(&output.stdout).unwrap(); + let path = Box::leak(Box::new(PathBuf::from(manifest.workspace_root))); + workspaces.insert(manifest_dir.to_string(), path.as_path()); + workspaces.get(manifest_dir).map(|w| *w) + } +} + +#[derive(Deserialize)] +struct Feature { + #[allow(unused)] + description: String, + enabled: bool, +} + +pub fn build() -> Result<(), Box> { + let input = env::var("CARGO_MANIFEST_DIR").unwrap(); + + let all_on = env::var("NUSHELL_ENABLE_ALL_FLAGS").is_ok(); + let flags: HashSet = env::var("NUSHELL_ENABLE_FLAGS") + .map(|s| s.split(",").map(|s| s.to_string()).collect()) + .unwrap_or_else(|_| HashSet::new()); + + if all_on && !flags.is_empty() { + println!( + "cargo:warning={}", + "Both NUSHELL_ENABLE_ALL_FLAGS and NUSHELL_ENABLE_FLAGS were set. You don't need both." + ); + } + + let workspace = match get_cargo_workspace(&input) { + // If the crate is being downloaded from crates.io, it won't have a workspace root, and that's ok + None => return Ok(()), + Some(workspace) => workspace, + }; + + let path = Path::new(&workspace).join("features.toml"); + + // If the crate is being downloaded from crates.io, it won't have a features.toml, and that's ok + if !path.exists() { + return Ok(()); + } + + let toml: HashMap = toml::from_str(&std::fs::read_to_string(path)?)?; + + for (key, value) in toml.iter() { + if value.enabled == true || all_on || flags.contains(key) { + println!("cargo:rustc-cfg={}", key); + } + } + + Ok(()) +} diff --git a/crates/nu-errors/Cargo.toml b/crates/nu-errors/Cargo.toml new file mode 100644 index 0000000000..3c3f4a4409 --- /dev/null +++ b/crates/nu-errors/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "nu-errors" +version = "0.1.0" +authors = ["Yehuda Katz "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +nu-source = { path = "../nu-source" } + +ansi_term = "0.12.1" +bigdecimal = { version = "0.1.0", features = ["serde"] } +derive-new = "0.5.8" +language-reporting = "0.4.0" +num-bigint = { version = "0.2.3", features = ["serde"] } +num-traits = "0.2.8" +serde = { version = "1.0.102", features = ["derive"] } +nom = "5.0.1" +nom_locate = "1.0.0" + +# implement conversions +subprocess = "0.1.18" +serde_yaml = "0.8" +toml = "0.5.5" +serde_json = "1.0.41" + +[build-dependencies] +nu-build = { version = "0.1.0", path = "../nu-build" } diff --git a/crates/nu-errors/build.rs b/crates/nu-errors/build.rs new file mode 100644 index 0000000000..b7511cfc6a --- /dev/null +++ b/crates/nu-errors/build.rs @@ -0,0 +1,3 @@ +fn main() -> Result<(), Box> { + nu_build::build() +} diff --git a/src/errors.rs b/crates/nu-errors/src/lib.rs similarity index 85% rename from src/errors.rs rename to crates/nu-errors/src/lib.rs index 036240a6a1..1abeae9db4 100644 --- a/src/errors.rs +++ b/crates/nu-errors/src/lib.rs @@ -1,71 +1,49 @@ -use crate::prelude::*; - use ansi_term::Color; +use bigdecimal::BigDecimal; use derive_new::new; use language_reporting::{Diagnostic, Label, Severity}; -use nu_source::{Spanned, TracableContext}; +use nu_source::{b, DebugDocBuilder, PrettyDebug, Span, Spanned, SpannedItem, TracableContext}; +use num_bigint::BigInt; +use num_traits::ToPrimitive; use serde::{Deserialize, Serialize}; use std::fmt; use std::ops::Range; -// TODO: Spanned -> HasSpanAndItem ? - -#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash, Serialize, Deserialize)] -pub enum Description { - Source(Spanned), - Synthetic(String), -} - -impl Description { - fn from_spanned(item: Spanned>) -> Description { - Description::Source(item.map(|s| s.into())) - } - - fn into_label(self) -> Result, String> { - match self { - Description::Source(s) => Ok(Label::new_primary(s.span).with_message(s.item)), - Description::Synthetic(s) => Err(s), - } - } -} - -impl PrettyDebug for Description { - fn pretty(&self) -> DebugDocBuilder { - match self { - Description::Source(s) => b::description(&s.item), - Description::Synthetic(s) => b::description(s), - } - } -} - +/// A structured reason for a ParseError. Note that parsing in nu is more like macro expansion in +/// other languages, so the kinds of errors that can occur during parsing are more contextual than +/// you might expect. #[derive(Debug, Clone)] pub enum ParseErrorReason { - Eof { - expected: &'static str, - span: Span, - }, + /// The parser encountered an EOF rather than what it was expecting + Eof { expected: &'static str, span: Span }, + /// The parser encountered something other than what it was expecting Mismatch { expected: &'static str, actual: Spanned, }, + /// The parser tried to parse an argument for a command, but it failed for + /// some reason ArgumentError { command: Spanned, error: ArgumentError, }, } +/// A newtype for `ParseErrorReason` #[derive(Debug, Clone)] pub struct ParseError { reason: ParseErrorReason, } impl ParseError { + /// Construct a [ParseErrorReason::Eof](ParseErrorReason::Eof) pub fn unexpected_eof(expected: &'static str, span: Span) -> ParseError { ParseError { reason: ParseErrorReason::Eof { expected, span }, } } + /// Construct a [ParseErrorReason::Mismatch](ParseErrorReason::Mismatch) pub fn mismatch(expected: &'static str, actual: Spanned>) -> ParseError { let Spanned { span, item } = actual; @@ -77,6 +55,7 @@ impl ParseError { } } + /// Construct a [ParseErrorReason::ArgumentError](ParseErrorReason::ArgumentError) pub fn argument_error(command: Spanned>, kind: ArgumentError) -> ParseError { ParseError { reason: ParseErrorReason::ArgumentError { @@ -87,6 +66,7 @@ impl ParseError { } } +/// Convert a [ParseError](ParseError) into a [ShellError](ShellError) impl From for ShellError { fn from(error: ParseError) -> ShellError { match error.reason { @@ -101,11 +81,20 @@ impl From for ShellError { } } +/// ArgumentError describes various ways that the parser could fail because of unexpected arguments. +/// Nu commands are like a combination of functions and macros, and these errors correspond to +/// problems that could be identified during expansion based on the syntactic signature of a +/// command. #[derive(Debug, Eq, PartialEq, Clone, Ord, Hash, PartialOrd, Serialize, Deserialize)] pub enum ArgumentError { + /// The command specified a mandatory flag, but it was missing. MissingMandatoryFlag(String), + /// The command specified a mandatory positional argument, but it was missing. MissingMandatoryPositional(String), + /// A flag was found, and it should have been followed by a value, but no value was found MissingValueForName(String), + /// A sequence of characters was found that was not syntactically valid (but would have + /// been valid if the command was an external command) InvalidExternalWord, } @@ -132,12 +121,16 @@ impl PrettyDebug for ArgumentError { } } +/// A `ShellError` is a proximate error and a possible cause, which could have its own cause, +/// creating a cause chain. #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Serialize, Deserialize, Hash)] pub struct ShellError { error: ProximateShellError, - cause: Option>, + cause: Option>, } +/// `PrettyDebug` is for internal debugging. For user-facing debugging, [to_diagnostic](ShellError::to_diagnostic) +/// is used, which prints an error, highlighting spans. impl PrettyDebug for ShellError { fn pretty(&self) -> DebugDocBuilder { match &self.error { @@ -170,12 +163,12 @@ impl PrettyDebug for ShellError { "(", b::description("expr:") + b::space() - + expr.pretty() + + b::description(&expr.item) + b::description(",") + b::space() + b::description("subpath:") + b::space() - + subpath.pretty(), + + b::description(&subpath.item), ")", ) } @@ -184,7 +177,7 @@ impl PrettyDebug for ShellError { + b::space() + b::delimit( "(", - b::description("subpath:") + b::space() + subpath.pretty(), + b::description("subpath:") + b::space() + b::description(&subpath.item), ")", ) } @@ -294,8 +287,8 @@ impl ShellError { expr: Spanned>, ) -> ShellError { ProximateShellError::MissingProperty { - subpath: Description::from_spanned(subpath), - expr: Description::from_spanned(expr), + subpath: subpath.map(|s| s.into()), + expr: expr.map(|e| e.into()), } .start() } @@ -305,7 +298,7 @@ impl ShellError { integer: impl Into, ) -> ShellError { ProximateShellError::InvalidIntegerIndex { - subpath: Description::from_spanned(subpath), + subpath: subpath.map(|s| s.into()), integer: integer.into(), } .start() @@ -318,7 +311,7 @@ impl ShellError { .start() } - pub(crate) fn unexpected_eof(expected: impl Into, span: impl Into) -> ShellError { + pub fn unexpected_eof(expected: impl Into, span: impl Into) -> ShellError { ProximateShellError::UnexpectedEof { expected: expected.into(), span: span.into(), @@ -326,7 +319,7 @@ impl ShellError { .start() } - pub(crate) fn range_error( + pub fn range_error( expected: impl Into, actual: &Spanned, operation: impl Into, @@ -339,14 +332,14 @@ impl ShellError { .start() } - pub(crate) fn syntax_error(problem: Spanned>) -> ShellError { + pub fn syntax_error(problem: Spanned>) -> ShellError { ProximateShellError::SyntaxError { problem: problem.map(|p| p.into()), } .start() } - pub(crate) fn coerce_error( + pub fn coerce_error( left: Spanned>, right: Spanned>, ) -> ShellError { @@ -357,10 +350,7 @@ impl ShellError { .start() } - pub(crate) fn argument_error( - command: Spanned>, - kind: ArgumentError, - ) -> ShellError { + pub fn argument_error(command: Spanned>, kind: ArgumentError) -> ShellError { ProximateShellError::ArgumentError { command: command.map(|c| c.into()), error: kind, @@ -368,7 +358,7 @@ impl ShellError { .start() } - pub(crate) fn parse_error( + pub fn parse_error( error: nom::Err<( nom_locate::LocatedSpanEx<&str, TracableContext>, nom::error::ErrorKind, @@ -395,11 +385,11 @@ impl ShellError { } } - pub(crate) fn diagnostic(diagnostic: Diagnostic) -> ShellError { + pub fn diagnostic(diagnostic: Diagnostic) -> ShellError { ProximateShellError::Diagnostic(ShellDiagnostic { diagnostic }).start() } - pub(crate) fn to_diagnostic(self) -> Diagnostic { + pub fn to_diagnostic(self) -> Diagnostic { match self.error { ProximateShellError::MissingValue { span, reason } => { let mut d = Diagnostic::new( @@ -491,7 +481,7 @@ impl ShellError { Label::new_primary(span).with_message(format!( "Expected to convert {} to {} while {}, but it was out of range", item, - kind.desc(), + kind.display(), operation )), ), @@ -506,31 +496,33 @@ impl ShellError { .with_label(Label::new_primary(span).with_message(item)), ProximateShellError::MissingProperty { subpath, expr, .. } => { - let subpath = subpath.into_label(); - let expr = expr.into_label(); let mut diag = Diagnostic::new(Severity::Error, "Missing property"); - match subpath { - Ok(label) => diag = diag.with_label(label), - Err(ty) => diag.message = format!("Missing property (for {})", ty), - } + if subpath.span == Span::unknown() { + diag.message = format!("Missing property (for {})", subpath.item); + } else { + let subpath = Label::new_primary(subpath.span).with_message(subpath.item); + diag = diag.with_label(subpath); + + if expr.span != Span::unknown() { + let expr = Label::new_primary(expr.span).with_message(expr.item); + diag = diag.with_label(expr) + } - if let Ok(label) = expr { - diag = diag.with_label(label); } diag } ProximateShellError::InvalidIntegerIndex { subpath,integer } => { - let subpath = subpath.into_label(); - let mut diag = Diagnostic::new(Severity::Error, "Invalid integer property"); - match subpath { - Ok(label) => diag = diag.with_label(label), - Err(ty) => diag.message = format!("Invalid integer property (for {})", ty) + if subpath.span == Span::unknown() { + diag.message = format!("Invalid integer property (for {})", subpath.item) + } else { + let label = Label::new_primary(subpath.span).with_message(subpath.item); + diag = diag.with_label(label) } diag = diag.with_label(Label::new_secondary(integer).with_message("integer")); @@ -579,23 +571,19 @@ impl ShellError { ) } - // pub fn string(title: impl Into) -> ShellError { - // ProximateShellError::String(StringError::new(title.into(), String::new())).start() - // } - // - // pub(crate) fn unreachable(title: impl Into) -> ShellError { - // ShellError::untagged_runtime_error(&format!("BUG: Unreachable: {}", title.into())) - // } - - pub(crate) fn unimplemented(title: impl Into) -> ShellError { + pub fn unimplemented(title: impl Into) -> ShellError { ShellError::untagged_runtime_error(&format!("Unimplemented: {}", title.into())) } - pub(crate) fn unexpected(title: impl Into) -> ShellError { + pub fn unexpected(title: impl Into) -> ShellError { ShellError::untagged_runtime_error(&format!("Unexpected: {}", title.into())) } } +/// `ExpectedRange` describes a range of values that was expected by a command. In addition +/// to typical ranges, this enum allows an error to specify that the range of allowed values +/// corresponds to a particular numeric type (which is a dominant use-case for the +/// [RangeError](ProximateShellError::RangeError) error type). #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Serialize, Deserialize)] pub enum ExpectedRange { I8, @@ -617,6 +605,7 @@ pub enum ExpectedRange { Range { start: usize, end: usize }, } +/// Convert a Rust range into an [ExpectedRange](ExpectedRange). impl From> for ExpectedRange { fn from(range: Range) -> Self { ExpectedRange::Range { @@ -628,13 +617,7 @@ impl From> for ExpectedRange { impl PrettyDebug for ExpectedRange { fn pretty(&self) -> DebugDocBuilder { - b::description(self.desc()) - } -} - -impl ExpectedRange { - fn desc(&self) -> String { - match self { + b::description(match self { ExpectedRange::I8 => "an 8-bit signed integer", ExpectedRange::I16 => "a 16-bit signed integer", ExpectedRange::I32 => "a 32-bit signed integer", @@ -651,9 +634,10 @@ impl ExpectedRange { ExpectedRange::Size => "a list offset", ExpectedRange::BigDecimal => "a decimal", ExpectedRange::BigInt => "an integer", - ExpectedRange::Range { start, end } => return format!("{} to {}", start, end), - } - .to_string() + ExpectedRange::Range { start, end } => { + return b::description(format!("{} to {}", start, end)) + } + }) } } @@ -671,11 +655,11 @@ pub enum ProximateShellError { actual: Spanned>, }, MissingProperty { - subpath: Description, - expr: Description, + subpath: Spanned, + expr: Spanned, }, InvalidIntegerIndex { - subpath: Description, + subpath: Spanned, integer: Span, }, MissingValue { diff --git a/crates/nu-parser/Cargo.toml b/crates/nu-parser/Cargo.toml new file mode 100644 index 0000000000..a6eadc4efe --- /dev/null +++ b/crates/nu-parser/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "nu-parser" +version = "0.1.0" +authors = ["Yehuda Katz "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +nu-errors = { path = "../nu-errors" } +nu-source = { path = "../nu-source" } +nu-protocol = { path = "../nu-protocol" } + +pretty_env_logger = "0.3.1" +pretty = "0.5.2" +termcolor = "1.0.5" +log = "0.4.8" +indexmap = { version = "1.3.0", features = ["serde-1"] } +serde = { version = "1.0.102", features = ["derive"] } +nom = "5.0.1" +nom_locate = "1.0.0" +nom-tracable = "0.4.1" +num-traits = "0.2.8" +num-bigint = { version = "0.2.3", features = ["serde"] } +bigdecimal = { version = "0.1.0", features = ["serde"] } +derive-new = "0.5.8" +getset = "0.0.9" +cfg-if = "0.1" +itertools = "0.8.1" +shellexpand = "1.0.0" +ansi_term = "0.12.1" +ptree = {version = "0.2" } +language-reporting = "0.4.0" +unicode-xid = "0.2.0" + +[dev-dependencies] +pretty_assertions = "0.6.1" + +[build-dependencies] +nu-build = { version = "0.1.0", path = "../nu-build" } diff --git a/crates/nu-parser/build.rs b/crates/nu-parser/build.rs new file mode 100644 index 0000000000..b7511cfc6a --- /dev/null +++ b/crates/nu-parser/build.rs @@ -0,0 +1,3 @@ +fn main() -> Result<(), Box> { + nu_build::build() +} diff --git a/crates/nu-parser/src/commands.rs b/crates/nu-parser/src/commands.rs new file mode 100644 index 0000000000..3e94dd7c2f --- /dev/null +++ b/crates/nu-parser/src/commands.rs @@ -0,0 +1,98 @@ +pub mod classified; + +use crate::commands::classified::ClassifiedCommand; +use crate::hir::expand_external_tokens::ExternalTokensShape; +use crate::hir::syntax_shape::{expand_syntax, ExpandContext}; +use crate::hir::tokens_iterator::TokensIterator; +use nu_errors::ParseError; +use nu_source::{b, DebugDocBuilder, HasSpan, PrettyDebug, Span, Spanned, Tag, Tagged}; + +// Classify this command as an external command, which doesn't give special meaning +// to nu syntactic constructs, and passes all arguments to the external command as +// strings. +pub(crate) fn external_command( + tokens: &mut TokensIterator, + context: &ExpandContext, + name: Tagged<&str>, +) -> Result { + let Spanned { item, span } = expand_syntax(&ExternalTokensShape, tokens, context)?.tokens; + + Ok(ClassifiedCommand::External(ExternalCommand { + name: name.to_string(), + name_tag: name.tag(), + args: ExternalArgs { + list: item + .iter() + .map(|x| ExternalArg { + tag: x.span.into(), + arg: x.item.clone(), + }) + .collect(), + span, + }, + })) +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct ExternalArg { + pub arg: String, + pub tag: Tag, +} + +impl std::ops::Deref for ExternalArg { + type Target = str; + + fn deref(&self) -> &str { + &self.arg + } +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct ExternalArgs { + pub list: Vec, + pub span: Span, +} + +impl ExternalArgs { + pub fn iter(&self) -> impl Iterator { + self.list.iter() + } +} + +impl std::ops::Deref for ExternalArgs { + type Target = [ExternalArg]; + + fn deref(&self) -> &[ExternalArg] { + &self.list + } +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct ExternalCommand { + pub name: String, + + pub name_tag: Tag, + pub args: ExternalArgs, +} + +impl PrettyDebug for ExternalCommand { + fn pretty(&self) -> DebugDocBuilder { + b::typed( + "external command", + b::description(&self.name) + + b::preceded( + b::space(), + b::intersperse( + self.args.iter().map(|a| b::primitive(format!("{}", a.arg))), + b::space(), + ), + ), + ) + } +} + +impl HasSpan for ExternalCommand { + fn span(&self) -> Span { + self.name_tag.span.until(self.args.span) + } +} diff --git a/crates/nu-parser/src/commands/classified.rs b/crates/nu-parser/src/commands/classified.rs new file mode 100644 index 0000000000..3454ce5a75 --- /dev/null +++ b/crates/nu-parser/src/commands/classified.rs @@ -0,0 +1,112 @@ +use crate::commands::ExternalCommand; +use crate::hir; +use crate::parse::token_tree::TokenNode; +use derive_new::new; +use nu_source::{b, DebugDocBuilder, HasSpan, PrettyDebugWithSource, Span, Tag}; + +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum ClassifiedCommand { + #[allow(unused)] + Expr(TokenNode), + #[allow(unused)] + Dynamic(hir::Call), + Internal(InternalCommand), + External(ExternalCommand), +} + +impl PrettyDebugWithSource for ClassifiedCommand { + fn pretty_debug(&self, source: &str) -> DebugDocBuilder { + match self { + ClassifiedCommand::Expr(token) => b::typed("command", token.pretty_debug(source)), + ClassifiedCommand::Dynamic(call) => b::typed("command", call.pretty_debug(source)), + ClassifiedCommand::Internal(internal) => internal.pretty_debug(source), + ClassifiedCommand::External(external) => external.pretty_debug(source), + } + } +} + +impl HasSpan for ClassifiedCommand { + fn span(&self) -> Span { + match self { + ClassifiedCommand::Expr(node) => node.span(), + ClassifiedCommand::Internal(command) => command.span(), + ClassifiedCommand::Dynamic(call) => call.span, + ClassifiedCommand::External(command) => command.span(), + } + } +} + +#[derive(new, Debug, Clone, Eq, PartialEq)] +pub struct InternalCommand { + pub name: String, + pub name_tag: Tag, + pub 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 { + fn span(&self) -> Span { + let start = self.name_tag.span; + + start.until(self.args.span) + } +} + +#[derive(new, Debug, Eq, PartialEq)] +pub(crate) struct DynamicCommand { + pub(crate) args: hir::Call, +} + +#[derive(Debug, Clone)] +pub struct Commands { + pub list: Vec, + pub span: Span, +} + +impl std::ops::Deref for Commands { + type Target = [ClassifiedCommand]; + + fn deref(&self) -> &Self::Target { + &self.list + } +} + +#[derive(Debug, Clone)] +pub struct ClassifiedPipeline { + pub commands: Commands, +} + +impl ClassifiedPipeline { + pub fn commands(list: Vec, span: impl Into) -> ClassifiedPipeline { + ClassifiedPipeline { + commands: Commands { + list, + span: span.into(), + }, + } + } +} + +impl HasSpan for ClassifiedPipeline { + fn span(&self) -> Span { + self.commands.span + } +} + +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"), ">")) + } +} diff --git a/crates/nu-parser/src/commands/classified/external.rs b/crates/nu-parser/src/commands/classified/external.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/parser/hir.rs b/crates/nu-parser/src/hir.rs similarity index 84% rename from src/parser/hir.rs rename to crates/nu-parser/src/hir.rs index d5ec134f6a..42e01e2d6a 100644 --- a/src/parser/hir.rs +++ b/crates/nu-parser/src/hir.rs @@ -4,30 +4,31 @@ pub(crate) mod expand_external_tokens; pub(crate) mod external_command; pub(crate) mod named; pub(crate) mod path; -pub(crate) mod syntax_shape; +pub mod syntax_shape; pub(crate) mod tokens_iterator; -use crate::parser::hir::path::PathMember; -use crate::parser::hir::syntax_shape::Member; -use crate::parser::{registry, Operator, Unit}; -use crate::prelude::*; +use crate::hir::syntax_shape::Member; +use crate::parse::operator::Operator; +use crate::parse::parser::Number; +use crate::parse::unit::Unit; use derive_new::new; use getset::Getters; -use nu_source::Spanned; +use nu_protocol::{PathMember, ShellTypeName}; +use nu_source::{ + b, DebugDocBuilder, HasSpan, PrettyDebug, PrettyDebugWithSource, Span, Spanned, SpannedItem, +}; use serde::{Deserialize, Serialize}; use std::path::PathBuf; -use crate::evaluate::Scope; -use crate::parser::parse::tokens::RawNumber; +use crate::parse::tokens::RawNumber; pub(crate) use self::binary::Binary; -pub(crate) use self::external_command::ExternalCommand; -pub(crate) use self::named::NamedArguments; pub(crate) use self::path::Path; pub(crate) use self::syntax_shape::ExpandContext; pub(crate) use self::tokens_iterator::TokensIterator; -pub use self::syntax_shape::SyntaxShape; +pub use self::external_command::ExternalCommand; +pub use self::named::{NamedArguments, NamedValue}; #[derive(Debug, Clone, Eq, PartialEq, Getters, Serialize, Deserialize, new)] pub struct Call { @@ -60,17 +61,6 @@ impl PrettyDebugWithSource for Call { } } -impl Call { - pub fn evaluate( - &self, - registry: ®istry::CommandRegistry, - scope: &Scope, - source: &Text, - ) -> Result { - registry::evaluate_args(self, registry, scope, source) - } -} - #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] pub enum RawExpression { Literal(Literal), @@ -196,41 +186,37 @@ impl PrettyDebugWithSource for Expression { } impl Expression { - pub(crate) fn number(i: impl Into, span: impl Into) -> Expression { + pub fn number(i: impl Into, span: impl Into) -> Expression { let span = span.into(); RawExpression::Literal(RawLiteral::Number(i.into()).into_literal(span)).into_expr(span) } - pub(crate) fn size( - i: impl Into, - unit: impl Into, - span: impl Into, - ) -> Expression { + pub fn size(i: impl Into, unit: impl Into, span: impl Into) -> Expression { let span = span.into(); RawExpression::Literal(RawLiteral::Size(i.into(), unit.into()).into_literal(span)) .into_expr(span) } - pub(crate) fn synthetic_string(s: impl Into) -> Expression { + pub fn synthetic_string(s: impl Into) -> Expression { RawExpression::Synthetic(Synthetic::String(s.into())).into_unspanned_expr() } - pub(crate) fn string(inner: impl Into, outer: impl Into) -> Expression { + pub fn string(inner: impl Into, outer: impl Into) -> Expression { let outer = outer.into(); RawExpression::Literal(RawLiteral::String(inner.into()).into_literal(outer)) .into_expr(outer) } - pub(crate) fn column_path(members: Vec, span: impl Into) -> Expression { + pub fn column_path(members: Vec, span: impl Into) -> Expression { let span = span.into(); RawExpression::Literal(RawLiteral::ColumnPath(members).into_literal(span)).into_expr(span) } - pub(crate) fn path( + pub fn path( head: Expression, tail: Vec>, span: impl Into, @@ -239,7 +225,7 @@ impl Expression { RawExpression::Path(Box::new(Path::new(head, tail))).into_expr(span.into()) } - pub(crate) fn dot_member(head: Expression, next: impl Into) -> Expression { + pub fn dot_member(head: Expression, next: impl Into) -> Expression { let Expression { expr: item, span } = head; let next = next.into(); @@ -257,7 +243,7 @@ impl Expression { } } - pub(crate) fn infix( + pub fn infix( left: Expression, op: Spanned>, right: Expression, @@ -268,36 +254,36 @@ impl Expression { .into_expr(new_span) } - pub(crate) fn file_path(path: impl Into, outer: impl Into) -> Expression { + pub fn file_path(path: impl Into, outer: impl Into) -> Expression { RawExpression::FilePath(path.into()).into_expr(outer) } - pub(crate) fn list(list: Vec, span: impl Into) -> Expression { + pub fn list(list: Vec, span: impl Into) -> Expression { RawExpression::List(list).into_expr(span) } - pub(crate) fn bare(span: impl Into) -> Expression { + pub fn bare(span: impl Into) -> Expression { let span = span.into(); RawExpression::Literal(RawLiteral::Bare.into_literal(span)).into_expr(span) } - pub(crate) fn pattern(inner: impl Into, outer: impl Into) -> Expression { + pub fn pattern(inner: impl Into, outer: impl Into) -> Expression { let outer = outer.into(); RawExpression::Literal(RawLiteral::GlobPattern(inner.into()).into_literal(outer)) .into_expr(outer) } - pub(crate) fn variable(inner: impl Into, outer: impl Into) -> Expression { + pub fn variable(inner: impl Into, outer: impl Into) -> Expression { RawExpression::Variable(Variable::Other(inner.into())).into_expr(outer) } - pub(crate) fn external_command(inner: impl Into, outer: impl Into) -> Expression { + pub fn external_command(inner: impl Into, outer: impl Into) -> Expression { RawExpression::ExternalCommand(ExternalCommand::new(inner.into())).into_expr(outer) } - pub(crate) fn it_variable(inner: impl Into, outer: impl Into) -> Expression { + pub fn it_variable(inner: impl Into, outer: impl Into) -> Expression { RawExpression::Variable(Variable::It(inner.into())).into_expr(outer) } } diff --git a/src/parser/hir/baseline_parse.rs b/crates/nu-parser/src/hir/baseline_parse.rs similarity index 100% rename from src/parser/hir/baseline_parse.rs rename to crates/nu-parser/src/hir/baseline_parse.rs diff --git a/src/parser/hir/baseline_parse/tests.rs b/crates/nu-parser/src/hir/baseline_parse/tests.rs similarity index 62% rename from src/parser/hir/baseline_parse/tests.rs rename to crates/nu-parser/src/hir/baseline_parse/tests.rs index 16120a5507..216be656b8 100644 --- a/src/parser/hir/baseline_parse/tests.rs +++ b/crates/nu-parser/src/hir/baseline_parse/tests.rs @@ -1,13 +1,13 @@ -use crate::commands::classified::InternalCommand; -use crate::commands::ClassifiedCommand; -use crate::env::host::BasicHost; -use crate::parser::hir::TokensIterator; -use crate::parser::hir::{ - self, named::NamedValue, path::PathMember, syntax_shape::*, NamedArguments, -}; -use crate::parser::parse::token_tree_builder::{CurriedToken, TokenTreeBuilder as b}; -use crate::parser::TokenNode; +use crate::commands::classified::{ClassifiedCommand, InternalCommand}; +use crate::hir::TokensIterator; +use crate::hir::{self, named::NamedValue, syntax_shape::*, NamedArguments}; +use crate::parse::files::Files; +use crate::parse::token_tree_builder::{CurriedToken, TokenTreeBuilder as b}; +use crate::TokenNode; +use derive_new::new; use indexmap::IndexMap; +use nu_errors::ShellError; +use nu_protocol::{PathMember, Signature, SyntaxShape}; use nu_source::{HasSpan, Span, Tag, Text}; use pretty_assertions::assert_eq; use std::fmt::Debug; @@ -90,6 +90,43 @@ fn test_parse_command() { ); } +#[derive(new)] +struct TestRegistry { + #[new(default)] + signatures: indexmap::IndexMap, +} + +impl TestRegistry { + fn insert(&mut self, key: &str, value: Signature) { + self.signatures.insert(key.to_string(), value); + } +} + +impl SignatureRegistry for TestRegistry { + fn has(&self, name: &str) -> bool { + self.signatures.contains_key(name) + } + fn get(&self, name: &str) -> Option { + self.signatures.get(name).map(|sig| sig.clone()) + } +} + +fn with_empty_context(source: &Text, callback: impl FnOnce(ExpandContext)) { + let mut registry = TestRegistry::new(); + registry.insert( + "ls", + Signature::build("ls") + .optional( + "path", + SyntaxShape::Pattern, + "a path to get the directory contents from", + ) + .switch("full", "list all available columns for each entry"), + ); + + callback(ExpandContext::new(Box::new(registry), source, None)) +} + fn parse_tokens( shape: impl ExpandSyntax, tokens: Vec, @@ -99,7 +136,7 @@ fn parse_tokens( let (tokens, source) = b::build(tokens); let text = Text::from(source); - ExpandContext::with_empty(&text, |context| { + with_empty_context(&text, |context| { let tokens = tokens.expect_list(); let mut iterator = TokensIterator::all(tokens.item, text.clone(), tokens.span); @@ -108,7 +145,7 @@ fn parse_tokens( let expr = match expr { Ok(expr) => expr, Err(err) => { - crate::cli::print_err(err.into(), &BasicHost, context.source().clone()); + print_err(err.into(), context.source().clone()); panic!("Parse failed"); } }; @@ -120,3 +157,20 @@ fn parse_tokens( fn inner_string_span(span: Span) -> Span { Span::new(span.start() + 1, span.end() - 1) } + +pub fn print_err(err: ShellError, source: &Text) { + let diag = err.to_diagnostic(); + + let writer = termcolor::StandardStream::stderr(termcolor::ColorChoice::Auto); + let mut source = source.to_string(); + source.push_str(" "); + let files = Files::new(source); + let _ = std::panic::catch_unwind(move || { + let _ = language_reporting::emit( + &mut writer.lock(), + &files, + &diag, + &language_reporting::DefaultConfig, + ); + }); +} diff --git a/src/parser/hir/binary.rs b/crates/nu-parser/src/hir/binary.rs similarity index 84% rename from src/parser/hir/binary.rs rename to crates/nu-parser/src/hir/binary.rs index 4a119cb4f1..47148fa6d8 100644 --- a/src/parser/hir/binary.rs +++ b/crates/nu-parser/src/hir/binary.rs @@ -1,15 +1,14 @@ -use crate::parser::{hir::Expression, Operator}; -use crate::prelude::*; +use crate::{hir::Expression, Operator}; use derive_new::new; use getset::Getters; -use nu_source::Spanned; +use nu_source::{b, DebugDocBuilder, PrettyDebugWithSource, Spanned}; use serde::{Deserialize, Serialize}; #[derive( Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Getters, Serialize, Deserialize, new, )] -#[get = "pub(crate)"] +#[get = "pub"] pub struct Binary { left: Expression, op: Spanned, diff --git a/src/parser/hir/expand_external_tokens.rs b/crates/nu-parser/src/hir/expand_external_tokens.rs similarity index 99% rename from src/parser/hir/expand_external_tokens.rs rename to crates/nu-parser/src/hir/expand_external_tokens.rs index c0c3d8eaa7..99232bd9c6 100644 --- a/src/parser/hir/expand_external_tokens.rs +++ b/crates/nu-parser/src/hir/expand_external_tokens.rs @@ -1,7 +1,6 @@ -use crate::errors::ParseError; #[cfg(not(coloring_in_tokens))] -use crate::parser::hir::syntax_shape::FlatShape; -use crate::parser::{ +use crate::hir::syntax_shape::FlatShape; +use crate::{ hir::syntax_shape::{ color_syntax, expand_atom, expand_expr, expand_syntax, AtomicToken, ColorSyntax, ExpandContext, ExpandExpression, ExpandSyntax, ExpansionRule, MaybeSpaceShape, @@ -10,6 +9,7 @@ use crate::parser::{ hir::Expression, TokensIterator, }; +use nu_errors::ParseError; use nu_source::{b, DebugDocBuilder, HasSpan, PrettyDebug, Span, Spanned, SpannedItem}; #[derive(Debug, Clone)] diff --git a/src/parser/hir/external_command.rs b/crates/nu-parser/src/hir/external_command.rs similarity index 84% rename from src/parser/hir/external_command.rs rename to crates/nu-parser/src/hir/external_command.rs index 7174a12a73..a07257d063 100644 --- a/src/parser/hir/external_command.rs +++ b/crates/nu-parser/src/hir/external_command.rs @@ -1,12 +1,12 @@ -use crate::prelude::*; use derive_new::new; use getset::Getters; +use nu_source::Span; use serde::{Deserialize, Serialize}; #[derive( Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Getters, Serialize, Deserialize, new, )] -#[get = "pub(crate)"] +#[get = "pub"] pub struct ExternalCommand { pub(crate) name: Span, } diff --git a/src/parser/hir/named.rs b/crates/nu-parser/src/hir/named.rs similarity index 89% rename from src/parser/hir/named.rs rename to crates/nu-parser/src/hir/named.rs index 09e12e8723..a30fdac7ea 100644 --- a/src/parser/hir/named.rs +++ b/crates/nu-parser/src/hir/named.rs @@ -1,8 +1,8 @@ -use crate::parser::hir::Expression; -use crate::parser::Flag; -use crate::prelude::*; +use crate::hir::Expression; +use crate::Flag; use indexmap::IndexMap; use log::trace; +use nu_source::{b, DebugDocBuilder, PrettyDebugWithSource, Tag}; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] @@ -26,7 +26,7 @@ impl PrettyDebugWithSource for NamedValue { #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub struct NamedArguments { - pub(crate) named: IndexMap, + pub named: IndexMap, } impl NamedArguments { @@ -35,6 +35,10 @@ impl NamedArguments { named: IndexMap::new(), } } + + pub fn iter(&self) -> impl Iterator { + self.named.iter() + } } impl NamedArguments { diff --git a/crates/nu-parser/src/hir/path.rs b/crates/nu-parser/src/hir/path.rs new file mode 100644 index 0000000000..7930e0fb77 --- /dev/null +++ b/crates/nu-parser/src/hir/path.rs @@ -0,0 +1,41 @@ +use crate::hir::Expression; +use derive_new::new; +use getset::{Getters, MutGetters}; +use nu_protocol::PathMember; +use nu_source::{b, DebugDocBuilder, PrettyDebug, PrettyDebugWithSource}; +use serde::{Deserialize, Serialize}; + +#[derive( + Debug, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + Getters, + MutGetters, + Serialize, + Deserialize, + new, +)] +#[get = "pub"] +pub struct Path { + head: Expression, + #[get_mut = "pub(crate)"] + tail: Vec, +} + +impl PrettyDebugWithSource for Path { + fn pretty_debug(&self, source: &str) -> DebugDocBuilder { + self.head.pretty_debug(source) + + b::operator(".") + + b::intersperse(self.tail.iter().map(|m| m.pretty()), b::operator(".")) + } +} + +impl Path { + pub(crate) fn parts(self) -> (Expression, Vec) { + (self.head, self.tail) + } +} diff --git a/src/parser/hir/syntax_shape.rs b/crates/nu-parser/src/hir/syntax_shape.rs similarity index 94% rename from src/parser/hir/syntax_shape.rs rename to crates/nu-parser/src/hir/syntax_shape.rs index 8d78c87160..98483eb1ad 100644 --- a/src/parser/hir/syntax_shape.rs +++ b/crates/nu-parser/src/hir/syntax_shape.rs @@ -1,23 +1,25 @@ mod block; mod expression; -pub(crate) mod flat_shape; +pub mod flat_shape; -use crate::cli::external_command; -use crate::commands::{ - classified::{ClassifiedPipeline, InternalCommand}, - ClassifiedCommand, Command, -}; -use crate::parser::hir::expand_external_tokens::ExternalTokensShape; -use crate::parser::hir::syntax_shape::block::AnyBlockShape; -use crate::parser::hir::tokens_iterator::Peeked; -use crate::parser::parse::tokens::Token; -use crate::parser::parse_command::{parse_command_tail, CommandTailShape}; -use crate::parser::{hir, hir::TokensIterator, Operator, TokenNode, UnspannedToken}; -use crate::prelude::*; +use crate::commands::classified::{ClassifiedCommand, ClassifiedPipeline, InternalCommand}; +use crate::commands::external_command; +use crate::hir; +use crate::hir::expand_external_tokens::ExternalTokensShape; +use crate::hir::syntax_shape::block::AnyBlockShape; +use crate::hir::tokens_iterator::{Peeked, TokensIterator}; +use crate::parse::operator::Operator; +use crate::parse::token_tree::TokenNode; +use crate::parse::tokens::{Token, UnspannedToken}; +use crate::parse_command::{parse_command_tail, CommandTailShape}; use derive_new::new; use getset::Getters; -use nu_source::Spanned; -use serde::{Deserialize, Serialize}; +use nu_errors::{ParseError, ShellError}; +use nu_protocol::{ShellTypeName, Signature}; +use nu_source::{ + b, DebugDocBuilder, HasFallibleSpan, HasSpan, PrettyDebug, PrettyDebugWithSource, Span, + Spanned, SpannedItem, Tag, TaggedItem, Text, +}; use std::path::{Path, PathBuf}; pub(crate) use self::expression::atom::{ @@ -41,40 +43,12 @@ pub(crate) use self::expression::{continue_expression, AnyExpressionShape}; pub(crate) use self::flat_shape::FlatShape; #[cfg(not(coloring_in_tokens))] -use crate::parser::hir::tokens_iterator::debug::debug_tokens; +use crate::hir::tokens_iterator::debug::debug_tokens; #[cfg(not(coloring_in_tokens))] -use crate::parser::parse::pipeline::Pipeline; +use crate::parse::pipeline::Pipeline; #[cfg(not(coloring_in_tokens))] use log::{log_enabled, trace}; - -#[derive(Debug, Copy, Clone, Serialize, Deserialize)] -pub enum SyntaxShape { - Any, - String, - Member, - ColumnPath, - Number, - Int, - Path, - Pattern, - Block, -} - -impl PrettyDebug for SyntaxShape { - fn pretty(&self) -> DebugDocBuilder { - b::kind(match self { - SyntaxShape::Any => "any shape", - SyntaxShape::String => "string shape", - SyntaxShape::Member => "member shape", - SyntaxShape::ColumnPath => "column path shape", - SyntaxShape::Number => "number shape", - SyntaxShape::Int => "integer shape", - SyntaxShape::Path => "file path shape", - SyntaxShape::Pattern => "pattern shape", - SyntaxShape::Block => "block shape", - }) - } -} +use nu_protocol::SyntaxShape; #[cfg(not(coloring_in_tokens))] impl FallibleColorSyntax for SyntaxShape { @@ -200,10 +174,15 @@ impl ExpandExpression for SyntaxShape { } } +pub trait SignatureRegistry { + fn has(&self, name: &str) -> bool; + fn get(&self, name: &str) -> Option; +} + #[derive(Getters, new)] pub struct ExpandContext<'context> { #[get = "pub(crate)"] - registry: &'context CommandRegistry, + registry: Box, #[get = "pub(crate)"] source: &'context Text, homedir: Option, @@ -213,21 +192,6 @@ impl<'context> ExpandContext<'context> { pub(crate) fn homedir(&self) -> Option<&Path> { self.homedir.as_ref().map(|h| h.as_path()) } - - #[cfg(test)] - pub fn with_empty(source: &Text, callback: impl FnOnce(ExpandContext)) { - let mut registry = CommandRegistry::new(); - registry.insert( - "ls", - crate::commands::whole_stream_command(crate::commands::LS), - ); - - callback(ExpandContext { - registry: ®istry, - source, - homedir: None, - }) - } } pub trait TestSyntax: std::fmt::Debug + Copy { @@ -306,7 +270,7 @@ pub trait ColorSyntax: std::fmt::Debug + Copy { ) -> Self::Info; } -pub(crate) trait ExpandSyntax: std::fmt::Debug + Copy { +pub trait ExpandSyntax: std::fmt::Debug + Copy { type Output: HasFallibleSpan + Clone + std::fmt::Debug + 'static; fn name(&self) -> &'static str; @@ -318,7 +282,7 @@ pub(crate) trait ExpandSyntax: std::fmt::Debug + Copy { ) -> Result; } -pub(crate) fn expand_syntax<'a, 'b, T: ExpandSyntax>( +pub fn expand_syntax<'a, 'b, T: ExpandSyntax>( shape: &T, token_nodes: &'b mut TokensIterator<'a>, context: &ExpandContext, @@ -747,7 +711,7 @@ impl TestSyntax for BareShape { #[derive(Debug, Clone)] pub enum CommandSignature { - Internal(Spanned>), + Internal(Spanned), LiteralExternal { outer: Span, inner: Span }, External(Span), Expression(hir::Expression), @@ -757,7 +721,7 @@ impl PrettyDebugWithSource for CommandSignature { fn pretty_debug(&self, source: &str) -> DebugDocBuilder { match self { CommandSignature::Internal(internal) => { - b::typed("command", b::description(internal.name())) + b::typed("command", b::description(&internal.name)) } CommandSignature::LiteralExternal { outer, .. } => { b::typed("command", b::description(outer.slice(source))) @@ -1003,8 +967,8 @@ impl FallibleColorSyntax for CommandHeadShape { if context.registry.has(name) { // If the registry has the command, color it as an internal command shapes.push(FlatShape::InternalCommand.spanned(text)); - let command = context.registry.expect_command(name); - Ok(CommandHeadKind::Internal(command.signature())) + let signature = context.registry.get(name).unwrap(); + Ok(CommandHeadKind::Internal(signature)) } else { // Otherwise, color it as an external command shapes.push(FlatShape::ExternalCommand.spanned(text)); @@ -1060,8 +1024,8 @@ impl FallibleColorSyntax for CommandHeadShape { if context.registry.has(name) { // If the registry has the command, color it as an internal command token_nodes.color_shape(FlatShape::InternalCommand.spanned(text)); - let command = context.registry.expect_command(name); - Ok(CommandHeadKind::Internal(command.signature())) + let signature = context.registry.get(name).unwrap(); + Ok(CommandHeadKind::Internal(signature)) } else { // Otherwise, color it as an external command token_nodes.color_shape(FlatShape::ExternalCommand.spanned(text)); @@ -1100,8 +1064,8 @@ impl ExpandSyntax for CommandHeadShape { UnspannedToken::Bare => { let name = token_span.slice(context.source); if context.registry.has(name) { - let command = context.registry.expect_command(name); - CommandSignature::Internal(command.spanned(token_span)) + let signature = context.registry.get(name).unwrap(); + CommandSignature::Internal(signature.spanned(token_span)) } else { CommandSignature::External(token_span) } @@ -1162,9 +1126,8 @@ impl ExpandSyntax for ClassifiedCommandShape { external_command(iterator, context, name_str.tagged(outer)) } - CommandSignature::Internal(command) => { - let tail = - parse_command_tail(&command.signature(), &context, iterator, command.span)?; + CommandSignature::Internal(signature) => { + let tail = parse_command_tail(&signature.item, &context, iterator, signature.span)?; let (positional, named) = match tail { None => (None, None), @@ -1181,9 +1144,9 @@ impl ExpandSyntax for ClassifiedCommandShape { }; Ok(ClassifiedCommand::Internal(InternalCommand::new( - command.item.name().to_string(), + signature.item.name.clone(), Tag { - span: command.span, + span: signature.span, anchor: None, }, call, diff --git a/src/parser/hir/syntax_shape/block.rs b/crates/nu-parser/src/hir/syntax_shape/block.rs similarity index 98% rename from src/parser/hir/syntax_shape/block.rs rename to crates/nu-parser/src/hir/syntax_shape/block.rs index 927133ebad..4a8f0aa9ac 100644 --- a/src/parser/hir/syntax_shape/block.rs +++ b/crates/nu-parser/src/hir/syntax_shape/block.rs @@ -1,17 +1,17 @@ -use crate::errors::ShellError; #[cfg(not(coloring_in_tokens))] -use crate::parser::hir::syntax_shape::FlatShape; -use crate::parser::{ +use crate::hir::syntax_shape::FlatShape; +use crate::{ hir, hir::syntax_shape::{ color_fallible_syntax, color_syntax_with, continue_expression, expand_expr, expand_syntax, DelimitedShape, ExpandContext, ExpandExpression, ExpressionContinuationShape, - ExpressionListShape, FallibleColorSyntax, MemberShape, ParseError, PathTailShape, - PathTailSyntax, VariablePathShape, + ExpressionListShape, FallibleColorSyntax, MemberShape, PathTailShape, PathTailSyntax, + VariablePathShape, }, hir::tokens_iterator::TokensIterator, parse::token_tree::Delimiter, }; +use nu_errors::{ParseError, ShellError}; use nu_source::Span; #[cfg(not(coloring_in_tokens))] use nu_source::Spanned; @@ -388,8 +388,8 @@ impl FallibleColorSyntax for ShorthandHeadShape { _context: &ExpandContext, shapes: &mut Vec>, ) -> Result<(), ShellError> { - use crate::parser::parse::token_tree::TokenNode; - use crate::parser::parse::tokens::{Token, UnspannedToken}; + use crate::parse::token_tree::TokenNode; + use crate::parse::tokens::{Token, UnspannedToken}; use nu_source::SpannedItem; // A shorthand path must not be at EOF diff --git a/src/parser/hir/syntax_shape/expression.rs b/crates/nu-parser/src/hir/syntax_shape/expression.rs similarity index 98% rename from src/parser/hir/syntax_shape/expression.rs rename to crates/nu-parser/src/hir/syntax_shape/expression.rs index 65760e6e65..4c7dfd3db6 100644 --- a/src/parser/hir/syntax_shape/expression.rs +++ b/crates/nu-parser/src/hir/syntax_shape/expression.rs @@ -8,18 +8,18 @@ pub(crate) mod string; pub(crate) mod unit; pub(crate) mod variable_path; -use crate::parser::hir::syntax_shape::{ +use crate::hir::syntax_shape::{ color_delimited_square, color_fallible_syntax, color_fallible_syntax_with, expand_atom, expand_delimited_square, expand_expr, expand_syntax, BareShape, ColorableDotShape, DotShape, ExpandContext, ExpandExpression, ExpandSyntax, ExpansionRule, ExpressionContinuation, - ExpressionContinuationShape, FallibleColorSyntax, FlatShape, ParseError, UnspannedAtomicToken, + ExpressionContinuationShape, FallibleColorSyntax, FlatShape, UnspannedAtomicToken, }; -use crate::parser::{ +use crate::{ hir, hir::{Expression, TokensIterator}, }; -use crate::prelude::*; -use nu_source::Spanned; +use nu_errors::{ParseError, ShellError}; +use nu_source::{HasSpan, Span, Spanned, SpannedItem, Tag}; use std::path::PathBuf; #[derive(Debug, Copy, Clone)] diff --git a/src/parser/hir/syntax_shape/expression/atom.rs b/crates/nu-parser/src/hir/syntax_shape/expression/atom.rs similarity index 98% rename from src/parser/hir/syntax_shape/expression/atom.rs rename to crates/nu-parser/src/hir/syntax_shape/expression/atom.rs index 76b264b1ed..6fe8a992ac 100644 --- a/src/parser/hir/syntax_shape/expression/atom.rs +++ b/crates/nu-parser/src/hir/syntax_shape/expression/atom.rs @@ -1,15 +1,19 @@ -use crate::parser::hir::syntax_shape::{ +use crate::hir::syntax_shape::FlatShape; +use crate::hir::syntax_shape::{ expand_syntax, expression::expand_file_path, parse_single_node, BarePathShape, BarePatternShape, ExpandContext, UnitShape, UnitSyntax, }; -use crate::parser::{ +use crate::parse::token_tree::{DelimitedNode, Delimiter, TokenNode}; +use crate::parse::tokens::UnspannedToken; +use crate::parse::unit::Unit; +use crate::{ hir, hir::{Expression, RawNumber, TokensIterator}, parse::flag::{Flag, FlagKind}, - DelimitedNode, Delimiter, FlatShape, TokenNode, Unit, UnspannedToken, }; -use crate::prelude::*; -use nu_source::Spanned; +use nu_errors::{ParseError, ShellError}; +use nu_protocol::ShellTypeName; +use nu_source::{b, DebugDocBuilder, HasSpan, PrettyDebugWithSource, Span, Spanned, SpannedItem}; use std::ops::Deref; #[derive(Debug, Clone)] diff --git a/src/parser/hir/syntax_shape/expression/delimited.rs b/crates/nu-parser/src/hir/syntax_shape/expression/delimited.rs similarity index 94% rename from src/parser/hir/syntax_shape/expression/delimited.rs rename to crates/nu-parser/src/hir/syntax_shape/expression/delimited.rs index e92c179bd9..4d84e521e9 100644 --- a/src/parser/hir/syntax_shape/expression/delimited.rs +++ b/crates/nu-parser/src/hir/syntax_shape/expression/delimited.rs @@ -1,10 +1,11 @@ -use crate::parser::hir::syntax_shape::{ +use crate::hir::syntax_shape::{ color_syntax, expand_syntax, ColorSyntax, ExpandContext, ExpressionListShape, TokenNode, }; -use crate::parser::{hir, hir::TokensIterator, Delimiter, FlatShape}; -use crate::prelude::*; +use crate::{hir, hir::TokensIterator, Delimiter, FlatShape}; +use nu_errors::ParseError; #[cfg(not(coloring_in_tokens))] use nu_source::Spanned; +use nu_source::{Span, SpannedItem, Tag}; pub fn expand_delimited_square( children: &Vec, diff --git a/src/parser/hir/syntax_shape/expression/file_path.rs b/crates/nu-parser/src/hir/syntax_shape/expression/file_path.rs similarity index 94% rename from src/parser/hir/syntax_shape/expression/file_path.rs rename to crates/nu-parser/src/hir/syntax_shape/expression/file_path.rs index 337d2240ce..0fca4a6c2c 100644 --- a/src/parser/hir/syntax_shape/expression/file_path.rs +++ b/crates/nu-parser/src/hir/syntax_shape/expression/file_path.rs @@ -1,12 +1,12 @@ -use crate::parser::hir::syntax_shape::expression::atom::{ +use crate::hir::syntax_shape::expression::atom::{ expand_atom, ExpansionRule, UnspannedAtomicToken, }; -use crate::parser::hir::syntax_shape::{ +use crate::hir::syntax_shape::{ expression::expand_file_path, ExpandContext, ExpandExpression, FallibleColorSyntax, FlatShape, - ParseError, }; -use crate::parser::{hir, hir::TokensIterator}; -use crate::prelude::*; +use crate::{hir, hir::TokensIterator}; +use nu_errors::{ParseError, ShellError}; +use nu_source::SpannedItem; #[derive(Debug, Copy, Clone)] pub struct FilePathShape; diff --git a/src/parser/hir/syntax_shape/expression/list.rs b/crates/nu-parser/src/hir/syntax_shape/expression/list.rs similarity index 99% rename from src/parser/hir/syntax_shape/expression/list.rs rename to crates/nu-parser/src/hir/syntax_shape/expression/list.rs index 88c6f6e62f..d7066027a2 100644 --- a/src/parser/hir/syntax_shape/expression/list.rs +++ b/crates/nu-parser/src/hir/syntax_shape/expression/list.rs @@ -1,7 +1,6 @@ -use crate::errors::ParseError; #[cfg(not(coloring_in_tokens))] -use crate::parser::hir::syntax_shape::FlatShape; -use crate::parser::{ +use crate::hir::syntax_shape::FlatShape; +use crate::{ hir, hir::syntax_shape::{ color_fallible_syntax, color_syntax, expand_atom, expand_expr, maybe_spaced, spaced, @@ -10,6 +9,7 @@ use crate::parser::{ }, hir::TokensIterator, }; +use nu_errors::ParseError; use nu_source::{b, DebugDocBuilder, HasSpan, PrettyDebugWithSource, Span, Spanned, SpannedItem}; #[derive(Debug, Clone)] diff --git a/src/parser/hir/syntax_shape/expression/number.rs b/crates/nu-parser/src/hir/syntax_shape/expression/number.rs similarity index 96% rename from src/parser/hir/syntax_shape/expression/number.rs rename to crates/nu-parser/src/hir/syntax_shape/expression/number.rs index c4fce3a36a..ed95439ce2 100644 --- a/src/parser/hir/syntax_shape/expression/number.rs +++ b/crates/nu-parser/src/hir/syntax_shape/expression/number.rs @@ -1,15 +1,15 @@ -use crate::parser::hir::syntax_shape::{ +use crate::hir::syntax_shape::{ expand_atom, parse_single_node, ExpandContext, ExpandExpression, ExpansionRule, - FallibleColorSyntax, FlatShape, ParseError, TestSyntax, + FallibleColorSyntax, FlatShape, TestSyntax, }; -use crate::parser::hir::tokens_iterator::Peeked; -use crate::parser::{ +use crate::hir::tokens_iterator::Peeked; +use crate::parse::tokens::UnspannedToken; +use crate::{ hir, hir::{RawNumber, TokensIterator}, - UnspannedToken, }; -use crate::prelude::*; -use nu_source::Spanned; +use nu_errors::{ParseError, ShellError}; +use nu_source::{Spanned, SpannedItem}; #[derive(Debug, Copy, Clone)] pub struct NumberShape; diff --git a/src/parser/hir/syntax_shape/expression/pattern.rs b/crates/nu-parser/src/hir/syntax_shape/expression/pattern.rs similarity index 92% rename from src/parser/hir/syntax_shape/expression/pattern.rs rename to crates/nu-parser/src/hir/syntax_shape/expression/pattern.rs index 3d11f16652..02fa0ed687 100644 --- a/src/parser/hir/syntax_shape/expression/pattern.rs +++ b/crates/nu-parser/src/hir/syntax_shape/expression/pattern.rs @@ -1,12 +1,15 @@ -use crate::parser::hir::syntax_shape::{ +use crate::hir::syntax_shape::{ expand_atom, expand_bare, expression::expand_file_path, ExpandContext, ExpandExpression, - ExpandSyntax, ExpansionRule, FallibleColorSyntax, FlatShape, ParseError, UnspannedAtomicToken, + ExpandSyntax, ExpansionRule, FallibleColorSyntax, FlatShape, UnspannedAtomicToken, }; -use crate::parser::parse::tokens::Token; -use crate::parser::{hir, hir::TokensIterator, Operator, TokenNode, UnspannedToken}; -use crate::prelude::*; +use crate::parse::tokens::{Token, UnspannedToken}; +use crate::{hir, hir::TokensIterator, Operator, TokenNode}; +use nu_errors::{ParseError, ShellError}; +#[cfg(coloring_in_tokens)] +use nu_protocol::ShellTypeName; #[cfg(not(coloring_in_tokens))] use nu_source::Spanned; +use nu_source::{Span, SpannedItem}; #[derive(Debug, Copy, Clone)] pub struct PatternShape; diff --git a/src/parser/hir/syntax_shape/expression/string.rs b/crates/nu-parser/src/hir/syntax_shape/expression/string.rs similarity index 91% rename from src/parser/hir/syntax_shape/expression/string.rs rename to crates/nu-parser/src/hir/syntax_shape/expression/string.rs index b6dbb2769f..caf9b0abad 100644 --- a/src/parser/hir/syntax_shape/expression/string.rs +++ b/crates/nu-parser/src/hir/syntax_shape/expression/string.rs @@ -1,12 +1,14 @@ -use crate::parser::hir::syntax_shape::{ +use crate::hir::syntax_shape::{ expand_atom, expand_variable, parse_single_node, AtomicToken, ExpandContext, ExpandExpression, - ExpansionRule, FallibleColorSyntax, FlatShape, ParseError, TestSyntax, UnspannedAtomicToken, + ExpansionRule, FallibleColorSyntax, FlatShape, TestSyntax, UnspannedAtomicToken, }; -use crate::parser::hir::tokens_iterator::Peeked; -use crate::parser::{hir, hir::TokensIterator, UnspannedToken}; -use crate::prelude::*; +use crate::hir::tokens_iterator::Peeked; +use crate::parse::tokens::UnspannedToken; +use crate::{hir, hir::TokensIterator}; +use nu_errors::{ParseError, ShellError}; #[cfg(not(coloring_in_tokens))] use nu_source::Spanned; +use nu_source::SpannedItem; #[derive(Debug, Copy, Clone)] pub struct StringShape; diff --git a/src/parser/hir/syntax_shape/expression/unit.rs b/crates/nu-parser/src/hir/syntax_shape/expression/unit.rs similarity index 89% rename from src/parser/hir/syntax_shape/expression/unit.rs rename to crates/nu-parser/src/hir/syntax_shape/expression/unit.rs index 0c500583d8..44738f1075 100644 --- a/src/parser/hir/syntax_shape/expression/unit.rs +++ b/crates/nu-parser/src/hir/syntax_shape/expression/unit.rs @@ -1,15 +1,16 @@ -use crate::parser::hir::syntax_shape::{ExpandContext, ExpandSyntax, ParseError}; -use crate::parser::parse::tokens::RawNumber; -use crate::parser::parse::tokens::Token; -use crate::parser::parse::unit::Unit; -use crate::parser::{hir::TokensIterator, TokenNode, UnspannedToken}; -use crate::prelude::*; +use crate::hir::syntax_shape::{ExpandContext, ExpandSyntax}; +use crate::parse::tokens::RawNumber; +use crate::parse::tokens::Token; +use crate::parse::tokens::UnspannedToken; +use crate::parse::unit::Unit; +use crate::{hir::TokensIterator, TokenNode}; use nom::branch::alt; use nom::bytes::complete::tag; use nom::character::complete::digit1; use nom::combinator::{all_consuming, opt, value}; use nom::IResult; -use nu_source::{Span, Spanned}; +use nu_errors::ParseError; +use nu_source::{b, DebugDocBuilder, HasSpan, PrettyDebugWithSource, Span, Spanned, SpannedItem}; #[derive(Debug, Clone)] pub struct UnitSyntax { diff --git a/src/parser/hir/syntax_shape/expression/variable_path.rs b/crates/nu-parser/src/hir/syntax_shape/expression/variable_path.rs similarity index 98% rename from src/parser/hir/syntax_shape/expression/variable_path.rs rename to crates/nu-parser/src/hir/syntax_shape/expression/variable_path.rs index 52ef946402..2f075a9d6f 100644 --- a/src/parser/hir/syntax_shape/expression/variable_path.rs +++ b/crates/nu-parser/src/hir/syntax_shape/expression/variable_path.rs @@ -1,16 +1,19 @@ -use crate::parser::hir::path::PathMember; -use crate::parser::hir::syntax_shape::{ +use crate::hir::syntax_shape::{ color_fallible_syntax, color_fallible_syntax_with, expand_atom, expand_expr, expand_syntax, parse_single_node, AnyExpressionShape, BareShape, ExpandContext, ExpandExpression, ExpandSyntax, ExpansionRule, FallibleColorSyntax, FlatShape, ParseError, Peeked, SkipSyntax, StringShape, TestSyntax, UnspannedAtomicToken, WhitespaceShape, }; -use crate::parser::{ - hir, hir::Expression, hir::TokensIterator, Operator, RawNumber, UnspannedToken, +use crate::parse::tokens::{RawNumber, UnspannedToken}; +use crate::{hir, hir::Expression, hir::TokensIterator, Operator}; +use nu_errors::ShellError; +use nu_protocol::{PathMember, ShellTypeName}; +use nu_source::{ + b, DebugDocBuilder, HasSpan, PrettyDebug, PrettyDebugWithSource, Span, Spanned, SpannedItem, + Tag, Tagged, TaggedItem, Text, }; -use crate::prelude::*; -use nu_source::{Spanned, Tagged}; -use serde::Serialize; +use num_bigint::BigInt; +use serde::{Deserialize, Serialize}; use std::str::FromStr; #[derive(Debug, Copy, Clone)] diff --git a/src/parser/hir/syntax_shape/flat_shape.rs b/crates/nu-parser/src/hir/syntax_shape/flat_shape.rs similarity index 95% rename from src/parser/hir/syntax_shape/flat_shape.rs rename to crates/nu-parser/src/hir/syntax_shape/flat_shape.rs index af34524ce7..2f2c865652 100644 --- a/src/parser/hir/syntax_shape/flat_shape.rs +++ b/crates/nu-parser/src/hir/syntax_shape/flat_shape.rs @@ -1,4 +1,7 @@ -use crate::parser::{Delimiter, Flag, FlagKind, Operator, RawNumber, TokenNode, UnspannedToken}; +use crate::parse::flag::{Flag, FlagKind}; +use crate::parse::operator::Operator; +use crate::parse::token_tree::{Delimiter, TokenNode}; +use crate::parse::tokens::{RawNumber, UnspannedToken}; use nu_source::{HasSpan, Span, Spanned, SpannedItem, Text}; #[derive(Debug, Copy, Clone)] diff --git a/src/parser/hir/tokens_iterator.rs b/crates/nu-parser/src/hir/tokens_iterator.rs similarity index 99% rename from src/parser/hir/tokens_iterator.rs rename to crates/nu-parser/src/hir/tokens_iterator.rs index 9cee23647a..49ddd25a9b 100644 --- a/src/parser/hir/tokens_iterator.rs +++ b/crates/nu-parser/src/hir/tokens_iterator.rs @@ -1,15 +1,14 @@ pub(crate) mod debug; use self::debug::{ColorTracer, ExpandTracer}; -use crate::errors::ShellError; #[cfg(coloring_in_tokens)] -use crate::parser::hir::syntax_shape::FlatShape; -use crate::parser::hir::Expression; -use crate::parser::TokenNode; -use crate::prelude::*; +use crate::hir::syntax_shape::FlatShape; +use crate::hir::Expression; +use crate::TokenNode; #[allow(unused)] use getset::{Getters, MutGetters}; -use nu_source::Spanned; +use nu_errors::{ParseError, ShellError}; +use nu_source::{HasFallibleSpan, HasSpan, Span, Spanned, SpannedItem, Tag, Text}; cfg_if::cfg_if! { if #[cfg(coloring_in_tokens)] { diff --git a/src/parser/hir/tokens_iterator/debug.rs b/crates/nu-parser/src/hir/tokens_iterator/debug.rs similarity index 93% rename from src/parser/hir/tokens_iterator/debug.rs rename to crates/nu-parser/src/hir/tokens_iterator/debug.rs index 14574ce631..67c6c1a3bf 100644 --- a/src/parser/hir/tokens_iterator/debug.rs +++ b/crates/nu-parser/src/hir/tokens_iterator/debug.rs @@ -6,7 +6,7 @@ pub(crate) mod expand_trace; pub(crate) use self::color_trace::*; pub(crate) use self::expand_trace::*; -use crate::parser::hir::tokens_iterator::TokensIteratorState; +use crate::hir::tokens_iterator::TokensIteratorState; use nu_source::{PrettyDebug, PrettyDebugWithSource, Text}; #[derive(Debug)] diff --git a/src/parser/hir/tokens_iterator/debug/color_trace.rs b/crates/nu-parser/src/hir/tokens_iterator/debug/color_trace.rs similarity index 98% rename from src/parser/hir/tokens_iterator/debug/color_trace.rs rename to crates/nu-parser/src/hir/tokens_iterator/debug/color_trace.rs index 3db7a06e5a..6cf2c131ef 100644 --- a/src/parser/hir/tokens_iterator/debug/color_trace.rs +++ b/crates/nu-parser/src/hir/tokens_iterator/debug/color_trace.rs @@ -1,9 +1,8 @@ -use crate::errors::ShellError; -use crate::parser::hir::syntax_shape::FlatShape; -use crate::prelude::*; +use crate::hir::syntax_shape::FlatShape; use ansi_term::Color; use log::trace; -use nu_source::Spanned; +use nu_errors::ShellError; +use nu_source::{Spanned, Text}; use ptree::*; use std::borrow::Cow; use std::io; diff --git a/src/parser/hir/tokens_iterator/debug/expand_trace.rs b/crates/nu-parser/src/hir/tokens_iterator/debug/expand_trace.rs similarity index 98% rename from src/parser/hir/tokens_iterator/debug/expand_trace.rs rename to crates/nu-parser/src/hir/tokens_iterator/debug/expand_trace.rs index d61d21703f..24d67d089b 100644 --- a/src/parser/hir/tokens_iterator/debug/expand_trace.rs +++ b/crates/nu-parser/src/hir/tokens_iterator/debug/expand_trace.rs @@ -1,8 +1,9 @@ -use crate::parser::hir::Expression; -use crate::prelude::*; +use crate::hir::Expression; use ansi_term::Color; use log::trace; -use nu_source::DebugDoc; +use nu_errors::ParseError; +use nu_protocol::ShellTypeName; +use nu_source::{DebugDoc, PrettyDebug, PrettyDebugWithSource, Text}; use ptree::*; use std::borrow::Cow; use std::io; diff --git a/src/parser/hir/tokens_iterator/tests.rs b/crates/nu-parser/src/hir/tokens_iterator/tests.rs similarity index 79% rename from src/parser/hir/tokens_iterator/tests.rs rename to crates/nu-parser/src/hir/tokens_iterator/tests.rs index 23f8889786..e3f44f7e05 100644 --- a/src/parser/hir/tokens_iterator/tests.rs +++ b/crates/nu-parser/src/hir/tokens_iterator/tests.rs @@ -1,5 +1,5 @@ -use crate::parser::hir::TokensIterator; -use crate::parser::parse::token_tree_builder::TokenTreeBuilder as b; +use crate::hir::TokensIterator; +use crate::parse::token_tree_builder::TokenTreeBuilder as b; use crate::Span; #[test] diff --git a/crates/nu-parser/src/lib.rs b/crates/nu-parser/src/lib.rs new file mode 100644 index 0000000000..41c7cde5f5 --- /dev/null +++ b/crates/nu-parser/src/lib.rs @@ -0,0 +1,29 @@ +pub mod commands; +pub mod hir; +pub mod parse; +pub mod parse_command; + +pub use crate::commands::classified::{ClassifiedCommand, ClassifiedPipeline, InternalCommand}; +pub use crate::commands::ExternalCommand; +pub use crate::hir::syntax_shape::flat_shape::FlatShape; +pub use crate::hir::syntax_shape::{expand_syntax, ExpandSyntax, PipelineShape, SignatureRegistry}; +pub use crate::hir::tokens_iterator::TokensIterator; +pub use crate::parse::files::Files; +pub use crate::parse::flag::Flag; +pub use crate::parse::operator::Operator; +pub use crate::parse::parser::pipeline; +pub use crate::parse::parser::Number; +pub use crate::parse::token_tree::{Delimiter, TokenNode}; +pub use crate::parse::token_tree_builder::TokenTreeBuilder; + +use nu_errors::ShellError; +use nu_source::nom_input; + +pub fn parse(input: &str) -> Result { + let _ = pretty_env_logger::try_init(); + + match pipeline(nom_input(input)) { + Ok((_rest, val)) => Ok(val), + Err(err) => Err(ShellError::parse_error(err)), + } +} diff --git a/src/parser/parse.rs b/crates/nu-parser/src/parse.rs similarity index 100% rename from src/parser/parse.rs rename to crates/nu-parser/src/parse.rs diff --git a/src/parser/parse/call_node.rs b/crates/nu-parser/src/parse/call_node.rs similarity index 93% rename from src/parser/parse/call_node.rs rename to crates/nu-parser/src/parse/call_node.rs index ef4298e425..b01d7f8945 100644 --- a/src/parser/parse/call_node.rs +++ b/crates/nu-parser/src/parse/call_node.rs @@ -1,6 +1,6 @@ -use crate::parser::TokenNode; -use crate::prelude::*; +use crate::TokenNode; use getset::Getters; +use nu_source::{b, DebugDocBuilder, PrettyDebugWithSource}; #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Getters)] pub struct CallNode { diff --git a/src/parser/parse/files.rs b/crates/nu-parser/src/parse/files.rs similarity index 100% rename from src/parser/parse/files.rs rename to crates/nu-parser/src/parse/files.rs diff --git a/src/parser/parse/flag.rs b/crates/nu-parser/src/parse/flag.rs similarity index 87% rename from src/parser/parse/flag.rs rename to crates/nu-parser/src/parse/flag.rs index 65f946ea31..5ee7ff02b5 100644 --- a/src/parser/parse/flag.rs +++ b/crates/nu-parser/src/parse/flag.rs @@ -1,8 +1,7 @@ -use crate::parser::hir::syntax_shape::flat_shape::FlatShape; -use crate::prelude::*; +use crate::hir::syntax_shape::flat_shape::FlatShape; use derive_new::new; use getset::Getters; -use nu_source::{Span, Spanned, SpannedItem}; +use nu_source::{b, DebugDocBuilder, PrettyDebugWithSource, Span, Spanned, SpannedItem}; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)] diff --git a/src/parser/parse/operator.rs b/crates/nu-parser/src/parse/operator.rs similarity index 97% rename from src/parser/parse/operator.rs rename to crates/nu-parser/src/parse/operator.rs index f98097f374..99e5b5499e 100644 --- a/src/parser/parse/operator.rs +++ b/crates/nu-parser/src/parse/operator.rs @@ -1,5 +1,4 @@ -#[allow(unused)] -use crate::prelude::*; +use nu_source::{b, DebugDocBuilder, PrettyDebug}; use serde::{Deserialize, Serialize}; use std::str::FromStr; diff --git a/src/parser/parse/parser.rs b/crates/nu-parser/src/parse/parser.rs similarity index 96% rename from src/parser/parse/parser.rs rename to crates/nu-parser/src/parse/parser.rs index 50cf4112bc..f63d505908 100644 --- a/src/parser/parse/parser.rs +++ b/crates/nu-parser/src/parse/parser.rs @@ -1,10 +1,9 @@ #![allow(unused)] -use crate::parser::parse::{ +use crate::parse::{ call_node::*, flag::*, operator::*, pipeline::*, token_tree::*, token_tree_builder::*, tokens::*, unit::*, }; -use crate::prelude::*; use nom; use nom::branch::*; use nom::bytes::complete::*; @@ -13,6 +12,7 @@ use nom::combinator::*; use nom::multi::*; use nom::sequence::*; +use bigdecimal::BigDecimal; use derive_new::new; use log::trace; use nom::dbg; @@ -20,7 +20,14 @@ use nom::*; use nom::{AsBytes, FindSubstring, IResult, InputLength, InputTake, Slice}; use nom_locate::{position, LocatedSpanEx}; use nom_tracable::{tracable_parser, HasTracableInfo, TracableInfo}; -use nu_source::{nom_input, NomSpan, Spanned}; +use nu_protocol::{Primitive, UntaggedValue}; +use nu_source::{ + b, nom_input, DebugDocBuilder, HasSpan, NomSpan, PrettyDebug, PrettyDebugWithSource, Span, + Spanned, SpannedItem, Tag, +}; +use num_bigint::BigInt; +use num_traits::identities::Zero; +use num_traits::FromPrimitive; use serde::{Deserialize, Serialize}; use std::fmt::Debug; use std::str::FromStr; @@ -63,6 +70,32 @@ impl Into for &Number { } } +impl Into for Number { + fn into(self) -> UntaggedValue { + match self { + Number::Int(i) => int(i), + Number::Decimal(d) => decimal(d), + } + } +} + +pub fn int(i: impl Into) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::Int(i.into())) +} + +pub fn decimal(i: impl Into) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::Decimal(i.into())) +} + +impl Into for &Number { + fn into(self) -> UntaggedValue { + match self { + Number::Int(i) => int(i.clone()), + Number::Decimal(d) => decimal(d.clone()), + } + } +} + impl PrettyDebug for Number { fn pretty(&self) -> DebugDocBuilder { match self { @@ -616,7 +649,7 @@ pub fn pipeline(input: NomSpan) -> IResult { )) } -fn int(frag: &str, neg: Option) -> i64 { +fn parse_int(frag: &str, neg: Option) -> i64 { let int = FromStr::from_str(frag).unwrap(); match neg { @@ -712,8 +745,8 @@ fn is_member_start(c: char) -> bool { #[cfg(test)] mod tests { use super::*; - use crate::parser::parse::token_tree_builder::TokenTreeBuilder as b; - use crate::parser::parse::token_tree_builder::{CurriedToken, TokenTreeBuilder}; + use crate::parse::token_tree_builder::TokenTreeBuilder as b; + use crate::parse::token_tree_builder::{CurriedToken, TokenTreeBuilder}; use pretty_assertions::assert_eq; pub type CurriedNode = Box T + 'static>; diff --git a/src/parser/parse/pipeline.rs b/crates/nu-parser/src/parse/pipeline.rs similarity index 93% rename from src/parser/parse/pipeline.rs rename to crates/nu-parser/src/parse/pipeline.rs index 883f714026..9752ce6117 100644 --- a/src/parser/parse/pipeline.rs +++ b/crates/nu-parser/src/parse/pipeline.rs @@ -1,8 +1,7 @@ -use crate::parser::TokenNode; -use crate::prelude::*; +use crate::TokenNode; use derive_new::new; use getset::Getters; -use nu_source::{DebugDocBuilder, PrettyDebugWithSource, Span, Spanned}; +use nu_source::{b, DebugDocBuilder, HasSpan, PrettyDebugWithSource, Span, Spanned}; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Getters, new)] pub struct Pipeline { diff --git a/src/parser/parse/token_tree.rs b/crates/nu-parser/src/parse/token_tree.rs similarity index 97% rename from src/parser/parse/token_tree.rs rename to crates/nu-parser/src/parse/token_tree.rs index 116a672883..2869a4b7ae 100644 --- a/src/parser/parse/token_tree.rs +++ b/crates/nu-parser/src/parse/token_tree.rs @@ -1,10 +1,12 @@ -use crate::errors::{ParseError, ShellError}; -use crate::parser::parse::{call_node::*, flag::*, operator::*, pipeline::*, tokens::*}; -use crate::prelude::*; +use crate::parse::{call_node::*, flag::*, operator::*, pipeline::*, tokens::*}; use derive_new::new; use getset::Getters; -use nu_source::Spanned; -use nu_source::{Tagged, Text}; +use nu_errors::{ParseError, ShellError}; +use nu_protocol::ShellTypeName; +use nu_source::{ + b, DebugDocBuilder, HasSpan, PrettyDebugWithSource, Span, Spanned, SpannedItem, Tagged, + TaggedItem, Text, +}; use std::fmt; #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] diff --git a/src/parser/parse/token_tree_builder.rs b/crates/nu-parser/src/parse/token_tree_builder.rs similarity index 96% rename from src/parser/parse/token_tree_builder.rs rename to crates/nu-parser/src/parse/token_tree_builder.rs index 3b6929b11d..7b82cb4131 100644 --- a/src/parser/parse/token_tree_builder.rs +++ b/crates/nu-parser/src/parse/token_tree_builder.rs @@ -1,12 +1,12 @@ -use crate::prelude::*; - -use crate::parser::parse::flag::{Flag, FlagKind}; -use crate::parser::parse::operator::Operator; -use crate::parser::parse::pipeline::{Pipeline, PipelineElement}; -use crate::parser::parse::token_tree::{DelimitedNode, Delimiter, TokenNode}; -use crate::parser::parse::tokens::{RawNumber, UnspannedToken}; -use crate::parser::CallNode; -use nu_source::Spanned; +use crate::parse::call_node::CallNode; +use crate::parse::flag::{Flag, FlagKind}; +use crate::parse::operator::Operator; +use crate::parse::pipeline::{Pipeline, PipelineElement}; +use crate::parse::token_tree::{DelimitedNode, Delimiter, TokenNode}; +use crate::parse::tokens::{RawNumber, UnspannedToken}; +use bigdecimal::BigDecimal; +use nu_source::{Span, Spanned, SpannedItem}; +use num_bigint::BigInt; pub struct TokenTreeBuilder { pos: usize, diff --git a/src/parser/parse/tokens.rs b/crates/nu-parser/src/parse/tokens.rs similarity index 95% rename from src/parser/parse/tokens.rs rename to crates/nu-parser/src/parse/tokens.rs index 8b6bdf4574..8430725313 100644 --- a/src/parser/parse/tokens.rs +++ b/crates/nu-parser/src/parse/tokens.rs @@ -1,6 +1,12 @@ -use crate::parser::Operator; -use crate::prelude::*; -use nu_source::{Spanned, Text}; +use crate::parse::parser::Number; +use crate::Operator; +use bigdecimal::BigDecimal; +use nu_protocol::ShellTypeName; +use nu_source::{ + b, DebugDocBuilder, HasSpan, PrettyDebug, PrettyDebugWithSource, Span, Spanned, SpannedItem, + Text, +}; +use num_bigint::BigInt; use std::fmt; use std::str::FromStr; diff --git a/src/parser/parse/unit.rs b/crates/nu-parser/src/parse/unit.rs similarity index 56% rename from src/parser/parse/unit.rs rename to crates/nu-parser/src/parse/unit.rs index 5312ed7286..e51d6cf362 100644 --- a/src/parser/parse/unit.rs +++ b/crates/nu-parser/src/parse/unit.rs @@ -1,4 +1,7 @@ -use crate::prelude::*; +use crate::parse::parser::Number; +use nu_protocol::{Primitive, UntaggedValue}; +use nu_source::{b, DebugDocBuilder, PrettyDebug}; +use num_traits::ToPrimitive; use serde::{Deserialize, Serialize}; use std::str::FromStr; @@ -25,7 +28,7 @@ pub enum Unit { impl PrettyDebug for Unit { fn pretty(&self) -> DebugDocBuilder { - b::keyword(format!("{:?}", self)) + b::keyword(self.as_str()) } } @@ -55,31 +58,40 @@ impl Unit { } } - pub(crate) fn compute(&self, size: &Number) -> UntaggedValue { + pub fn compute(&self, size: &Number) -> UntaggedValue { let size = size.clone(); match &self { - Unit::Byte => UntaggedValue::number(size), - Unit::Kilobyte => UntaggedValue::number(size * 1024), - Unit::Megabyte => UntaggedValue::number(size * 1024 * 1024), - Unit::Gigabyte => UntaggedValue::number(size * 1024 * 1024 * 1024), - Unit::Terabyte => UntaggedValue::number(size * 1024 * 1024 * 1024 * 1024), - Unit::Petabyte => UntaggedValue::number(size * 1024 * 1024 * 1024 * 1024 * 1024), - Unit::Second => UntaggedValue::duration(convert_number_to_u64(&size)), - Unit::Minute => UntaggedValue::duration(60 * convert_number_to_u64(&size)), - Unit::Hour => UntaggedValue::duration(60 * 60 * convert_number_to_u64(&size)), - Unit::Day => UntaggedValue::duration(24 * 60 * 60 * convert_number_to_u64(&size)), - Unit::Week => UntaggedValue::duration(7 * 24 * 60 * 60 * convert_number_to_u64(&size)), - Unit::Month => { - UntaggedValue::duration(30 * 24 * 60 * 60 * convert_number_to_u64(&size)) - } - Unit::Year => { - UntaggedValue::duration(365 * 24 * 60 * 60 * convert_number_to_u64(&size)) - } + Unit::Byte => number(size), + Unit::Kilobyte => number(size * 1024), + Unit::Megabyte => number(size * 1024 * 1024), + Unit::Gigabyte => number(size * 1024 * 1024 * 1024), + Unit::Terabyte => number(size * 1024 * 1024 * 1024 * 1024), + Unit::Petabyte => number(size * 1024 * 1024 * 1024 * 1024 * 1024), + Unit::Second => duration(convert_number_to_u64(&size)), + Unit::Minute => duration(60 * convert_number_to_u64(&size)), + Unit::Hour => duration(60 * 60 * convert_number_to_u64(&size)), + Unit::Day => duration(24 * 60 * 60 * convert_number_to_u64(&size)), + Unit::Week => duration(7 * 24 * 60 * 60 * convert_number_to_u64(&size)), + Unit::Month => duration(30 * 24 * 60 * 60 * convert_number_to_u64(&size)), + Unit::Year => duration(365 * 24 * 60 * 60 * convert_number_to_u64(&size)), } } } +fn number(number: impl Into) -> UntaggedValue { + let number = number.into(); + + match number { + Number::Int(int) => UntaggedValue::Primitive(Primitive::Int(int)), + Number::Decimal(decimal) => UntaggedValue::Primitive(Primitive::Decimal(decimal)), + } +} + +pub fn duration(secs: u64) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::Duration(secs)) +} + impl FromStr for Unit { type Err = (); fn from_str(input: &str) -> Result::Err> { diff --git a/src/parser/parse/util.rs b/crates/nu-parser/src/parse/util.rs similarity index 100% rename from src/parser/parse/util.rs rename to crates/nu-parser/src/parse/util.rs diff --git a/src/parser/parse_command.rs b/crates/nu-parser/src/parse_command.rs similarity index 98% rename from src/parser/parse_command.rs rename to crates/nu-parser/src/parse_command.rs index 41aff543f8..5edc93fd45 100644 --- a/src/parser/parse_command.rs +++ b/crates/nu-parser/src/parse_command.rs @@ -1,17 +1,17 @@ -use crate::errors::{ArgumentError, ParseError}; -use crate::parser::hir::syntax_shape::{ +use crate::hir::syntax_shape::{ color_fallible_syntax, color_syntax, expand_expr, flat_shape::FlatShape, spaced, BackoffColoringMode, ColorSyntax, MaybeSpaceShape, }; -use crate::parser::registry::{NamedType, PositionalType, Signature}; -use crate::parser::TokensIterator; -use crate::parser::{ +use crate::TokensIterator; +use crate::{ hir::{self, ExpandContext, NamedArguments}, Flag, }; use log::trace; -use nu_source::{PrettyDebugWithSource, Text}; -use nu_source::{Span, Spanned, SpannedItem}; +use nu_source::{PrettyDebugWithSource, Span, Spanned, SpannedItem, Text}; + +use nu_errors::{ArgumentError, ParseError}; +use nu_protocol::{NamedType, PositionalType, Signature}; pub fn parse_command_tail( config: &Signature, @@ -389,7 +389,7 @@ impl ColorSyntax for CommandTailShape { token_nodes: &'b mut TokensIterator<'a>, context: &ExpandContext, ) -> Self::Info { - use crate::parser::hir::syntax_shape::SyntaxShape; + use nu_protocol::SyntaxShape; let mut args = ColoringArgs::new(token_nodes.len()); trace_remaining("nodes", &token_nodes, context.source()); diff --git a/crates/nu-protocol/Cargo.toml b/crates/nu-protocol/Cargo.toml new file mode 100644 index 0000000000..4379527189 --- /dev/null +++ b/crates/nu-protocol/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "nu-protocol" +version = "0.1.0" +authors = ["Yehuda Katz "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +nu-source = { path = "../nu-source" } +nu-errors = { path = "../nu-errors" } + +serde = { version = "1.0.102", features = ["derive"] } +indexmap = { version = "1.3.0", features = ["serde-1"] } +num-bigint = { version = "0.2.3", features = ["serde"] } +bigdecimal = { version = "0.1.0", features = ["serde"] } +chrono = { version = "0.4.9", features = ["serde"] } +num-traits = "0.2.8" +serde_bytes = "0.11.2" +getset = "0.0.9" +derive-new = "0.5.8" +ansi_term = "0.12.1" +language-reporting = "0.4.0" +nom = "5.0.1" +nom_locate = "1.0.0" +nom-tracable = "0.4.1" +typetag = "0.1.4" +query_interface = "0.3.5" + +# implement conversions +subprocess = "0.1.18" +serde_yaml = "0.8" +toml = "0.5.5" +serde_json = "1.0.41" + +[build-dependencies] +nu-build = { version = "0.1.0", path = "../nu-build" } diff --git a/crates/nu-protocol/build.rs b/crates/nu-protocol/build.rs new file mode 100644 index 0000000000..b7511cfc6a --- /dev/null +++ b/crates/nu-protocol/build.rs @@ -0,0 +1,3 @@ +fn main() -> Result<(), Box> { + nu_build::build() +} diff --git a/crates/nu-protocol/src/call_info.rs b/crates/nu-protocol/src/call_info.rs new file mode 100644 index 0000000000..1a58aabb43 --- /dev/null +++ b/crates/nu-protocol/src/call_info.rs @@ -0,0 +1,93 @@ +use crate::value::Value; +use derive_new::new; +use indexmap::IndexMap; +use nu_errors::ShellError; +use nu_source::Tag; +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize, Debug, Clone)] +pub struct CallInfo { + pub args: EvaluatedArgs, + pub name_tag: Tag, +} + +#[derive(Debug, Default, new, Serialize, Deserialize, Clone)] +pub struct EvaluatedArgs { + pub positional: Option>, + pub named: Option>, +} + +impl EvaluatedArgs { + pub fn slice_from(&self, from: usize) -> Vec { + let positional = &self.positional; + + match positional { + None => vec![], + Some(list) => list[from..].to_vec(), + } + } + + pub fn nth(&self, pos: usize) -> Option<&Value> { + match &self.positional { + None => None, + Some(array) => array.iter().nth(pos), + } + } + + pub fn expect_nth(&self, pos: usize) -> Result<&Value, ShellError> { + match &self.positional { + None => Err(ShellError::unimplemented("Better error: expect_nth")), + Some(array) => match array.iter().nth(pos) { + None => Err(ShellError::unimplemented("Better error: expect_nth")), + Some(item) => Ok(item), + }, + } + } + + pub fn len(&self) -> usize { + match &self.positional { + None => 0, + Some(array) => array.len(), + } + } + + pub fn has(&self, name: &str) -> bool { + match &self.named { + None => false, + Some(named) => named.contains_key(name), + } + } + + pub fn get(&self, name: &str) -> Option<&Value> { + match &self.named { + None => None, + Some(named) => named.get(name), + } + } + + pub fn positional_iter(&self) -> PositionalIter<'_> { + match &self.positional { + None => PositionalIter::Empty, + Some(v) => { + let iter = v.iter(); + PositionalIter::Array(iter) + } + } + } +} + +pub enum PositionalIter<'a> { + Empty, + Array(std::slice::Iter<'a, Value>), +} + +impl<'a> Iterator for PositionalIter<'a> { + type Item = &'a Value; + + fn next(&mut self) -> Option { + match self { + PositionalIter::Empty => None, + PositionalIter::Array(iter) => iter.next(), + } + } +} diff --git a/crates/nu-protocol/src/lib.rs b/crates/nu-protocol/src/lib.rs new file mode 100644 index 0000000000..8aa60ea695 --- /dev/null +++ b/crates/nu-protocol/src/lib.rs @@ -0,0 +1,24 @@ +#[macro_use] +mod macros; + +mod call_info; +mod maybe_owned; +mod plugin; +mod return_value; +mod signature; +mod syntax_shape; +mod type_name; +mod value; + +pub use crate::call_info::{CallInfo, EvaluatedArgs}; +pub use crate::maybe_owned::MaybeOwned; +pub use crate::plugin::{serve_plugin, Plugin}; +pub use crate::return_value::{CommandAction, ReturnSuccess, ReturnValue}; +pub use crate::signature::{NamedType, PositionalType, Signature}; +pub use crate::syntax_shape::SyntaxShape; +pub use crate::type_name::{PrettyType, ShellTypeName, SpannedTypeName}; +pub use crate::value::column_path::{ColumnPath, PathMember, UnspannedPathMember}; +pub use crate::value::dict::Dictionary; +pub use crate::value::evaluate::{Evaluate, EvaluateTrait, Scope}; +pub use crate::value::primitive::Primitive; +pub use crate::value::{UntaggedValue, Value}; diff --git a/crates/nu-protocol/src/macros.rs b/crates/nu-protocol/src/macros.rs new file mode 100644 index 0000000000..66e7ab13b6 --- /dev/null +++ b/crates/nu-protocol/src/macros.rs @@ -0,0 +1,12 @@ +// These macros exist to differentiate between intentional writing to stdout +// and stray printlns left by accident + +#[macro_export] +macro_rules! outln { + ($($tokens:tt)*) => { println!($($tokens)*) } +} + +#[macro_export] +macro_rules! errln { + ($($tokens:tt)*) => { eprintln!($($tokens)*) } +} diff --git a/crates/nu-protocol/src/maybe_owned.rs b/crates/nu-protocol/src/maybe_owned.rs new file mode 100644 index 0000000000..c654057cab --- /dev/null +++ b/crates/nu-protocol/src/maybe_owned.rs @@ -0,0 +1,14 @@ +#[derive(Debug)] +pub enum MaybeOwned<'a, T> { + Owned(T), + Borrowed(&'a T), +} + +impl MaybeOwned<'_, T> { + pub fn borrow(&self) -> &T { + match self { + MaybeOwned::Owned(v) => v, + MaybeOwned::Borrowed(v) => v, + } + } +} diff --git a/src/plugin.rs b/crates/nu-protocol/src/plugin.rs similarity index 97% rename from src/plugin.rs rename to crates/nu-protocol/src/plugin.rs index cc9ee411b8..4fc56e0af9 100644 --- a/src/plugin.rs +++ b/crates/nu-protocol/src/plugin.rs @@ -1,5 +1,8 @@ -use crate::Signature; -use crate::{CallInfo, ReturnValue, ShellError, Value}; +use crate::call_info::CallInfo; +use crate::return_value::ReturnValue; +use crate::signature::Signature; +use crate::value::Value; +use nu_errors::ShellError; use serde::{Deserialize, Serialize}; use std::io; diff --git a/crates/nu-protocol/src/return_value.rs b/crates/nu-protocol/src/return_value.rs new file mode 100644 index 0000000000..42e948b197 --- /dev/null +++ b/crates/nu-protocol/src/return_value.rs @@ -0,0 +1,76 @@ +use crate::value::Value; +use nu_errors::ShellError; +use nu_source::{b, DebugDocBuilder, PrettyDebug}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum CommandAction { + ChangePath(String), + Exit, + Error(ShellError), + EnterShell(String), + EnterValueShell(Value), + EnterHelpShell(Value), + PreviousShell, + NextShell, + LeaveShell, +} + +impl PrettyDebug for CommandAction { + fn pretty(&self) -> DebugDocBuilder { + match self { + CommandAction::ChangePath(path) => b::typed("change path", b::description(path)), + CommandAction::Exit => b::description("exit"), + CommandAction::Error(_) => b::error("error"), + CommandAction::EnterShell(s) => b::typed("enter shell", b::description(s)), + CommandAction::EnterValueShell(v) => b::typed("enter value shell", v.pretty()), + CommandAction::EnterHelpShell(v) => b::typed("enter help shell", v.pretty()), + CommandAction::PreviousShell => b::description("previous shell"), + CommandAction::NextShell => b::description("next shell"), + CommandAction::LeaveShell => b::description("leave shell"), + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum ReturnSuccess { + Value(Value), + DebugValue(Value), + Action(CommandAction), +} + +impl PrettyDebug for ReturnSuccess { + fn pretty(&self) -> DebugDocBuilder { + match self { + ReturnSuccess::Value(value) => b::typed("value", value.pretty()), + ReturnSuccess::DebugValue(value) => b::typed("debug value", value.pretty()), + ReturnSuccess::Action(action) => b::typed("action", action.pretty()), + } + } +} + +pub type ReturnValue = Result; + +impl Into for Value { + fn into(self) -> ReturnValue { + Ok(ReturnSuccess::Value(self)) + } +} + +impl ReturnSuccess { + pub fn change_cwd(path: String) -> ReturnValue { + Ok(ReturnSuccess::Action(CommandAction::ChangePath(path))) + } + + pub fn value(input: impl Into) -> ReturnValue { + Ok(ReturnSuccess::Value(input.into())) + } + + pub fn debug_value(input: impl Into) -> ReturnValue { + Ok(ReturnSuccess::DebugValue(input.into())) + } + + pub fn action(input: CommandAction) -> ReturnValue { + Ok(ReturnSuccess::Action(input)) + } +} diff --git a/src/parser/registry.rs b/crates/nu-protocol/src/signature.rs similarity index 55% rename from src/parser/registry.rs rename to crates/nu-protocol/src/signature.rs index 98d8a0375c..591ec4d727 100644 --- a/src/parser/registry.rs +++ b/crates/nu-protocol/src/signature.rs @@ -1,11 +1,6 @@ -// TODO: Temporary redirect -pub(crate) use crate::context::CommandRegistry; -use crate::evaluate::{evaluate_baseline_expr, Scope}; -use crate::parser::{hir, hir::SyntaxShape}; -use crate::prelude::*; -use derive_new::new; +use crate::syntax_shape::SyntaxShape; use indexmap::IndexMap; - +use nu_source::{b, DebugDocBuilder, PrettyDebug, PrettyDebugWithSource}; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize, Clone)] @@ -57,14 +52,14 @@ impl PositionalType { PositionalType::Optional(name.to_string(), SyntaxShape::Any) } - pub(crate) fn name(&self) -> &str { + pub fn name(&self) -> &str { match self { PositionalType::Mandatory(s, _) => s, PositionalType::Optional(s, _) => s, } } - pub(crate) fn syntax_type(&self) -> SyntaxShape { + pub fn syntax_type(&self) -> SyntaxShape { match *self { PositionalType::Mandatory(_, t) => t, PositionalType::Optional(_, t) => t, @@ -192,135 +187,3 @@ impl Signature { self } } - -#[derive(Debug, Default, new, Serialize, Deserialize, Clone)] -pub struct EvaluatedArgs { - pub positional: Option>, - pub named: Option>, -} - -impl EvaluatedArgs { - pub fn slice_from(&self, from: usize) -> Vec { - let positional = &self.positional; - - match positional { - None => vec![], - Some(list) => list[from..].to_vec(), - } - } -} - -impl EvaluatedArgs { - pub fn nth(&self, pos: usize) -> Option<&Value> { - match &self.positional { - None => None, - Some(array) => array.iter().nth(pos), - } - } - - pub fn expect_nth(&self, pos: usize) -> Result<&Value, ShellError> { - match &self.positional { - None => Err(ShellError::unimplemented("Better error: expect_nth")), - Some(array) => match array.iter().nth(pos) { - None => Err(ShellError::unimplemented("Better error: expect_nth")), - Some(item) => Ok(item), - }, - } - } - - pub fn len(&self) -> usize { - match &self.positional { - None => 0, - Some(array) => array.len(), - } - } - - pub fn has(&self, name: &str) -> bool { - match &self.named { - None => false, - Some(named) => named.contains_key(name), - } - } - - pub fn get(&self, name: &str) -> Option<&Value> { - match &self.named { - None => None, - Some(named) => named.get(name), - } - } - - pub fn positional_iter(&self) -> PositionalIter<'_> { - match &self.positional { - None => PositionalIter::Empty, - Some(v) => { - let iter = v.iter(); - PositionalIter::Array(iter) - } - } - } -} - -pub enum PositionalIter<'a> { - Empty, - Array(std::slice::Iter<'a, Value>), -} - -impl<'a> Iterator for PositionalIter<'a> { - type Item = &'a Value; - - fn next(&mut self) -> Option { - match self { - PositionalIter::Empty => None, - PositionalIter::Array(iter) => iter.next(), - } - } -} - -pub(crate) fn evaluate_args( - call: &hir::Call, - registry: &CommandRegistry, - scope: &Scope, - source: &Text, -) -> Result { - let positional: Result>, _> = call - .positional() - .as_ref() - .map(|p| { - p.iter() - .map(|e| evaluate_baseline_expr(e, registry, scope, source)) - .collect() - }) - .transpose(); - - let positional = positional?; - - let named: Result>, ShellError> = call - .named() - .as_ref() - .map(|n| { - let mut results = IndexMap::new(); - - for (name, value) in n.named.iter() { - match value { - hir::named::NamedValue::PresentSwitch(tag) => { - results.insert(name.clone(), UntaggedValue::boolean(true).into_value(tag)); - } - hir::named::NamedValue::Value(expr) => { - results.insert( - name.clone(), - evaluate_baseline_expr(expr, registry, scope, source)?, - ); - } - - _ => {} - }; - } - - Ok(results) - }) - .transpose(); - - let named = named?; - - Ok(EvaluatedArgs::new(positional, named)) -} diff --git a/crates/nu-protocol/src/syntax_shape.rs b/crates/nu-protocol/src/syntax_shape.rs new file mode 100644 index 0000000000..7f6d486bfd --- /dev/null +++ b/crates/nu-protocol/src/syntax_shape.rs @@ -0,0 +1,31 @@ +use nu_source::{b, DebugDocBuilder, PrettyDebug}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Copy, Clone, Serialize, Deserialize)] +pub enum SyntaxShape { + Any, + String, + Member, + ColumnPath, + Number, + Int, + Path, + Pattern, + Block, +} + +impl PrettyDebug for SyntaxShape { + fn pretty(&self) -> DebugDocBuilder { + b::kind(match self { + SyntaxShape::Any => "any shape", + SyntaxShape::String => "string shape", + SyntaxShape::Member => "member shape", + SyntaxShape::ColumnPath => "column path shape", + SyntaxShape::Number => "number shape", + SyntaxShape::Int => "integer shape", + SyntaxShape::Path => "file path shape", + SyntaxShape::Pattern => "pattern shape", + SyntaxShape::Block => "block shape", + }) + } +} diff --git a/src/traits.rs b/crates/nu-protocol/src/type_name.rs similarity index 90% rename from src/traits.rs rename to crates/nu-protocol/src/type_name.rs index 94d09b67c3..b9d6344c0e 100644 --- a/src/traits.rs +++ b/crates/nu-protocol/src/type_name.rs @@ -1,5 +1,4 @@ -use crate::prelude::*; -use nu_source::{DebugDocBuilder, Spanned, SpannedItem, Tagged}; +use nu_source::{DebugDocBuilder, HasSpan, Spanned, SpannedItem, Tagged}; pub trait ShellTypeName { fn type_name(&self) -> &'static str; diff --git a/crates/nu-protocol/src/value.rs b/crates/nu-protocol/src/value.rs new file mode 100644 index 0000000000..8e116315a7 --- /dev/null +++ b/crates/nu-protocol/src/value.rs @@ -0,0 +1,212 @@ +pub mod column_path; +mod convert; +mod debug; +pub mod dict; +pub mod evaluate; +pub mod primitive; +mod serde_bigdecimal; +mod serde_bigint; + +use crate::type_name::{ShellTypeName, SpannedTypeName}; +use crate::value::dict::Dictionary; +use crate::value::evaluate::Evaluate; +use crate::value::primitive::Primitive; +use nu_errors::ShellError; +use nu_source::{AnchorLocation, HasSpan, Span, Tag}; +use serde::{Deserialize, Serialize}; +use std::path::PathBuf; + +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)] +pub enum UntaggedValue { + Primitive(Primitive), + Row(Dictionary), + Table(Vec), + + // Errors are a type of value too + Error(ShellError), + + Block(Evaluate), +} + +impl UntaggedValue { + pub fn retag(self, tag: impl Into) -> Value { + Value { + value: self, + tag: tag.into(), + } + } + + pub fn data_descriptors(&self) -> Vec { + match self { + UntaggedValue::Primitive(_) => vec![], + UntaggedValue::Row(columns) => columns + .entries + .keys() + .into_iter() + .map(|x| x.to_string()) + .collect(), + UntaggedValue::Block(_) => vec![], + UntaggedValue::Table(_) => vec![], + UntaggedValue::Error(_) => vec![], + } + } + + pub fn into_value(self, tag: impl Into) -> Value { + Value { + value: self, + tag: tag.into(), + } + } + + pub fn into_untagged_value(self) -> Value { + Value { + value: self, + tag: Tag::unknown(), + } + } + + pub fn is_true(&self) -> bool { + match self { + UntaggedValue::Primitive(Primitive::Boolean(true)) => true, + _ => false, + } + } + + pub fn is_some(&self) -> bool { + !self.is_none() + } + + pub fn is_none(&self) -> bool { + match self { + UntaggedValue::Primitive(Primitive::Nothing) => true, + _ => false, + } + } + + pub fn is_error(&self) -> bool { + match self { + UntaggedValue::Error(_err) => true, + _ => false, + } + } + + pub fn expect_error(&self) -> ShellError { + match self { + UntaggedValue::Error(err) => err.clone(), + _ => panic!("Don't call expect_error without first calling is_error"), + } + } + + pub fn expect_string(&self) -> &str { + match self { + UntaggedValue::Primitive(Primitive::String(string)) => &string[..], + _ => panic!("expect_string assumes that the value must be a string"), + } + } +} + +#[derive(Debug, Clone, PartialOrd, PartialEq, Ord, Eq, 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 Value { + pub fn anchor(&self) -> Option { + self.tag.anchor() + } + + pub fn anchor_name(&self) -> Option { + self.tag.anchor_name() + } + + pub fn tag(&self) -> Tag { + self.tag.clone() + } + + pub fn as_string(&self) -> Result<&str, ShellError> { + match &self.value { + UntaggedValue::Primitive(Primitive::String(string)) => Ok(&string[..]), + _ => Err(ShellError::type_error("string", self.spanned_type_name())), + } + } + + pub fn as_forgiving_string(&self) -> Result<&str, ShellError> { + match &self.value { + UntaggedValue::Primitive(Primitive::String(string)) => Ok(&string[..]), + _ => Err(ShellError::type_error("string", self.spanned_type_name())), + } + } + + pub fn as_path(&self) -> Result { + match &self.value { + UntaggedValue::Primitive(Primitive::Path(path)) => Ok(path.clone()), + UntaggedValue::Primitive(Primitive::String(path_str)) => { + Ok(PathBuf::from(&path_str).clone()) + } + _ => Err(ShellError::type_error("Path", self.spanned_type_name())), + } + } +} + +impl Into for &str { + fn into(self) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::String(self.to_string())) + } +} + +impl Into for Value { + fn into(self) -> UntaggedValue { + self.value + } +} + +impl<'a> Into<&'a UntaggedValue> for &'a Value { + fn into(self) -> &'a UntaggedValue { + &self.value + } +} + +impl HasSpan for Value { + fn span(&self) -> Span { + self.tag.span + } +} + +impl ShellTypeName for Value { + fn type_name(&self) -> &'static str { + ShellTypeName::type_name(&self.value) + } +} + +impl ShellTypeName for UntaggedValue { + fn type_name(&self) -> &'static str { + match &self { + UntaggedValue::Primitive(p) => p.type_name(), + UntaggedValue::Row(_) => "row", + UntaggedValue::Table(_) => "table", + UntaggedValue::Error(_) => "error", + UntaggedValue::Block(_) => "block", + } + } +} + +impl From for UntaggedValue { + fn from(input: Primitive) -> UntaggedValue { + UntaggedValue::Primitive(input) + } +} + +impl From for UntaggedValue { + fn from(input: String) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::String(input)) + } +} diff --git a/src/parser/hir/path.rs b/crates/nu-protocol/src/value/column_path.rs similarity index 73% rename from src/parser/hir/path.rs rename to crates/nu-protocol/src/value/column_path.rs index 2e2e6f4248..5695b59572 100644 --- a/src/parser/hir/path.rs +++ b/crates/nu-protocol/src/value/column_path.rs @@ -1,8 +1,7 @@ -use crate::parser::hir::Expression; -use crate::prelude::*; use derive_new::new; -use getset::{Getters, MutGetters}; -use nu_source::{b, span_for_spanned_list, PrettyDebug}; +use getset::Getters; +use nu_source::{b, span_for_spanned_list, DebugDocBuilder, HasFallibleSpan, PrettyDebug, Span}; +use num_bigint::BigInt; use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] @@ -86,38 +85,3 @@ impl PathMember { UnspannedPathMember::Int(int.into()).into_path_member(span) } } - -#[derive( - Debug, - Clone, - Eq, - PartialEq, - Ord, - PartialOrd, - Hash, - Getters, - MutGetters, - Serialize, - Deserialize, - new, -)] -#[get = "pub(crate)"] -pub struct Path { - head: Expression, - #[get_mut = "pub(crate)"] - tail: Vec, -} - -impl PrettyDebugWithSource for Path { - fn pretty_debug(&self, source: &str) -> DebugDocBuilder { - self.head.pretty_debug(source) - + b::operator(".") - + b::intersperse(self.tail.iter().map(|m| m.pretty()), b::operator(".")) - } -} - -impl Path { - pub(crate) fn parts(self) -> (Expression, Vec) { - (self.head, self.tail) - } -} diff --git a/crates/nu-protocol/src/value/convert.rs b/crates/nu-protocol/src/value/convert.rs new file mode 100644 index 0000000000..739d87b6e1 --- /dev/null +++ b/crates/nu-protocol/src/value/convert.rs @@ -0,0 +1,55 @@ +use crate::type_name::SpannedTypeName; +use crate::value::dict::Dictionary; +use crate::value::primitive::Primitive; +use crate::value::{UntaggedValue, Value}; +use nu_errors::{CoerceInto, ShellError}; +use nu_source::TaggedItem; + +impl std::convert::TryFrom<&Value> for i64 { + type Error = ShellError; + + fn try_from(value: &Value) -> Result { + match &value.value { + UntaggedValue::Primitive(Primitive::Int(int)) => { + int.tagged(&value.tag).coerce_into("converting to i64") + } + _ => Err(ShellError::type_error("Integer", value.spanned_type_name())), + } + } +} + +impl std::convert::TryFrom<&Value> for String { + type Error = ShellError; + + fn try_from(value: &Value) -> Result { + match &value.value { + UntaggedValue::Primitive(Primitive::String(s)) => Ok(s.clone()), + _ => Err(ShellError::type_error("String", value.spanned_type_name())), + } + } +} + +impl std::convert::TryFrom<&Value> for Vec { + type Error = ShellError; + + fn try_from(value: &Value) -> Result, ShellError> { + match &value.value { + UntaggedValue::Primitive(Primitive::Binary(b)) => Ok(b.clone()), + _ => Err(ShellError::type_error("Binary", value.spanned_type_name())), + } + } +} + +impl<'a> std::convert::TryFrom<&'a Value> for &'a Dictionary { + type Error = ShellError; + + fn try_from(value: &'a Value) -> Result<&'a Dictionary, ShellError> { + match &value.value { + UntaggedValue::Row(d) => Ok(d), + _ => Err(ShellError::type_error( + "Dictionary", + value.spanned_type_name(), + )), + } + } +} diff --git a/src/data/base/debug.rs b/crates/nu-protocol/src/value/debug.rs similarity index 76% rename from src/data/base/debug.rs rename to crates/nu-protocol/src/value/debug.rs index 05b8b911bd..c24789340d 100644 --- a/src/data/base/debug.rs +++ b/crates/nu-protocol/src/value/debug.rs @@ -1,7 +1,28 @@ -use crate::data::base::Primitive; -use crate::traits::PrettyType; +use crate::type_name::PrettyType; +use crate::value::primitive::Primitive; +use crate::value::{UntaggedValue, Value}; use nu_source::{b, DebugDocBuilder, PrettyDebug}; +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 PrettyType for Primitive { fn pretty_type(&self) -> DebugDocBuilder { match self { @@ -51,10 +72,10 @@ fn prim(name: impl std::fmt::Debug) -> DebugDocBuilder { b::primitive(format!("{:?}", name)) } -fn ty(name: impl std::fmt::Debug) -> DebugDocBuilder { - b::kind(format!("{:?}", name)) -} - fn primitive_doc(name: impl std::fmt::Debug, ty: impl Into) -> DebugDocBuilder { b::primitive(format!("{:?}", name)) + b::delimit("(", b::kind(ty.into()), ")") } + +fn ty(name: impl std::fmt::Debug) -> DebugDocBuilder { + b::kind(format!("{:?}", name)) +} diff --git a/crates/nu-protocol/src/value/dict.rs b/crates/nu-protocol/src/value/dict.rs new file mode 100644 index 0000000000..d8c588803d --- /dev/null +++ b/crates/nu-protocol/src/value/dict.rs @@ -0,0 +1,140 @@ +use crate::maybe_owned::MaybeOwned; +use crate::value::primitive::Primitive; +use crate::value::{UntaggedValue, Value}; +use derive_new::new; +use getset::Getters; +use indexmap::IndexMap; +use nu_source::{b, DebugDocBuilder, PrettyDebug, Spanned, Tag}; +use serde::{Deserialize, Serialize}; +use std::cmp::{Ord, Ordering, PartialOrd}; + +#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, Clone, Getters, new)] +pub struct Dictionary { + #[get = "pub"] + pub entries: IndexMap, +} + +impl PartialOrd for Dictionary { + fn partial_cmp(&self, other: &Dictionary) -> Option { + let this: Vec<&String> = self.entries.keys().collect(); + let that: Vec<&String> = other.entries.keys().collect(); + + if this != that { + return this.partial_cmp(&that); + } + + let this: Vec<&Value> = self.entries.values().collect(); + let that: Vec<&Value> = self.entries.values().collect(); + + this.partial_cmp(&that) + } +} + +impl Ord for Dictionary { + fn cmp(&self, other: &Dictionary) -> Ordering { + let this: Vec<&String> = self.entries.keys().collect(); + let that: Vec<&String> = other.entries.keys().collect(); + + if this != that { + return this.cmp(&that); + } + + let this: Vec<&Value> = self.entries.values().collect(); + let that: Vec<&Value> = self.entries.values().collect(); + + this.cmp(&that) + } +} + +impl PartialEq for Dictionary { + fn eq(&self, other: &Value) -> bool { + match &other.value { + UntaggedValue::Row(d) => self == d, + _ => false, + } + } +} + +#[derive(Debug, new)] +struct DebugEntry<'a> { + key: &'a str, + value: &'a Value, +} + +impl<'a> PrettyDebug for DebugEntry<'a> { + fn pretty(&self) -> DebugDocBuilder { + (b::key(self.key.to_string()) + b::equals() + self.value.pretty().as_value()).group() + } +} + +impl PrettyDebug for Dictionary { + fn pretty(&self) -> DebugDocBuilder { + b::delimit( + "(", + b::intersperse( + self.entries() + .iter() + .map(|(key, value)| DebugEntry::new(key, value)), + b::space(), + ), + ")", + ) + } +} + +impl From> for Dictionary { + fn from(input: IndexMap) -> Dictionary { + let mut out = IndexMap::default(); + + for (key, value) in input { + out.insert(key, value); + } + + Dictionary::new(out) + } +} + +impl Dictionary { + pub fn get_data(&self, desc: &String) -> MaybeOwned<'_, Value> { + match self.entries.get(desc) { + Some(v) => MaybeOwned::Borrowed(v), + None => MaybeOwned::Owned( + UntaggedValue::Primitive(Primitive::Nothing).into_untagged_value(), + ), + } + } + + pub fn keys(&self) -> impl Iterator { + self.entries.keys() + } + + pub fn get_data_by_key(&self, name: Spanned<&str>) -> Option { + let result = self + .entries + .iter() + .find(|(desc_name, _)| *desc_name == name.item)? + .1; + + Some( + result + .value + .clone() + .into_value(Tag::new(result.tag.anchor(), name.span)), + ) + } + + pub fn get_mut_data_by_key(&mut self, name: &str) -> Option<&mut Value> { + match self + .entries + .iter_mut() + .find(|(desc_name, _)| *desc_name == name) + { + Some((_, v)) => Some(v), + None => None, + } + } + + pub fn insert_data_at_key(&mut self, name: &str, value: Value) { + self.entries.insert(name.to_string(), value); + } +} diff --git a/crates/nu-protocol/src/value/evaluate.rs b/crates/nu-protocol/src/value/evaluate.rs new file mode 100644 index 0000000000..9dea813809 --- /dev/null +++ b/crates/nu-protocol/src/value/evaluate.rs @@ -0,0 +1,102 @@ +use crate::value::{Primitive, UntaggedValue, Value}; +use indexmap::IndexMap; +use nu_errors::ShellError; +use query_interface::{interfaces, vtable_for, Object, ObjectHash}; +use serde::{Deserialize, Serialize}; +use std::cmp::{Ord, Ordering, PartialOrd}; +use std::fmt::Debug; + +#[derive(Debug)] +pub struct Scope { + pub it: Value, + pub vars: IndexMap, +} + +impl Scope { + pub fn new(it: Value) -> Scope { + Scope { + it, + vars: IndexMap::new(), + } + } +} + +impl Scope { + pub fn empty() -> Scope { + Scope { + it: UntaggedValue::Primitive(Primitive::Nothing).into_untagged_value(), + vars: IndexMap::new(), + } + } + + pub fn it_value(value: Value) -> Scope { + Scope { + it: value, + vars: IndexMap::new(), + } + } +} + +#[typetag::serde(tag = "type")] +pub trait EvaluateTrait: Debug + Send + Sync + Object + ObjectHash + 'static { + fn invoke(&self, scope: &Scope) -> Result; + fn clone_box(&self) -> Evaluate; +} + +interfaces!(Evaluate: dyn ObjectHash); + +#[typetag::serde] +impl EvaluateTrait for Evaluate { + fn invoke(&self, scope: &Scope) -> Result { + self.expr.invoke(scope) + } + + fn clone_box(&self) -> Evaluate { + self.expr.clone_box() + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Evaluate { + expr: Box, +} + +impl Evaluate { + pub fn new(evaluate: impl EvaluateTrait) -> Evaluate { + Evaluate { + expr: Box::new(evaluate), + } + } +} + +impl std::hash::Hash for Evaluate { + fn hash(&self, state: &mut H) { + self.expr.obj_hash(state) + } +} + +impl Clone for Evaluate { + fn clone(&self) -> Evaluate { + self.expr.clone_box() + } +} + +impl Ord for Evaluate { + fn cmp(&self, _: &Self) -> Ordering { + Ordering::Equal + } +} + +impl PartialOrd for Evaluate { + fn partial_cmp(&self, _: &Evaluate) -> Option { + Some(Ordering::Equal) + } +} + +impl PartialEq for Evaluate { + fn eq(&self, _: &Evaluate) -> bool { + true + } +} + +impl Eq for Evaluate {} diff --git a/crates/nu-protocol/src/value/primitive.rs b/crates/nu-protocol/src/value/primitive.rs new file mode 100644 index 0000000000..34bacb69ca --- /dev/null +++ b/crates/nu-protocol/src/value/primitive.rs @@ -0,0 +1,65 @@ +use crate::type_name::ShellTypeName; +use crate::value::column_path::ColumnPath; +use crate::value::{serde_bigdecimal, serde_bigint}; +use bigdecimal::BigDecimal; +use chrono::{DateTime, Utc}; +use num_bigint::BigInt; +use num_traits::cast::FromPrimitive; +use serde::{Deserialize, Serialize}; +use std::path::PathBuf; + +#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Deserialize, Serialize)] +pub enum Primitive { + Nothing, + #[serde(with = "serde_bigint")] + Int(BigInt), + #[serde(with = "serde_bigdecimal")] + Decimal(BigDecimal), + Bytes(u64), + String(String), + ColumnPath(ColumnPath), + Pattern(String), + Boolean(bool), + Date(DateTime), + Duration(u64), // Duration in seconds + Path(PathBuf), + #[serde(with = "serde_bytes")] + Binary(Vec), + + // Stream markers (used as bookend markers rather than actual values) + BeginningOfStream, + EndOfStream, +} + +impl From for Primitive { + fn from(decimal: BigDecimal) -> Primitive { + Primitive::Decimal(decimal) + } +} + +impl From for Primitive { + fn from(float: f64) -> Primitive { + Primitive::Decimal(BigDecimal::from_f64(float).unwrap()) + } +} + +impl ShellTypeName for Primitive { + fn type_name(&self) -> &'static str { + match self { + Primitive::Nothing => "nothing", + Primitive::Int(_) => "integer", + Primitive::Decimal(_) => "decimal", + Primitive::Bytes(_) => "bytes", + Primitive::String(_) => "string", + Primitive::ColumnPath(_) => "column path", + Primitive::Pattern(_) => "pattern", + Primitive::Boolean(_) => "boolean", + Primitive::Date(_) => "date", + Primitive::Duration(_) => "duration", + Primitive::Path(_) => "file path", + Primitive::Binary(_) => "binary", + Primitive::BeginningOfStream => "marker", + Primitive::EndOfStream => "marker", + } + } +} diff --git a/crates/nu-protocol/src/value/serde_bigdecimal.rs b/crates/nu-protocol/src/value/serde_bigdecimal.rs new file mode 100644 index 0000000000..423826887c --- /dev/null +++ b/crates/nu-protocol/src/value/serde_bigdecimal.rs @@ -0,0 +1,24 @@ +use bigdecimal::BigDecimal; +use num_traits::cast::FromPrimitive; +use num_traits::cast::ToPrimitive; + +pub fn serialize(big_decimal: &BigDecimal, serializer: S) -> Result +where + S: serde::Serializer, +{ + serde::Serialize::serialize( + &big_decimal + .to_f64() + .ok_or(serde::ser::Error::custom("expected a f64-sized bignum"))?, + serializer, + ) +} + +pub fn deserialize<'de, D>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, +{ + let x: f64 = serde::Deserialize::deserialize(deserializer)?; + Ok(BigDecimal::from_f64(x) + .ok_or(serde::de::Error::custom("expected a f64-sized bigdecimal"))?) +} diff --git a/crates/nu-protocol/src/value/serde_bigint.rs b/crates/nu-protocol/src/value/serde_bigint.rs new file mode 100644 index 0000000000..2ab4ec4dfe --- /dev/null +++ b/crates/nu-protocol/src/value/serde_bigint.rs @@ -0,0 +1,23 @@ +use num_bigint::BigInt; +use num_traits::cast::FromPrimitive; +use num_traits::cast::ToPrimitive; + +pub fn serialize(big_int: &BigInt, serializer: S) -> Result +where + S: serde::Serializer, +{ + serde::Serialize::serialize( + &big_int + .to_i64() + .ok_or(serde::ser::Error::custom("expected a i64-sized bignum"))?, + serializer, + ) +} + +pub fn deserialize<'de, D>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, +{ + let x: i64 = serde::Deserialize::deserialize(deserializer)?; + Ok(BigInt::from_i64(x).ok_or(serde::de::Error::custom("expected a i64-sized bignum"))?) +} diff --git a/crates/nu-source/Cargo.toml b/crates/nu-source/Cargo.toml index 1515dfa732..f30a937267 100644 --- a/crates/nu-source/Cargo.toml +++ b/crates/nu-source/Cargo.toml @@ -18,3 +18,6 @@ nom-tracable = "0.4.1" language-reporting = "0.4.0" termcolor = "1.0.5" pretty = "0.5.2" + +[build-dependencies] +nu-build = { version = "0.1.0", path = "../nu-build" } diff --git a/crates/nu-source/build.rs b/crates/nu-source/build.rs new file mode 100644 index 0000000000..b7511cfc6a --- /dev/null +++ b/crates/nu-source/build.rs @@ -0,0 +1,3 @@ +fn main() -> Result<(), Box> { + nu_build::build() +} diff --git a/crates/nu-source/src/lib.rs b/crates/nu-source/src/lib.rs index 840ba6a750..524e53b8c7 100644 --- a/crates/nu-source/src/lib.rs +++ b/crates/nu-source/src/lib.rs @@ -11,5 +11,6 @@ pub use self::meta::{ pub use self::pretty::{ b, DebugDoc, DebugDocBuilder, PrettyDebug, PrettyDebugWithSource, ShellAnnotation, }; +pub use self::term_colored::TermColored; pub use self::text::Text; pub use self::tracable::{nom_input, NomSpan, TracableContext}; diff --git a/crates/nu-textview/Cargo.toml b/crates/nu-textview/Cargo.toml new file mode 100644 index 0000000000..dab1b330b6 --- /dev/null +++ b/crates/nu-textview/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "nu-textview" +version = "0.1.0" +authors = ["Yehuda Katz "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[[bin]] +name = "nu_plugin_textview" +path = "src/main.rs" +required-features = ["textview"] + +[dependencies] + +syntect = { version = "3.2.0" } +ansi_term = "0.12.1" +crossterm = { version = "0.10.2" } +nu = { path = "../.." } +nu-protocol = { path = "../nu-protocol" } +nu-source = { path = "../nu-source" } +url = "2.1.0" + +[build-dependencies] +nu-build = { version = "0.1.0", path = "../nu-build" } diff --git a/crates/nu-textview/build.rs b/crates/nu-textview/build.rs new file mode 100644 index 0000000000..b7511cfc6a --- /dev/null +++ b/crates/nu-textview/build.rs @@ -0,0 +1,3 @@ +fn main() -> Result<(), Box> { + nu_build::build() +} diff --git a/src/plugins/textview.rs b/crates/nu-textview/src/main.rs similarity index 97% rename from src/plugins/textview.rs rename to crates/nu-textview/src/main.rs index dd6d3da341..208eaae810 100644 --- a/src/plugins/textview.rs +++ b/crates/nu-textview/src/main.rs @@ -1,8 +1,7 @@ use crossterm::{cursor, terminal, RawScreen}; use crossterm::{InputEvent, KeyEvent}; -use nu::{ - outln, serve_plugin, CallInfo, Plugin, Primitive, ShellError, Signature, UntaggedValue, Value, -}; +use nu::{CallInfo, Plugin, Primitive, ShellError, Signature, UntaggedValue, Value}; +use nu_protocol::{outln, serve_plugin}; use nu_source::AnchorLocation; use syntect::easy::HighlightLines; @@ -252,12 +251,12 @@ fn view_text_value(value: &Value) { Some(extension) => { // Load these once at the start of your program let ps: SyntaxSet = syntect::dumps::from_binary(include_bytes!( - "../../assets/syntaxes.bin" + "../../../assets/syntaxes.bin" )); if let Some(syntax) = ps.find_syntax_by_extension(&extension) { let ts: ThemeSet = syntect::dumps::from_binary(include_bytes!( - "../../assets/themes.bin" + "../../../assets/themes.bin" )); let mut h = HighlightLines::new(syntax, &ts.themes["OneHalfDark"]); diff --git a/docs/commands/config.md b/docs/commands/config.md index cae8e43ef3..3998b0dea9 100644 --- a/docs/commands/config.md +++ b/docs/commands/config.md @@ -6,7 +6,6 @@ Syntax: `config {flags}` ### Flags - --load load the config from the path give @@ -30,13 +29,13 @@ Syntax: `config {flags}` ### Variables -| Variable | Type | Description | -| ------------- | ------------- | ----- | -| path | table of strings | PATH to use to find binaries | -| env | row | the environment variables to pass to external commands | -| ctrlc_exit | boolean | whether or not to exit Nu after multiple ctrl-c presses | -| table_mode | "light" or other | enable lightweight or normal tables | -| edit_mode | "vi" or "emacs" | changes line editing to "vi" or "emacs" mode | +| Variable | Type | Description | +| ---------- | ---------------- | ------------------------------------------------------- | +| path | table of strings | PATH to use to find binaries | +| env | row | the environment variables to pass to external commands | +| ctrlc_exit | boolean | whether or not to exit Nu after multiple ctrl-c presses | +| table_mode | "light" or other | enable lightweight or normal tables | +| edit_mode | "vi" or "emacs" | changes line editing to "vi" or "emacs" mode | ## Examples diff --git a/docs/commands/from-yaml.md b/docs/commands/from-yaml.md index 1c7e9fef78..b8bf931e15 100644 --- a/docs/commands/from-yaml.md +++ b/docs/commands/from-yaml.md @@ -16,9 +16,9 @@ flags: false ```shell > open command_from-yaml | from-yaml ━━━━━━━━━━━┯━━━━━━━━━┯━━━━━━━ - title │ type │ flags + title │ type │ flags ───────────┼─────────┼─────── - from-yaml │ command │ No + from-yaml │ command │ No ━━━━━━━━━━━┷━━━━━━━━━┷━━━━━━━ ``` diff --git a/src/cli.rs b/src/cli.rs index 386d16734f..2c813c9dc4 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,27 +1,19 @@ -use crate::commands::classified::{ - ClassifiedCommand, ClassifiedInputStream, ClassifiedPipeline, ExternalArg, ExternalArgs, - ExternalCommand, InternalCommand, -}; +use crate::commands::classified::pipeline::run_pipeline; +use crate::commands::classified::ClassifiedInputStream; use crate::commands::plugin::JsonRpc; use crate::commands::plugin::{PluginCommand, PluginSink}; use crate::commands::whole_stream_command; use crate::context::Context; -use crate::data::{ - base::{UntaggedValue, Value}, - config, -}; -pub(crate) use crate::errors::ShellError; +use crate::data::config; #[cfg(not(feature = "starship-prompt"))] use crate::git::current_branch; -use crate::parser::registry::Signature; -use crate::parser::{ - hir, - hir::syntax_shape::{expand_syntax, ExpandContext, PipelineShape}, - hir::{expand_external_tokens::ExternalTokensShape, tokens_iterator::TokensIterator}, - TokenNode, -}; use crate::prelude::*; -use nu_source::{Spanned, Tagged}; +use nu_errors::ShellError; +use nu_parser::{ + expand_syntax, hir, ClassifiedCommand, ClassifiedPipeline, InternalCommand, PipelineShape, + TokenNode, TokensIterator, +}; +use nu_protocol::{Signature, UntaggedValue, Value}; use log::{debug, log_enabled, trace}; use rustyline::error::ReadlineError; @@ -32,21 +24,6 @@ use std::iter::Iterator; use std::path::PathBuf; use std::sync::atomic::Ordering; -#[derive(Debug)] -pub enum MaybeOwned<'a, T> { - Owned(T), - Borrowed(&'a T), -} - -impl MaybeOwned<'_, T> { - pub fn borrow(&self) -> &T { - match self { - MaybeOwned::Owned(v) => v, - MaybeOwned::Borrowed(v) => v, - } - } -} - fn load_plugin(path: &std::path::Path, context: &mut Context) -> Result<(), ShellError> { let mut child = std::process::Command::new(path) .stdin(std::process::Stdio::piped()) @@ -571,7 +548,7 @@ async fn process_line(readline: Result, ctx: &mut Context Ok(line) => { let line = chomp_newline(line); - let result = match crate::parser::parse(&line) { + let result = match nu_parser::parse(&line) { Err(err) => { return LineResult::Error(line.to_string(), err); } @@ -609,7 +586,8 @@ async fn process_line(readline: Result, ctx: &mut Context set_env_from_config(); let input = ClassifiedInputStream::new(); - match pipeline.run(ctx, input, line).await { + + match run_pipeline(pipeline, ctx, input, line).await { Ok(_) => LineResult::Success(line.to_string()), Err(err) => LineResult::Error(line.to_string(), err), } @@ -647,39 +625,13 @@ fn classify_pipeline( result } -// Classify this command as an external command, which doesn't give special meaning -// to nu syntactic constructs, and passes all arguments to the external command as -// strings. -pub(crate) fn external_command( - tokens: &mut TokensIterator, - context: &ExpandContext, - name: Tagged<&str>, -) -> Result { - let Spanned { item, span } = expand_syntax(&ExternalTokensShape, tokens, context)?.tokens; - - Ok(ClassifiedCommand::External(ExternalCommand { - name: name.to_string(), - name_tag: name.tag(), - args: ExternalArgs { - list: item - .iter() - .map(|x| ExternalArg { - tag: x.span.into(), - arg: x.item.clone(), - }) - .collect(), - span, - }, - })) -} - pub fn print_err(err: ShellError, host: &dyn Host, source: &Text) { let diag = err.to_diagnostic(); let writer = host.err_termcolor(); let mut source = source.to_string(); source.push_str(" "); - let files = crate::parser::Files::new(source); + let files = nu_parser::Files::new(source); let _ = std::panic::catch_unwind(move || { let _ = language_reporting::emit( &mut writer.lock(), diff --git a/src/commands.rs b/src/commands.rs index 705deb1d56..f2e6ef477b 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -99,7 +99,6 @@ pub(crate) use command::{ }; pub(crate) use append::Append; -pub(crate) use classified::ClassifiedCommand; pub(crate) use compact::Compact; pub(crate) use config::Config; pub(crate) use count::Count; diff --git a/src/commands/append.rs b/src/commands/append.rs index a41e3e4a23..9866e05f95 100644 --- a/src/commands/append.rs +++ b/src/commands/append.rs @@ -1,7 +1,8 @@ use crate::commands::WholeStreamCommand; -use crate::errors::ShellError; -use crate::parser::CommandRegistry; +use crate::context::CommandRegistry; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Signature, SyntaxShape, Value}; #[derive(Deserialize)] struct AppendArgs { diff --git a/src/commands/args.rs b/src/commands/args.rs index 85329af5a1..2e6961888c 100644 --- a/src/commands/args.rs +++ b/src/commands/args.rs @@ -1,4 +1,4 @@ -use crate::data::Value; +use nu_protocol::Value; #[derive(Debug)] pub enum LogLevel {} diff --git a/src/commands/autoview.rs b/src/commands/autoview.rs index 26e9532697..5c8bf1c982 100644 --- a/src/commands/autoview.rs +++ b/src/commands/autoview.rs @@ -1,8 +1,10 @@ use crate::commands::{RawCommandArgs, WholeStreamCommand}; -use crate::errors::ShellError; -use crate::parser::hir::{Expression, NamedArguments}; +use crate::data::value; use crate::prelude::*; use futures::stream::TryStreamExt; +use nu_errors::ShellError; +use nu_parser::hir::{Expression, NamedArguments}; +use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value}; use std::sync::atomic::Ordering; pub struct Autoview; @@ -137,7 +139,7 @@ pub fn autoview( } if anchor.is_some() => { if let Some(text) = text { let mut stream = VecDeque::new(); - stream.push_back(UntaggedValue::string(s).into_value(Tag { anchor, span })); + stream.push_back(value::string(s).into_value(Tag { anchor, span })); let result = text.run(raw.with_input(stream.into()), &context.commands); result.collect::>().await; } else { @@ -150,6 +152,24 @@ pub fn autoview( } => { outln!("{}", s); } + Value { + value: UntaggedValue::Primitive(Primitive::Path(s)), + .. + } => { + outln!("{}", s.display()); + } + Value { + value: UntaggedValue::Primitive(Primitive::Int(n)), + .. + } => { + outln!("{}", n); + } + Value { + value: UntaggedValue::Primitive(Primitive::Decimal(n)), + .. + } => { + outln!("{}", n); + } Value { value: UntaggedValue::Primitive(Primitive::Binary(ref b)), .. } => { if let Some(binary) = binary { @@ -188,7 +208,7 @@ pub fn autoview( // Needed for async_stream to type check if false { - yield ReturnSuccess::value(UntaggedValue::nothing().into_untagged_value()); + yield ReturnSuccess::value(value::nothing().into_untagged_value()); } })) } diff --git a/src/commands/cd.rs b/src/commands/cd.rs index 65cc45231d..b96619caed 100644 --- a/src/commands/cd.rs +++ b/src/commands/cd.rs @@ -1,6 +1,7 @@ use crate::commands::WholeStreamCommand; -use crate::errors::ShellError; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Signature, SyntaxShape}; pub struct CD; diff --git a/src/commands/classified/dynamic.rs b/src/commands/classified/dynamic.rs index 8e6e7d6510..31194f6b61 100644 --- a/src/commands/classified/dynamic.rs +++ b/src/commands/classified/dynamic.rs @@ -1,5 +1,5 @@ -use crate::parser::hir; use derive_new::new; +use nu_parser::hir; #[derive(new, Debug, Eq, PartialEq)] pub(crate) struct Command { diff --git a/src/commands/classified/external.rs b/src/commands/classified/external.rs index c72c487b3c..3ddb7a3276 100644 --- a/src/commands/classified/external.rs +++ b/src/commands/classified/external.rs @@ -1,12 +1,16 @@ -use super::ClassifiedInputStream; use crate::prelude::*; use bytes::{BufMut, BytesMut}; use futures::stream::StreamExt; use futures_codec::{Decoder, Encoder, Framed}; use log::trace; +use nu_errors::ShellError; +use nu_parser::ExternalCommand; +use nu_protocol::Value; use std::io::{Error, ErrorKind}; use subprocess::Exec; +use super::ClassifiedInputStream; + /// A simple `Codec` implementation that splits up data into lines. pub struct LinesCodec {} @@ -43,36 +47,6 @@ impl Decoder for LinesCodec { } } -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Command { - pub(crate) name: String, - - pub(crate) name_tag: Tag, - pub(crate) args: ExternalArgs, -} - -impl HasSpan for Command { - fn span(&self) -> Span { - self.name_tag.span.until(self.args.span) - } -} - -impl PrettyDebug for Command { - fn pretty(&self) -> DebugDocBuilder { - b::typed( - "external command", - b::description(&self.name) - + b::preceded( - b::space(), - b::intersperse( - self.args.iter().map(|a| b::primitive(format!("{}", a.arg))), - b::space(), - ), - ), - ) - } -} - #[derive(Debug)] pub(crate) enum StreamNext { Last, @@ -80,196 +54,156 @@ pub(crate) enum StreamNext { Internal, } -impl Command { - pub(crate) async fn run( - self, - context: &mut Context, - input: ClassifiedInputStream, - stream_next: StreamNext, - ) -> Result { - let stdin = input.stdin; - let inputs: Vec = input.objects.into_vec().await; +pub(crate) async fn run_external_command( + command: ExternalCommand, + context: &mut Context, + input: ClassifiedInputStream, + stream_next: StreamNext, +) -> Result { + let stdin = input.stdin; + let inputs: Vec = input.objects.into_vec().await; - trace!(target: "nu::run::external", "-> {}", self.name); - trace!(target: "nu::run::external", "inputs = {:?}", inputs); + trace!(target: "nu::run::external", "-> {}", command.name); + trace!(target: "nu::run::external", "inputs = {:?}", inputs); - let mut arg_string = format!("{}", self.name); - for arg in &self.args.list { - arg_string.push_str(&arg); - } + let mut arg_string = format!("{}", command.name); + for arg in command.args.iter() { + arg_string.push_str(&arg); + } - let home_dir = dirs::home_dir(); + let home_dir = dirs::home_dir(); - trace!(target: "nu::run::external", "command = {:?}", self.name); + trace!(target: "nu::run::external", "command = {:?}", command.name); - let mut process; - if arg_string.contains("$it") { - let input_strings = inputs - .iter() - .map(|i| { - i.as_string().map_err(|_| { - let arg = self.args.iter().find(|arg| arg.arg.contains("$it")); - if let Some(arg) = arg { - ShellError::labeled_error( - "External $it needs string data", - "given row instead of string data", - &arg.tag, - ) - } else { - ShellError::labeled_error( - "$it needs string data", - "given something else", - self.name_tag.clone(), - ) - } - }) - }) - .collect::, ShellError>>()?; - - let commands = input_strings.iter().map(|i| { - let args = self.args.iter().filter_map(|arg| { - if arg.chars().all(|c| c.is_whitespace()) { - None + let mut process; + if arg_string.contains("$it") { + let input_strings = inputs + .iter() + .map(|i| { + i.as_string().map(|s| s.to_string()).map_err(|_| { + let arg = command.args.iter().find(|arg| arg.contains("$it")); + if let Some(arg) = arg { + ShellError::labeled_error( + "External $it needs string data", + "given row instead of string data", + &arg.tag, + ) } else { - // Let's also replace ~ as we shell out - let arg = if let Some(ref home_dir) = home_dir { - arg.replace("~", home_dir.to_str().unwrap()) - } else { - arg.replace("~", "~") - }; - - Some(arg.replace("$it", &i)) + ShellError::labeled_error( + "$it needs string data", + "given something else", + command.name_tag.clone(), + ) } - }); + }) + }) + .collect::, ShellError>>()?; - format!("{} {}", self.name, itertools::join(args, " ")) + let commands = input_strings.iter().map(|i| { + let args = command.args.iter().filter_map(|arg| { + if arg.chars().all(|c| c.is_whitespace()) { + None + } else { + // Let's also replace ~ as we shell out + let arg = if let Some(ref home_dir) = home_dir { + arg.replace("~", home_dir.to_str().unwrap()) + } else { + arg.replace("~", "~") + }; + + Some(arg.replace("$it", &i)) + } }); - process = Exec::shell(itertools::join(commands, " && ")) - } else { - process = Exec::cmd(&self.name); - for arg in &self.args.list { - // Let's also replace ~ as we shell out - let arg = if let Some(ref home_dir) = home_dir { - arg.replace("~", home_dir.to_str().unwrap()) - } else { - arg.replace("~", "~") - }; + format!("{} {}", command.name, itertools::join(args, " ")) + }); - let arg_chars: Vec<_> = arg.chars().collect(); - if arg_chars.len() > 1 - && arg_chars[0] == '"' - && arg_chars[arg_chars.len() - 1] == '"' - { - // quoted string - let new_arg: String = arg_chars[1..arg_chars.len() - 1].iter().collect(); - process = process.arg(new_arg); - } else { - process = process.arg(arg.clone()); - } + process = Exec::shell(itertools::join(commands, " && ")) + } else { + process = Exec::cmd(&command.name); + for arg in command.args.iter() { + // Let's also replace ~ as we shell out + let arg = if let Some(ref home_dir) = home_dir { + arg.replace("~", home_dir.to_str().unwrap()) + } else { + arg.replace("~", "~") + }; + + let arg_chars: Vec<_> = arg.chars().collect(); + if arg_chars.len() > 1 && arg_chars[0] == '"' && arg_chars[arg_chars.len() - 1] == '"' { + // quoted string + let new_arg: String = arg_chars[1..arg_chars.len() - 1].iter().collect(); + process = process.arg(new_arg); + } else { + process = process.arg(arg.clone()); } } + } - process = process.cwd(context.shell_manager.path()); + process = process.cwd(context.shell_manager.path()); - trace!(target: "nu::run::external", "cwd = {:?}", context.shell_manager.path()); + trace!(target: "nu::run::external", "cwd = {:?}", context.shell_manager.path()); - let mut process = match stream_next { - StreamNext::Last => process, - StreamNext::External | StreamNext::Internal => { - process.stdout(subprocess::Redirection::Pipe) - } - }; - - trace!(target: "nu::run::external", "set up stdout pipe"); - - if let Some(stdin) = stdin { - process = process.stdin(stdin); + let mut process = match stream_next { + StreamNext::Last => process, + StreamNext::External | StreamNext::Internal => { + process.stdout(subprocess::Redirection::Pipe) } + }; - trace!(target: "nu::run::external", "set up stdin pipe"); - trace!(target: "nu::run::external", "built process {:?}", process); + trace!(target: "nu::run::external", "set up stdout pipe"); - let popen = process.popen(); + if let Some(stdin) = stdin { + process = process.stdin(stdin); + } - trace!(target: "nu::run::external", "next = {:?}", stream_next); + trace!(target: "nu::run::external", "set up stdin pipe"); + trace!(target: "nu::run::external", "built process {:?}", process); - let name_tag = self.name_tag.clone(); - if let Ok(mut popen) = popen { - match stream_next { - StreamNext::Last => { - let _ = popen.detach(); - loop { - match popen.poll() { - None => { - let _ = std::thread::sleep(std::time::Duration::new(0, 100000000)); - } - _ => { - let _ = popen.terminate(); - break; - } + let popen = process.popen(); + + trace!(target: "nu::run::external", "next = {:?}", stream_next); + + let name_tag = command.name_tag.clone(); + if let Ok(mut popen) = popen { + match stream_next { + StreamNext::Last => { + let _ = popen.detach(); + loop { + match popen.poll() { + None => { + let _ = std::thread::sleep(std::time::Duration::new(0, 100000000)); + } + _ => { + let _ = popen.terminate(); + break; } } - Ok(ClassifiedInputStream::new()) - } - StreamNext::External => { - let _ = popen.detach(); - let stdout = popen.stdout.take().unwrap(); - Ok(ClassifiedInputStream::from_stdout(stdout)) - } - StreamNext::Internal => { - let _ = popen.detach(); - let stdout = popen.stdout.take().unwrap(); - let file = futures::io::AllowStdIo::new(stdout); - let stream = Framed::new(file, LinesCodec {}); - let stream = stream.map(move |line| { - UntaggedValue::string(line.unwrap()).into_value(&name_tag) - }); - Ok(ClassifiedInputStream::from_input_stream( - stream.boxed() as BoxStream<'static, Value> - )) } + Ok(ClassifiedInputStream::new()) + } + StreamNext::External => { + let _ = popen.detach(); + let stdout = popen.stdout.take().unwrap(); + Ok(ClassifiedInputStream::from_stdout(stdout)) + } + StreamNext::Internal => { + let _ = popen.detach(); + let stdout = popen.stdout.take().unwrap(); + let file = futures::io::AllowStdIo::new(stdout); + let stream = Framed::new(file, LinesCodec {}); + let stream = + stream.map(move |line| value::string(line.unwrap()).into_value(&name_tag)); + Ok(ClassifiedInputStream::from_input_stream( + stream.boxed() as BoxStream<'static, Value> + )) } - } else { - return Err(ShellError::labeled_error( - "Command not found", - "command not found", - name_tag, - )); } - } -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct ExternalArg { - pub arg: String, - pub tag: Tag, -} - -impl std::ops::Deref for ExternalArg { - type Target = str; - - fn deref(&self) -> &str { - &self.arg - } -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct ExternalArgs { - pub list: Vec, - pub span: Span, -} - -impl ExternalArgs { - pub fn iter(&self) -> impl Iterator { - self.list.iter() - } -} - -impl std::ops::Deref for ExternalArgs { - type Target = [ExternalArg]; - - fn deref(&self) -> &[ExternalArg] { - &self.list + } else { + return Err(ShellError::labeled_error( + "Command not found", + "command not found", + name_tag, + )); } } diff --git a/src/commands/classified/internal.rs b/src/commands/classified/internal.rs index 582f7d7986..ee928bf7a5 100644 --- a/src/commands/classified/internal.rs +++ b/src/commands/classified/internal.rs @@ -1,147 +1,129 @@ -use crate::parser::hir; use crate::prelude::*; -use derive_new::new; use log::{log_enabled, trace}; +use nu_errors::ShellError; +use nu_parser::InternalCommand; +use nu_protocol::{CommandAction, Primitive, ReturnSuccess, UntaggedValue, Value}; use super::ClassifiedInputStream; -#[derive(new, Debug, Clone, Eq, PartialEq)] -pub struct Command { - pub(crate) name: String, - pub(crate) name_tag: Tag, - pub(crate) args: hir::Call, -} - -impl HasSpan for Command { - fn span(&self) -> Span { - let start = self.name_tag.span; - - start.until(self.args.span) +pub(crate) async fn run_internal_command( + command: InternalCommand, + context: &mut Context, + input: ClassifiedInputStream, + source: Text, +) -> Result { + if log_enabled!(log::Level::Trace) { + trace!(target: "nu::run::internal", "->"); + trace!(target: "nu::run::internal", "{}", command.name); + trace!(target: "nu::run::internal", "{}", command.args.debug(&source)); } -} -impl PrettyDebugWithSource for Command { - fn pretty_debug(&self, source: &str) -> DebugDocBuilder { - b::typed( - "internal command", - b::description(&self.name) + b::space() + self.args.pretty_debug(source), + let objects: InputStream = + trace_stream!(target: "nu::trace_stream::internal", "input" = input.objects); + + let internal_command = context.expect_command(&command.name); + + let result = { + context.run_command( + internal_command, + command.name_tag.clone(), + command.args, + &source, + objects, ) - } -} + }; -impl Command { - pub(crate) fn run( - self, - context: &mut Context, - input: ClassifiedInputStream, - source: Text, - ) -> Result { - if log_enabled!(log::Level::Trace) { - trace!(target: "nu::run::internal", "->"); - trace!(target: "nu::run::internal", "{}", self.name); - trace!(target: "nu::run::internal", "{}", self.args.debug(&source)); - } + let result = trace_out_stream!(target: "nu::trace_stream::internal", "output" = result); + let mut result = result.values; + let mut context = context.clone(); - let objects: InputStream = - trace_stream!(target: "nu::trace_stream::internal", "input" = input.objects); + let stream = async_stream! { + let mut soft_errs: Vec = vec![]; + let mut yielded = false; - let command = context.expect_command(&self.name); - - let result = - { context.run_command(command, self.name_tag.clone(), self.args, &source, objects) }; - - let result = trace_out_stream!(target: "nu::trace_stream::internal", "output" = result); - let mut result = result.values; - let mut context = context.clone(); - - let stream = async_stream! { - let mut soft_errs: Vec = vec![]; - let mut yielded = false; - - while let Some(item) = result.next().await { - match item { - Ok(ReturnSuccess::Action(action)) => match action { - CommandAction::ChangePath(path) => { - context.shell_manager.set_path(path); - } - CommandAction::Exit => std::process::exit(0), // TODO: save history.txt - CommandAction::Error(err) => { - context.error(err); - break; - } - CommandAction::EnterHelpShell(value) => { - match value { - Value { - value: UntaggedValue::Primitive(Primitive::String(cmd)), - tag, - } => { - context.shell_manager.insert_at_current(Box::new( - HelpShell::for_command( - UntaggedValue::string(cmd).into_value(tag), - &context.registry(), - ).unwrap(), - )); - } - _ => { - context.shell_manager.insert_at_current(Box::new( - HelpShell::index(&context.registry()).unwrap(), - )); - } - } - } - CommandAction::EnterValueShell(value) => { - context - .shell_manager - .insert_at_current(Box::new(ValueShell::new(value))); - } - CommandAction::EnterShell(location) => { - context.shell_manager.insert_at_current(Box::new( - FilesystemShell::with_location(location, context.registry().clone()).unwrap(), - )); - } - CommandAction::PreviousShell => { - context.shell_manager.prev(); - } - CommandAction::NextShell => { - context.shell_manager.next(); - } - CommandAction::LeaveShell => { - context.shell_manager.remove_at_current(); - if context.shell_manager.is_empty() { - std::process::exit(0); // TODO: save history.txt - } - } - }, - - Ok(ReturnSuccess::Value(v)) => { - yielded = true; - yield Ok(v); + while let Some(item) = result.next().await { + match item { + Ok(ReturnSuccess::Action(action)) => match action { + CommandAction::ChangePath(path) => { + context.shell_manager.set_path(path); } - - Ok(ReturnSuccess::DebugValue(v)) => { - yielded = true; - - let doc = PrettyDebug::pretty_doc(&v); - let mut buffer = termcolor::Buffer::ansi(); - - doc.render_raw( - context.with_host(|host| host.width() - 5), - &mut crate::parser::debug::TermColored::new(&mut buffer), - ).unwrap(); - - let value = String::from_utf8_lossy(buffer.as_slice()); - - yield Ok(UntaggedValue::string(value).into_untagged_value()) - } - - Err(err) => { + CommandAction::Exit => std::process::exit(0), // TODO: save history.txt + CommandAction::Error(err) => { context.error(err); break; } + CommandAction::EnterHelpShell(value) => { + match value { + Value { + value: UntaggedValue::Primitive(Primitive::String(cmd)), + tag, + } => { + context.shell_manager.insert_at_current(Box::new( + HelpShell::for_command( + value::string(cmd).into_value(tag), + &context.registry(), + ).unwrap(), + )); + } + _ => { + context.shell_manager.insert_at_current(Box::new( + HelpShell::index(&context.registry()).unwrap(), + )); + } + } + } + CommandAction::EnterValueShell(value) => { + context + .shell_manager + .insert_at_current(Box::new(ValueShell::new(value))); + } + CommandAction::EnterShell(location) => { + context.shell_manager.insert_at_current(Box::new( + FilesystemShell::with_location(location, context.registry().clone()).unwrap(), + )); + } + CommandAction::PreviousShell => { + context.shell_manager.prev(); + } + CommandAction::NextShell => { + context.shell_manager.next(); + } + CommandAction::LeaveShell => { + context.shell_manager.remove_at_current(); + if context.shell_manager.is_empty() { + std::process::exit(0); // TODO: save history.txt + } + } + }, + + Ok(ReturnSuccess::Value(v)) => { + yielded = true; + yield Ok(v); + } + + Ok(ReturnSuccess::DebugValue(v)) => { + yielded = true; + + let doc = PrettyDebug::pretty_doc(&v); + let mut buffer = termcolor::Buffer::ansi(); + + doc.render_raw( + context.with_host(|host| host.width() - 5), + &mut nu_source::TermColored::new(&mut buffer), + ).unwrap(); + + let value = String::from_utf8_lossy(buffer.as_slice()); + + yield Ok(value::string(value).into_untagged_value()) + } + + Err(err) => { + context.error(err); + break; } } - }; + } + }; - Ok(stream.to_input_stream()) - } + Ok(stream.to_input_stream()) } diff --git a/src/commands/classified/mod.rs b/src/commands/classified/mod.rs index b3add6eccb..f786c8dabd 100644 --- a/src/commands/classified/mod.rs +++ b/src/commands/classified/mod.rs @@ -1,17 +1,13 @@ -use crate::parser::{hir, TokenNode}; +use crate::data::value; use crate::prelude::*; mod dynamic; -mod external; -mod internal; -mod pipeline; +pub(crate) mod external; +pub(crate) mod internal; +pub(crate) mod pipeline; #[allow(unused_imports)] pub(crate) use dynamic::Command as DynamicCommand; -#[allow(unused_imports)] -pub(crate) use external::{Command as ExternalCommand, ExternalArg, ExternalArgs, StreamNext}; -pub(crate) use internal::Command as InternalCommand; -pub(crate) use pipeline::Pipeline as ClassifiedPipeline; pub(crate) struct ClassifiedInputStream { pub(crate) objects: InputStream, @@ -21,7 +17,7 @@ pub(crate) struct ClassifiedInputStream { impl ClassifiedInputStream { pub(crate) fn new() -> ClassifiedInputStream { ClassifiedInputStream { - objects: vec![UntaggedValue::nothing().into_untagged_value()].into(), + objects: vec![value::nothing().into_value(Tag::unknown())].into(), stdin: None, } } @@ -40,35 +36,3 @@ impl ClassifiedInputStream { } } } - -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum ClassifiedCommand { - #[allow(unused)] - Expr(TokenNode), - #[allow(unused)] - Dynamic(hir::Call), - Internal(InternalCommand), - External(ExternalCommand), -} - -impl PrettyDebugWithSource for ClassifiedCommand { - fn pretty_debug(&self, source: &str) -> DebugDocBuilder { - match self { - ClassifiedCommand::Expr(token) => b::typed("command", token.pretty_debug(source)), - ClassifiedCommand::Dynamic(call) => b::typed("command", call.pretty_debug(source)), - ClassifiedCommand::Internal(internal) => internal.pretty_debug(source), - ClassifiedCommand::External(external) => external.pretty_debug(source), - } - } -} - -impl HasSpan for ClassifiedCommand { - fn span(&self) -> Span { - match self { - ClassifiedCommand::Expr(node) => node.span(), - ClassifiedCommand::Internal(command) => command.span(), - ClassifiedCommand::Dynamic(call) => call.span, - ClassifiedCommand::External(command) => command.span(), - } - } -} diff --git a/src/commands/classified/pipeline.rs b/src/commands/classified/pipeline.rs index a9e829023e..253f7b0c27 100644 --- a/src/commands/classified/pipeline.rs +++ b/src/commands/classified/pipeline.rs @@ -1,107 +1,74 @@ -use super::{ClassifiedCommand, ClassifiedInputStream, StreamNext}; -use crate::data::base::Value; -use crate::prelude::*; +use crate::commands::classified::external::{run_external_command, StreamNext}; +use crate::commands::classified::internal::run_internal_command; +use crate::commands::classified::ClassifiedInputStream; +use crate::context::Context; +use crate::stream::OutputStream; +use nu_errors::ShellError; +use nu_parser::{ClassifiedCommand, ClassifiedPipeline}; +use nu_protocol::{ReturnSuccess, UntaggedValue, Value}; +use nu_source::Text; use std::sync::atomic::Ordering; -#[derive(Debug, Clone)] -pub(crate) struct Pipeline { - pub(crate) commands: ClassifiedCommands, -} +pub(crate) async fn run_pipeline( + pipeline: ClassifiedPipeline, + ctx: &mut Context, + mut input: ClassifiedInputStream, + line: &str, +) -> Result<(), ShellError> { + let mut iter = pipeline.commands.list.into_iter().peekable(); -impl Pipeline { - pub fn commands(list: Vec, span: impl Into) -> Pipeline { - Pipeline { - commands: ClassifiedCommands { - list, - span: span.into(), - }, - } + loop { + let item: Option = iter.next(); + let next: Option<&ClassifiedCommand> = iter.peek(); + + input = match (item, next) { + (Some(ClassifiedCommand::Dynamic(_)), _) | (_, Some(ClassifiedCommand::Dynamic(_))) => { + return Err(ShellError::unimplemented("Dynamic commands")) + } + + (Some(ClassifiedCommand::Expr(_)), _) | (_, Some(ClassifiedCommand::Expr(_))) => { + return Err(ShellError::unimplemented("Expression-only commands")) + } + + (Some(ClassifiedCommand::Internal(left)), _) => { + let stream = run_internal_command(left, ctx, input, Text::from(line)).await?; + ClassifiedInputStream::from_input_stream(stream) + } + + (Some(ClassifiedCommand::External(left)), Some(ClassifiedCommand::External(_))) => { + run_external_command(left, ctx, input, StreamNext::External).await? + } + + (Some(ClassifiedCommand::External(left)), Some(_)) => { + run_external_command(left, ctx, input, StreamNext::Internal).await? + } + + (Some(ClassifiedCommand::External(left)), None) => { + run_external_command(left, ctx, input, StreamNext::Last).await? + } + + (None, _) => break, + }; } - pub(crate) async fn run( - self, - ctx: &mut Context, - mut input: ClassifiedInputStream, - line: &str, - ) -> Result<(), ShellError> { - let mut iter = self.commands.list.into_iter().peekable(); - - loop { - let item: Option = iter.next(); - let next: Option<&ClassifiedCommand> = iter.peek(); - - input = match (item, next) { - (Some(ClassifiedCommand::Dynamic(_)), _) - | (_, Some(ClassifiedCommand::Dynamic(_))) => { - return Err(ShellError::unimplemented("Dynamic commands")) - } - - (Some(ClassifiedCommand::Expr(_)), _) | (_, Some(ClassifiedCommand::Expr(_))) => { - return Err(ShellError::unimplemented("Expression-only commands")) - } - - (Some(ClassifiedCommand::Internal(left)), _) => { - let stream = left.run(ctx, input, Text::from(line))?; - ClassifiedInputStream::from_input_stream(stream) - } - - (Some(ClassifiedCommand::External(left)), Some(ClassifiedCommand::External(_))) => { - left.run(ctx, input, StreamNext::External).await? - } - - (Some(ClassifiedCommand::External(left)), Some(_)) => { - left.run(ctx, input, StreamNext::Internal).await? - } - - (Some(ClassifiedCommand::External(left)), None) => { - left.run(ctx, input, StreamNext::Last).await? - } - - (None, _) => break, - }; - } - - use futures::stream::TryStreamExt; - let mut output_stream: OutputStream = input.objects.into(); - loop { - match output_stream.try_next().await { - Ok(Some(ReturnSuccess::Value(Value { - value: UntaggedValue::Error(e), - .. - }))) => return Err(e), - Ok(Some(_item)) => { - if ctx.ctrl_c.load(Ordering::SeqCst) { - break; - } - } - _ => { + use futures::stream::TryStreamExt; + let mut output_stream: OutputStream = input.objects.into(); + loop { + match output_stream.try_next().await { + Ok(Some(ReturnSuccess::Value(Value { + value: UntaggedValue::Error(e), + .. + }))) => return Err(e), + Ok(Some(_item)) => { + if ctx.ctrl_c.load(Ordering::SeqCst) { break; } } + _ => { + break; + } } - - Ok(()) } -} -#[derive(Debug, Clone)] -pub struct ClassifiedCommands { - pub list: Vec, - pub span: Span, -} - -impl HasSpan for Pipeline { - fn span(&self) -> Span { - self.commands.span - } -} - -impl PrettyDebugWithSource for Pipeline { - fn pretty_debug(&self, source: &str) -> DebugDocBuilder { - b::intersperse( - self.commands.list.iter().map(|c| c.pretty_debug(source)), - b::operator(" | "), - ) - .or(b::delimit("<", b::description("empty pipeline"), ">")) - } + Ok(()) } diff --git a/src/commands/clip.rs b/src/commands/clip.rs index 3b59d9eed6..de10ffca14 100644 --- a/src/commands/clip.rs +++ b/src/commands/clip.rs @@ -2,9 +2,10 @@ pub mod clipboard { use crate::commands::WholeStreamCommand; use crate::context::CommandRegistry; - use crate::errors::ShellError; use crate::prelude::*; use futures::stream::StreamExt; + use nu_errors::ShellError; + use nu_protocol::{ReturnValue, Signature, Value}; use clipboard::{ClipboardContext, ClipboardProvider}; @@ -67,7 +68,7 @@ pub mod clipboard { } let string: String = match i.as_string() { - Ok(string) => string, + Ok(string) => string.to_string(), Err(_) => { return OutputStream::one(Err(ShellError::labeled_error( "Given non-string data", diff --git a/src/commands/command.rs b/src/commands/command.rs index 97c4fa373a..9be654ce0e 100644 --- a/src/commands/command.rs +++ b/src/commands/command.rs @@ -1,14 +1,14 @@ -use crate::data::Value; -use crate::errors::ShellError; -use crate::evaluate::Scope; -use crate::parser::hir; -use crate::parser::{registry, ConfigDeserializer}; +use crate::context::CommandRegistry; +use crate::deserializer::ConfigDeserializer; +use crate::evaluate::evaluate_args::evaluate_args; use crate::prelude::*; use derive_new::new; use getset::Getters; +use nu_errors::ShellError; +use nu_parser::hir; +use nu_protocol::{CallInfo, EvaluatedArgs, ReturnValue, Scope, Signature, Value}; use serde::{Deserialize, Serialize}; use std::ops::Deref; -use std::path::PathBuf; use std::sync::atomic::AtomicBool; #[derive(Deserialize, Serialize, Debug, Clone)] @@ -21,10 +21,10 @@ pub struct UnevaluatedCallInfo { impl UnevaluatedCallInfo { pub fn evaluate( self, - registry: ®istry::CommandRegistry, + registry: &CommandRegistry, scope: &Scope, ) -> Result { - let args = self.args.evaluate(registry, scope, &self.source)?; + let args = evaluate_args(&self.args, registry, scope, &self.source)?; Ok(CallInfo { args, @@ -33,14 +33,16 @@ impl UnevaluatedCallInfo { } } -#[derive(Deserialize, Serialize, Debug, Clone)] -pub struct CallInfo { - pub args: registry::EvaluatedArgs, - pub name_tag: Tag, +pub trait CallInfoExt { + fn process<'de, T: Deserialize<'de>>( + &self, + shell_manager: &ShellManager, + callback: fn(T, &RunnablePerItemContext) -> Result, + ) -> Result, ShellError>; } -impl CallInfo { - pub fn process<'de, T: Deserialize<'de>>( +impl CallInfoExt for CallInfo { + fn process<'de, T: Deserialize<'de>>( &self, shell_manager: &ShellManager, callback: fn(T, &RunnablePerItemContext) -> Result, @@ -87,10 +89,6 @@ impl RawCommandArgs { input: input.into(), } } - - pub fn source(&self) -> Text { - self.call_info.source.clone() - } } impl std::fmt::Debug for CommandArgs { @@ -102,7 +100,7 @@ impl std::fmt::Debug for CommandArgs { impl CommandArgs { pub fn evaluate_once( self, - registry: ®istry::CommandRegistry, + registry: &CommandRegistry, ) -> Result { let host = self.host.clone(); let ctrl_c = self.ctrl_c.clone(); @@ -198,12 +196,6 @@ pub struct RunnablePerItemContext { pub name: Tag, } -impl RunnablePerItemContext { - pub fn cwd(&self) -> PathBuf { - PathBuf::from(self.shell_manager.path()) - } -} - pub struct RunnableContext { pub input: InputStream, pub shell_manager: ShellManager, @@ -295,7 +287,7 @@ impl EvaluatedWholeStreamCommandArgs { self.args.call_info.name_tag.clone() } - pub fn parts(self) -> (InputStream, registry::EvaluatedArgs) { + pub fn parts(self) -> (InputStream, EvaluatedArgs) { let EvaluatedWholeStreamCommandArgs { args, input } = self; (input, args.call_info.args) @@ -349,112 +341,19 @@ pub struct EvaluatedCommandArgs { } impl EvaluatedCommandArgs { - pub fn call_args(&self) -> ®istry::EvaluatedArgs { - &self.call_info.args - } - pub fn nth(&self, pos: usize) -> Option<&Value> { self.call_info.args.nth(pos) } - pub fn expect_nth(&self, pos: usize) -> Result<&Value, ShellError> { - self.call_info.args.expect_nth(pos) - } - - pub fn len(&self) -> usize { - self.call_info.args.len() - } - pub fn get(&self, name: &str) -> Option<&Value> { self.call_info.args.get(name) } - pub fn slice_from(&self, from: usize) -> Vec { - let positional = &self.call_info.args.positional; - - match positional { - None => vec![], - Some(list) => list[from..].to_vec(), - } - } - pub fn has(&self, name: &str) -> bool { self.call_info.args.has(name) } } -#[derive(Debug, Clone, Serialize, Deserialize)] -pub enum CommandAction { - ChangePath(String), - Exit, - Error(ShellError), - EnterShell(String), - EnterValueShell(Value), - EnterHelpShell(Value), - PreviousShell, - NextShell, - LeaveShell, -} - -impl PrettyDebug for CommandAction { - fn pretty(&self) -> DebugDocBuilder { - match self { - CommandAction::ChangePath(path) => b::typed("change path", b::description(path)), - CommandAction::Exit => b::description("exit"), - CommandAction::Error(_) => b::error("error"), - CommandAction::EnterShell(s) => b::typed("enter shell", b::description(s)), - CommandAction::EnterValueShell(v) => b::typed("enter value shell", v.pretty()), - CommandAction::EnterHelpShell(v) => b::typed("enter help shell", v.pretty()), - CommandAction::PreviousShell => b::description("previous shell"), - CommandAction::NextShell => b::description("next shell"), - CommandAction::LeaveShell => b::description("leave shell"), - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub enum ReturnSuccess { - Value(Value), - DebugValue(Value), - Action(CommandAction), -} - -impl PrettyDebug for ReturnSuccess { - fn pretty(&self) -> DebugDocBuilder { - match self { - ReturnSuccess::Value(value) => b::typed("value", value.pretty()), - ReturnSuccess::DebugValue(value) => b::typed("debug value", value.pretty()), - ReturnSuccess::Action(action) => b::typed("action", action.pretty()), - } - } -} - -pub type ReturnValue = Result; - -impl From for ReturnValue { - fn from(input: Value) -> ReturnValue { - Ok(ReturnSuccess::Value(input)) - } -} - -impl ReturnSuccess { - pub fn change_cwd(path: String) -> ReturnValue { - Ok(ReturnSuccess::Action(CommandAction::ChangePath(path))) - } - - pub fn value(input: impl Into) -> ReturnValue { - Ok(ReturnSuccess::Value(input.into())) - } - - pub fn debug_value(input: impl Into) -> ReturnValue { - Ok(ReturnSuccess::DebugValue(input.into())) - } - - pub fn action(input: CommandAction) -> ReturnValue { - Ok(ReturnSuccess::Action(input)) - } -} - pub trait WholeStreamCommand: Send + Sync { fn name(&self) -> &str; @@ -474,7 +373,7 @@ pub trait WholeStreamCommand: Send + Sync { fn run( &self, args: CommandArgs, - registry: ®istry::CommandRegistry, + registry: &CommandRegistry, ) -> Result; fn is_binary(&self) -> bool { @@ -570,7 +469,7 @@ impl Command { } } - pub fn run(&self, args: CommandArgs, registry: ®istry::CommandRegistry) -> OutputStream { + pub fn run(&self, args: CommandArgs, registry: &CommandRegistry) -> OutputStream { match self { Command::WholeStream(command) => match command.run(args, registry) { Ok(stream) => stream, @@ -637,7 +536,7 @@ impl WholeStreamCommand for FnFilterCommand { fn run( &self, args: CommandArgs, - registry: ®istry::CommandRegistry, + registry: &CommandRegistry, ) -> Result { let CommandArgs { host, @@ -649,7 +548,7 @@ impl WholeStreamCommand for FnFilterCommand { let host: Arc> = host.clone(); let shell_manager = shell_manager.clone(); - let registry: registry::CommandRegistry = registry.clone(); + let registry: CommandRegistry = registry.clone(); let func = self.func; let result = input.values.map(move |it| { diff --git a/src/commands/compact.rs b/src/commands/compact.rs index b2bd01b29d..94ee9dc4f7 100644 --- a/src/commands/compact.rs +++ b/src/commands/compact.rs @@ -1,9 +1,9 @@ use crate::commands::WholeStreamCommand; -use crate::data::base::UntaggedValue; -use crate::errors::ShellError; -use crate::parser::registry::{CommandRegistry, Signature}; +use crate::context::CommandRegistry; use crate::prelude::*; use futures::stream::StreamExt; +use nu_errors::ShellError; +use nu_protocol::{Signature, SyntaxShape, UntaggedValue, Value}; use nu_source::Tagged; pub struct Compact; diff --git a/src/commands/config.rs b/src/commands/config.rs index 1cabfd2c57..eaa7dbab0b 100644 --- a/src/commands/config.rs +++ b/src/commands/config.rs @@ -1,9 +1,9 @@ use crate::commands::WholeStreamCommand; -use crate::data::{config, Value}; -use crate::errors::ShellError; -use crate::parser::hir::SyntaxShape; -use crate::parser::registry::{self}; +use crate::context::CommandRegistry; +use crate::data::config; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; use nu_source::Tagged; use std::path::PathBuf; @@ -55,7 +55,7 @@ impl WholeStreamCommand for Config { fn run( &self, args: CommandArgs, - registry: ®istry::CommandRegistry, + registry: &CommandRegistry, ) -> Result { args.process(registry, config)?.run() } diff --git a/src/commands/count.rs b/src/commands/count.rs index 1bfa746f6a..f6b7b78cb4 100644 --- a/src/commands/count.rs +++ b/src/commands/count.rs @@ -1,9 +1,10 @@ use crate::commands::WholeStreamCommand; -use crate::data::Value; -use crate::errors::ShellError; -use crate::parser::CommandRegistry; +use crate::context::CommandRegistry; +use crate::data::value; use crate::prelude::*; use futures::stream::StreamExt; +use nu_errors::ShellError; +use nu_protocol::{ReturnSuccess, Signature, Value}; pub struct Count; @@ -39,7 +40,7 @@ pub fn count( let stream = async_stream! { let rows: Vec = input.values.collect().await; - yield ReturnSuccess::value(UntaggedValue::int(rows.len()).into_value(name)) + yield ReturnSuccess::value(value::int(rows.len()).into_value(name)) }; Ok(stream.to_output_stream()) diff --git a/src/commands/cp.rs b/src/commands/cp.rs index 2ef0af269b..4919dc3758 100644 --- a/src/commands/cp.rs +++ b/src/commands/cp.rs @@ -1,8 +1,8 @@ use crate::commands::command::RunnablePerItemContext; -use crate::errors::ShellError; -use crate::parser::hir::SyntaxShape; -use crate::parser::registry::{CommandRegistry, Signature}; +use crate::context::CommandRegistry; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{CallInfo, Signature, SyntaxShape, Value}; use nu_source::Tagged; use std::path::PathBuf; diff --git a/src/commands/date.rs b/src/commands/date.rs index d4c094819f..438939daca 100644 --- a/src/commands/date.rs +++ b/src/commands/date.rs @@ -1,13 +1,14 @@ -use crate::data::{Dictionary, Value}; -use crate::errors::ShellError; use crate::prelude::*; use chrono::{DateTime, Local, Utc}; +use nu_errors::ShellError; +use nu_protocol::{Dictionary, Value}; use crate::commands::WholeStreamCommand; -use crate::parser::registry::Signature; +use crate::data::value; use chrono::{Datelike, TimeZone, Timelike}; use core::fmt::Display; use indexmap::IndexMap; +use nu_protocol::{Signature, UntaggedValue}; pub struct Date; @@ -41,35 +42,23 @@ where { let mut indexmap = IndexMap::new(); - indexmap.insert( - "year".to_string(), - UntaggedValue::int(dt.year()).into_value(&tag), - ); - indexmap.insert( - "month".to_string(), - UntaggedValue::int(dt.month()).into_value(&tag), - ); - indexmap.insert( - "day".to_string(), - UntaggedValue::int(dt.day()).into_value(&tag), - ); - indexmap.insert( - "hour".to_string(), - UntaggedValue::int(dt.hour()).into_value(&tag), - ); + indexmap.insert("year".to_string(), value::int(dt.year()).into_value(&tag)); + indexmap.insert("month".to_string(), value::int(dt.month()).into_value(&tag)); + indexmap.insert("day".to_string(), value::int(dt.day()).into_value(&tag)); + indexmap.insert("hour".to_string(), value::int(dt.hour()).into_value(&tag)); indexmap.insert( "minute".to_string(), - UntaggedValue::int(dt.minute()).into_value(&tag), + value::int(dt.minute()).into_value(&tag), ); indexmap.insert( "second".to_string(), - UntaggedValue::int(dt.second()).into_value(&tag), + value::int(dt.second()).into_value(&tag), ); let tz = dt.offset(); indexmap.insert( "timezone".to_string(), - UntaggedValue::string(format!("{}", tz)).into_value(&tag), + value::string(format!("{}", tz)).into_value(&tag), ); UntaggedValue::Row(Dictionary::from(indexmap)).into_value(&tag) diff --git a/src/commands/debug.rs b/src/commands/debug.rs index 63662fece5..e19995e6b1 100644 --- a/src/commands/debug.rs +++ b/src/commands/debug.rs @@ -1,5 +1,8 @@ use crate::commands::WholeStreamCommand; +use crate::data::value; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{ReturnSuccess, Signature}; pub struct Debug; @@ -34,8 +37,6 @@ fn debug_value( ) -> Result { Ok(input .values - .map(|v| { - ReturnSuccess::value(UntaggedValue::string(format!("{:?}", v)).into_untagged_value()) - }) + .map(|v| ReturnSuccess::value(value::string(format!("{:?}", v)).into_untagged_value())) .to_output_stream()) } diff --git a/src/commands/default.rs b/src/commands/default.rs index 9107eb9d0d..c423f06b2b 100644 --- a/src/commands/default.rs +++ b/src/commands/default.rs @@ -1,7 +1,8 @@ use crate::commands::WholeStreamCommand; -use crate::errors::ShellError; -use crate::parser::CommandRegistry; +use crate::context::CommandRegistry; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; use nu_source::Tagged; #[derive(Deserialize)] diff --git a/src/commands/echo.rs b/src/commands/echo.rs index 45b6daf479..50a995ae9d 100644 --- a/src/commands/echo.rs +++ b/src/commands/echo.rs @@ -1,8 +1,7 @@ -use crate::data::Value; -use crate::errors::ShellError; +use crate::data::value; use crate::prelude::*; - -use crate::parser::registry::Signature; +use nu_errors::ShellError; +use nu_protocol::{CallInfo, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; pub struct Echo; @@ -42,7 +41,7 @@ fn run( match i.as_string() { Ok(s) => { output.push(Ok(ReturnSuccess::Value( - UntaggedValue::string(s).into_value(i.tag.clone()), + value::string(s).into_value(i.tag.clone()), ))); } _ => match i { diff --git a/src/commands/enter.rs b/src/commands/enter.rs index 66d5c0c86e..26e55291ff 100644 --- a/src/commands/enter.rs +++ b/src/commands/enter.rs @@ -1,9 +1,12 @@ -use crate::commands::command::CommandAction; use crate::commands::PerItemCommand; use crate::commands::UnevaluatedCallInfo; -use crate::errors::ShellError; -use crate::parser::registry; +use crate::context::CommandRegistry; +use crate::data::value; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{ + CallInfo, CommandAction, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value, +}; use std::path::PathBuf; pub struct Enter; @@ -13,7 +16,7 @@ impl PerItemCommand for Enter { "enter" } - fn signature(&self) -> registry::Signature { + fn signature(&self) -> Signature { Signature::build("enter").required( "location", SyntaxShape::Path, @@ -28,7 +31,7 @@ impl PerItemCommand for Enter { fn run( &self, call_info: &CallInfo, - registry: ®istry::CommandRegistry, + registry: &CommandRegistry, raw_args: &RawCommandArgs, _input: Value, ) -> Result { @@ -51,12 +54,12 @@ impl PerItemCommand for Enter { if registry.has(command) { Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterHelpShell( - UntaggedValue::string(command).into_value(Tag::unknown()), + value::string(command).into_value(Tag::unknown()), )))] .into()) } else { Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterHelpShell( - UntaggedValue::nothing().into_value(Tag::unknown()), + value::nothing().into_value(Tag::unknown()), )))] .into()) } @@ -93,7 +96,7 @@ impl PerItemCommand for Enter { ctrl_c: raw_args.ctrl_c, shell_manager: raw_args.shell_manager, call_info: UnevaluatedCallInfo { - args: crate::parser::hir::Call { + args: nu_parser::hir::Call { head: raw_args.call_info.args.head, positional: None, named: None, diff --git a/src/commands/env.rs b/src/commands/env.rs index add9df82ff..e7385c3202 100644 --- a/src/commands/env.rs +++ b/src/commands/env.rs @@ -1,12 +1,11 @@ use crate::cli::History; -use crate::data::config; -use crate::data::{Dictionary, Value}; -use crate::errors::ShellError; +use crate::data::{config, value}; use crate::prelude::*; use crate::TaggedDictBuilder; +use nu_errors::ShellError; +use nu_protocol::{Dictionary, Signature, UntaggedValue, Value}; use crate::commands::WholeStreamCommand; -use crate::parser::registry::Signature; use indexmap::IndexMap; pub struct Env; @@ -37,39 +36,24 @@ pub fn get_environment(tag: Tag) -> Result> { let mut indexmap = IndexMap::new(); let path = std::env::current_dir()?; - indexmap.insert( - "cwd".to_string(), - UntaggedValue::path(path).into_value(&tag), - ); + indexmap.insert("cwd".to_string(), value::path(path).into_value(&tag)); if let Some(home) = dirs::home_dir() { - indexmap.insert( - "home".to_string(), - UntaggedValue::path(home).into_value(&tag), - ); + indexmap.insert("home".to_string(), value::path(home).into_value(&tag)); } let config = config::default_path()?; - indexmap.insert( - "config".to_string(), - UntaggedValue::path(config).into_value(&tag), - ); + indexmap.insert("config".to_string(), value::path(config).into_value(&tag)); let history = History::path(); - indexmap.insert( - "history".to_string(), - UntaggedValue::path(history).into_value(&tag), - ); + indexmap.insert("history".to_string(), value::path(history).into_value(&tag)); let temp = std::env::temp_dir(); - indexmap.insert( - "temp".to_string(), - UntaggedValue::path(temp).into_value(&tag), - ); + indexmap.insert("temp".to_string(), value::path(temp).into_value(&tag)); let mut dict = TaggedDictBuilder::new(&tag); for v in std::env::vars() { - dict.insert_untagged(v.0, UntaggedValue::string(v.1)); + dict.insert_untagged(v.0, value::string(v.1)); } if !dict.is_empty() { indexmap.insert("vars".to_string(), dict.into_value()); diff --git a/src/commands/evaluate_by.rs b/src/commands/evaluate_by.rs index d0d568f9aa..08559758e0 100644 --- a/src/commands/evaluate_by.rs +++ b/src/commands/evaluate_by.rs @@ -1,6 +1,8 @@ use crate::commands::WholeStreamCommand; -use crate::parser::hir::SyntaxShape; +use crate::data::value; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; use nu_source::{SpannedItem, Tagged}; pub struct EvaluateBy; @@ -71,7 +73,7 @@ pub fn evaluate_by( fn fetch(key: Option) -> Box Option + 'static> { Box::new(move |value: Value, tag| match &key { Some(key_given) => value.get_data_by_key(key_given[..].spanned(tag.span)), - None => Some(UntaggedValue::int(1).into_value(tag)), + None => Some(value::int(1).into_value(tag)), }) } @@ -136,25 +138,26 @@ mod tests { use crate::commands::evaluate_by::{evaluate, fetch}; use crate::commands::group_by::group; use crate::commands::t_sort_by::t_sort; + use crate::data::value; use crate::prelude::*; - use crate::Value; use indexmap::IndexMap; + use nu_protocol::{UntaggedValue, Value}; use nu_source::TaggedItem; fn int(s: impl Into) -> Value { - UntaggedValue::int(s).into_untagged_value() + value::int(s).into_untagged_value() } fn string(input: impl Into) -> Value { - UntaggedValue::string(input.into()).into_untagged_value() + value::string(input.into()).into_untagged_value() } fn row(entries: IndexMap) -> Value { - UntaggedValue::row(entries).into_untagged_value() + value::row(entries).into_untagged_value() } fn table(list: &Vec) -> Value { - UntaggedValue::table(list).into_untagged_value() + value::table(list).into_untagged_value() } fn nu_releases_sorted_by_date() -> Value { @@ -222,7 +225,7 @@ mod tests { assert_eq!( evaluator(subject, Tag::unknown()), - Some(UntaggedValue::int(1).into_untagged_value()) + Some(value::int(1).into_untagged_value()) ); } diff --git a/src/commands/exit.rs b/src/commands/exit.rs index b7db7cc340..fc22502ebc 100644 --- a/src/commands/exit.rs +++ b/src/commands/exit.rs @@ -1,7 +1,8 @@ -use crate::commands::command::{CommandAction, WholeStreamCommand}; -use crate::errors::ShellError; -use crate::parser::registry::{CommandRegistry, Signature}; +use crate::commands::command::WholeStreamCommand; +use crate::context::CommandRegistry; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{CommandAction, ReturnSuccess, Signature}; pub struct Exit; diff --git a/src/commands/fetch.rs b/src/commands/fetch.rs index 0432f917e1..451a5085e0 100644 --- a/src/commands/fetch.rs +++ b/src/commands/fetch.rs @@ -1,10 +1,9 @@ use crate::commands::UnevaluatedCallInfo; -use crate::data::base::Value; -use crate::errors::ShellError; -use crate::parser::hir::SyntaxShape; -use crate::parser::registry::Signature; +use crate::data::value; use crate::prelude::*; use mime::Mime; +use nu_errors::ShellError; +use nu_protocol::{CallInfo, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; use nu_source::{AnchorLocation, Span}; use std::path::PathBuf; use std::str::FromStr; @@ -91,7 +90,7 @@ fn run( ctrl_c: raw_args.ctrl_c, shell_manager: raw_args.shell_manager, call_info: UnevaluatedCallInfo { - args: crate::parser::hir::Call { + args: nu_parser::hir::Call { head: raw_args.call_info.args.head, positional: None, named: None, @@ -147,7 +146,7 @@ pub async fn fetch( match (content_type.type_(), content_type.subtype()) { (mime::APPLICATION, mime::XML) => Ok(( Some("xml".to_string()), - UntaggedValue::string(r.body_string().await.map_err(|_| { + value::string(r.body_string().await.map_err(|_| { ShellError::labeled_error( "Could not load text from remote url", "could not load", @@ -161,7 +160,7 @@ pub async fn fetch( )), (mime::APPLICATION, mime::JSON) => Ok(( Some("json".to_string()), - UntaggedValue::string(r.body_string().await.map_err(|_| { + value::string(r.body_string().await.map_err(|_| { ShellError::labeled_error( "Could not load text from remote url", "could not load", @@ -183,7 +182,7 @@ pub async fn fetch( })?; Ok(( None, - UntaggedValue::binary(buf), + value::binary(buf), Tag { span, anchor: Some(AnchorLocation::Url(location.to_string())), @@ -192,7 +191,7 @@ pub async fn fetch( } (mime::IMAGE, mime::SVG) => Ok(( Some("svg".to_string()), - UntaggedValue::string(r.body_string().await.map_err(|_| { + value::string(r.body_string().await.map_err(|_| { ShellError::labeled_error( "Could not load svg from remote url", "could not load", @@ -214,7 +213,7 @@ pub async fn fetch( })?; Ok(( Some(image_ty.to_string()), - UntaggedValue::binary(buf), + value::binary(buf), Tag { span, anchor: Some(AnchorLocation::Url(location.to_string())), @@ -223,7 +222,7 @@ pub async fn fetch( } (mime::TEXT, mime::HTML) => Ok(( Some("html".to_string()), - UntaggedValue::string(r.body_string().await.map_err(|_| { + value::string(r.body_string().await.map_err(|_| { ShellError::labeled_error( "Could not load text from remote url", "could not load", @@ -249,7 +248,7 @@ pub async fn fetch( Ok(( path_extension, - UntaggedValue::string(r.body_string().await.map_err(|_| { + value::string(r.body_string().await.map_err(|_| { ShellError::labeled_error( "Could not load text from remote url", "could not load", @@ -264,10 +263,7 @@ pub async fn fetch( } (ty, sub_ty) => Ok(( None, - UntaggedValue::string(format!( - "Not yet supported MIME type: {} {}", - ty, sub_ty - )), + value::string(format!("Not yet supported MIME type: {} {}", ty, sub_ty)), Tag { span, anchor: Some(AnchorLocation::Url(location.to_string())), @@ -277,7 +273,7 @@ pub async fn fetch( } None => Ok(( None, - UntaggedValue::string(format!("No content type found")), + value::string(format!("No content type found")), Tag { span, anchor: Some(AnchorLocation::Url(location.to_string())), diff --git a/src/commands/first.rs b/src/commands/first.rs index 1113691bf1..eaf74b83fe 100644 --- a/src/commands/first.rs +++ b/src/commands/first.rs @@ -1,7 +1,8 @@ use crate::commands::WholeStreamCommand; -use crate::errors::ShellError; -use crate::parser::CommandRegistry; +use crate::context::CommandRegistry; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Signature, SyntaxShape}; use nu_source::Tagged; pub struct First; diff --git a/src/commands/from_bson.rs b/src/commands/from_bson.rs index e6a41907ad..e0de2dfeab 100644 --- a/src/commands/from_bson.rs +++ b/src/commands/from_bson.rs @@ -1,8 +1,10 @@ use crate::commands::WholeStreamCommand; +use crate::data::value; use crate::data::TaggedDictBuilder; -use crate::errors::ExpectedRange; use crate::prelude::*; use bson::{decode_document, spec::BinarySubtype, Bson}; +use nu_errors::{ExpectedRange, ShellError}; +use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value}; use nu_source::SpannedItem; use std::str::FromStr; @@ -72,8 +74,8 @@ fn convert_bson_value_to_nu_value(v: &Bson, tag: impl Into) -> Result UntaggedValue::number(n).into_value(&tag), - Bson::I64(n) => UntaggedValue::number(n).into_value(&tag), + Bson::I32(n) => value::number(n).into_value(&tag), + Bson::I64(n) => value::number(n).into_value(&tag), Bson::Decimal128(n) => { // TODO: this really isn't great, and we should update this to do a higher // fidelity translation @@ -108,10 +110,7 @@ fn convert_bson_value_to_nu_value(v: &Bson, tag: impl Into) -> Result { let mut collected = TaggedDictBuilder::new(tag.clone()); - collected.insert_value( - "$timestamp".to_string(), - UntaggedValue::number(ts).into_value(&tag), - ); + collected.insert_value("$timestamp".to_string(), value::number(ts).into_value(&tag)); collected.into_value() } Bson::Binary(bst, bytes) => { @@ -119,7 +118,7 @@ fn convert_bson_value_to_nu_value(v: &Bson, tag: impl Into) -> Result UntaggedValue::number(u), + BinarySubtype::UserDefined(u) => value::number(u), _ => { UntaggedValue::Primitive(Primitive::String(binary_subtype_to_string(*bst))) } diff --git a/src/commands/from_csv.rs b/src/commands/from_csv.rs index 663b2fd255..fb821d7363 100644 --- a/src/commands/from_csv.rs +++ b/src/commands/from_csv.rs @@ -1,7 +1,8 @@ use crate::commands::from_delimited_data::from_delimited_data; use crate::commands::WholeStreamCommand; -use crate::data::{Primitive, Value}; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Primitive, Signature, SyntaxShape, UntaggedValue, Value}; pub struct FromCSV; diff --git a/src/commands/from_delimited_data.rs b/src/commands/from_delimited_data.rs index 805f187eb3..99db232f80 100644 --- a/src/commands/from_delimited_data.rs +++ b/src/commands/from_delimited_data.rs @@ -1,6 +1,8 @@ -use crate::data::{Primitive, TaggedDictBuilder, Value}; +use crate::data::TaggedDictBuilder; use crate::prelude::*; use csv::ReaderBuilder; +use nu_errors::ShellError; +use nu_protocol::{Primitive, ReturnSuccess, UntaggedValue, Value}; fn from_delimited_string_to_value( s: String, diff --git a/src/commands/from_ini.rs b/src/commands/from_ini.rs index bd2282ea4c..63383ba18d 100644 --- a/src/commands/from_ini.rs +++ b/src/commands/from_ini.rs @@ -1,6 +1,8 @@ use crate::commands::WholeStreamCommand; -use crate::data::{Primitive, TaggedDictBuilder, Value}; +use crate::data::TaggedDictBuilder; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value}; use std::collections::HashMap; pub struct FromINI; diff --git a/src/commands/from_json.rs b/src/commands/from_json.rs index 0eff08daa6..9a9ea1ecbd 100644 --- a/src/commands/from_json.rs +++ b/src/commands/from_json.rs @@ -1,6 +1,8 @@ use crate::commands::WholeStreamCommand; -use crate::data::{Primitive, TaggedDictBuilder, Value}; +use crate::data::{value, TaggedDictBuilder}; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value}; pub struct FromJSON; @@ -36,10 +38,10 @@ fn convert_json_value_to_nu_value(v: &serde_hjson::Value, tag: impl Into) - match v { serde_hjson::Value::Null => UntaggedValue::Primitive(Primitive::Nothing).into_value(&tag), - serde_hjson::Value::Bool(b) => UntaggedValue::boolean(*b).into_value(&tag), - serde_hjson::Value::F64(n) => UntaggedValue::number(n).into_value(&tag), - serde_hjson::Value::U64(n) => UntaggedValue::number(n).into_value(&tag), - serde_hjson::Value::I64(n) => UntaggedValue::number(n).into_value(&tag), + serde_hjson::Value::Bool(b) => value::boolean(*b).into_value(&tag), + serde_hjson::Value::F64(n) => value::number(n).into_value(&tag), + serde_hjson::Value::U64(n) => value::number(n).into_value(&tag), + serde_hjson::Value::I64(n) => value::number(n).into_value(&tag), serde_hjson::Value::String(s) => { UntaggedValue::Primitive(Primitive::String(String::from(s))).into_value(&tag) } diff --git a/src/commands/from_sqlite.rs b/src/commands/from_sqlite.rs index 15bfbb6cab..5c65e4ccc4 100644 --- a/src/commands/from_sqlite.rs +++ b/src/commands/from_sqlite.rs @@ -1,7 +1,8 @@ use crate::commands::WholeStreamCommand; -use crate::data::{Primitive, TaggedDictBuilder, Value}; -use crate::errors::ShellError; +use crate::data::{value, TaggedDictBuilder}; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value}; use rusqlite::{types::ValueRef, Connection, Row, NO_PARAMS}; use std::io::Write; use std::path::Path; @@ -105,14 +106,14 @@ fn convert_sqlite_value_to_nu_value(value: ValueRef, tag: impl Into + Clone ValueRef::Null => { UntaggedValue::Primitive(Primitive::String(String::from(""))).into_value(tag) } - ValueRef::Integer(i) => UntaggedValue::number(i).into_value(tag), - ValueRef::Real(f) => UntaggedValue::number(f).into_value(tag), + ValueRef::Integer(i) => value::number(i).into_value(tag), + ValueRef::Real(f) => value::number(f).into_value(tag), t @ ValueRef::Text(_) => { // this unwrap is safe because we know the ValueRef is Text. UntaggedValue::Primitive(Primitive::String(t.as_str().unwrap().to_string())) .into_value(tag) } - ValueRef::Blob(u) => UntaggedValue::binary(u.to_owned()).into_value(tag), + ValueRef::Blob(u) => value::binary(u.to_owned()).into_value(tag), } } diff --git a/src/commands/from_ssv.rs b/src/commands/from_ssv.rs index a77ecf4f50..24caae107e 100644 --- a/src/commands/from_ssv.rs +++ b/src/commands/from_ssv.rs @@ -1,6 +1,8 @@ use crate::commands::WholeStreamCommand; -use crate::data::{Primitive, TaggedDictBuilder, Value}; +use crate::data::TaggedDictBuilder; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; use nu_source::Tagged; pub struct FromSSV; diff --git a/src/commands/from_toml.rs b/src/commands/from_toml.rs index 70ddde6b7d..eabaa2392c 100644 --- a/src/commands/from_toml.rs +++ b/src/commands/from_toml.rs @@ -1,6 +1,8 @@ use crate::commands::WholeStreamCommand; -use crate::data::{Primitive, TaggedDictBuilder, Value}; +use crate::data::{value, TaggedDictBuilder}; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value}; pub struct FromTOML; @@ -30,9 +32,9 @@ pub fn convert_toml_value_to_nu_value(v: &toml::Value, tag: impl Into) -> V let tag = tag.into(); match v { - toml::Value::Boolean(b) => UntaggedValue::boolean(*b).into_value(tag), - toml::Value::Integer(n) => UntaggedValue::number(n).into_value(tag), - toml::Value::Float(n) => UntaggedValue::number(n).into_value(tag), + toml::Value::Boolean(b) => value::boolean(*b).into_value(tag), + toml::Value::Integer(n) => value::number(n).into_value(tag), + toml::Value::Float(n) => value::number(n).into_value(tag), toml::Value::String(s) => { UntaggedValue::Primitive(Primitive::String(String::from(s))).into_value(tag) } diff --git a/src/commands/from_tsv.rs b/src/commands/from_tsv.rs index 38af5e4333..c4807dd912 100644 --- a/src/commands/from_tsv.rs +++ b/src/commands/from_tsv.rs @@ -1,6 +1,8 @@ use crate::commands::from_delimited_data::from_delimited_data; use crate::commands::WholeStreamCommand; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::Signature; pub struct FromTSV; diff --git a/src/commands/from_url.rs b/src/commands/from_url.rs index e3b6694ad3..cafcb6cd1f 100644 --- a/src/commands/from_url.rs +++ b/src/commands/from_url.rs @@ -1,6 +1,9 @@ use crate::commands::WholeStreamCommand; -use crate::data::{Primitive, TaggedDictBuilder, Value}; +use crate::data::value; +use crate::data::TaggedDictBuilder; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value}; pub struct FromURL; @@ -63,7 +66,7 @@ fn from_url(args: CommandArgs, registry: &CommandRegistry) -> Result UntaggedValue::nothing(), - DataType::String(s) => UntaggedValue::string(s), - DataType::Float(f) => UntaggedValue::decimal(*f), - DataType::Int(i) => UntaggedValue::int(*i), - DataType::Bool(b) => UntaggedValue::boolean(*b), - _ => UntaggedValue::nothing(), + DataType::Empty => value::nothing(), + DataType::String(s) => value::string(s), + DataType::Float(f) => value::decimal(*f), + DataType::Int(i) => value::int(*i), + DataType::Bool(b) => value::boolean(*b), + _ => value::nothing(), }; row_output.insert_untagged(&format!("Column{}", i), value); diff --git a/src/commands/from_xml.rs b/src/commands/from_xml.rs index 1b97646980..db2d173604 100644 --- a/src/commands/from_xml.rs +++ b/src/commands/from_xml.rs @@ -1,7 +1,8 @@ use crate::commands::WholeStreamCommand; -use crate::data::base::{Primitive, UntaggedValue, Value}; -use crate::data::TaggedDictBuilder; +use crate::data::{value, TaggedDictBuilder}; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value}; pub struct FromXML; @@ -60,13 +61,13 @@ fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>, tag: impl Into) collected.into_value() } else if n.is_comment() { - UntaggedValue::string("").into_value(tag) + value::string("").into_value(tag) } else if n.is_pi() { - UntaggedValue::string("").into_value(tag) + value::string("").into_value(tag) } else if n.is_text() { - UntaggedValue::string(n.text().unwrap()).into_value(tag) + value::string(n.text().unwrap()).into_value(tag) } else { - UntaggedValue::string("").into_value(tag) + value::string("").into_value(tag) } } @@ -139,20 +140,21 @@ fn from_xml(args: CommandArgs, registry: &CommandRegistry) -> Result) -> Value { - UntaggedValue::string(input.into()).into_untagged_value() + value::string(input.into()).into_untagged_value() } fn row(entries: IndexMap) -> Value { - UntaggedValue::row(entries).into_untagged_value() + value::row(entries).into_untagged_value() } fn table(list: &Vec) -> Value { - UntaggedValue::table(list).into_untagged_value() + value::table(list).into_untagged_value() } fn parse(xml: &str) -> Value { diff --git a/src/commands/from_yaml.rs b/src/commands/from_yaml.rs index 6377efd77f..3beea333c9 100644 --- a/src/commands/from_yaml.rs +++ b/src/commands/from_yaml.rs @@ -1,6 +1,8 @@ use crate::commands::WholeStreamCommand; -use crate::data::{Primitive, TaggedDictBuilder, Value}; +use crate::data::{value, TaggedDictBuilder}; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value}; pub struct FromYAML; @@ -54,14 +56,14 @@ fn convert_yaml_value_to_nu_value(v: &serde_yaml::Value, tag: impl Into) -> let tag = tag.into(); match v { - serde_yaml::Value::Bool(b) => UntaggedValue::boolean(*b).into_value(tag), + serde_yaml::Value::Bool(b) => value::boolean(*b).into_value(tag), serde_yaml::Value::Number(n) if n.is_i64() => { - UntaggedValue::number(n.as_i64().unwrap()).into_value(tag) + value::number(n.as_i64().unwrap()).into_value(tag) } serde_yaml::Value::Number(n) if n.is_f64() => { UntaggedValue::Primitive(Primitive::from(n.as_f64().unwrap())).into_value(tag) } - serde_yaml::Value::String(s) => UntaggedValue::string(s).into_value(tag), + serde_yaml::Value::String(s) => value::string(s).into_value(tag), serde_yaml::Value::Sequence(a) => UntaggedValue::Table( a.iter() .map(|x| convert_yaml_value_to_nu_value(x, &tag)) diff --git a/src/commands/get.rs b/src/commands/get.rs index fe39287620..8de42c339a 100644 --- a/src/commands/get.rs +++ b/src/commands/get.rs @@ -1,12 +1,14 @@ use crate::commands::WholeStreamCommand; +use crate::data::base::property_get::get_data_by_column_path; use crate::data::base::shape::Shapes; -use crate::data::Value; -use crate::errors::ShellError; use crate::prelude::*; use crate::utils::did_you_mean; -use crate::ColumnPath; use futures_util::pin_mut; use log::trace; +use nu_errors::ShellError; +use nu_protocol::{ + ColumnPath, ReturnSuccess, ReturnValue, Signature, SyntaxShape, UntaggedValue, Value, +}; use nu_source::{span_for_spanned_list, PrettyDebug}; pub struct Get; @@ -44,7 +46,8 @@ impl WholeStreamCommand for Get { pub fn get_column_path(path: &ColumnPath, obj: &Value) -> Result { let fields = path.clone(); - obj.get_data_by_column_path( + get_data_by_column_path( + obj, path, Box::new(move |(obj_source, column_path_tried, error)| { match &obj_source.value { diff --git a/src/commands/group_by.rs b/src/commands/group_by.rs index 066950db72..71e0d2e2e6 100644 --- a/src/commands/group_by.rs +++ b/src/commands/group_by.rs @@ -1,8 +1,9 @@ use crate::commands::WholeStreamCommand; -use crate::data::base::UntaggedValue; -use crate::data::TaggedDictBuilder; -use crate::errors::ShellError; +use crate::data::base::property_get::get_data_by_key; +use crate::data::{value, TaggedDictBuilder}; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, Value}; use nu_source::Tagged; pub struct GroupBy; @@ -69,10 +70,10 @@ pub fn group( ) -> Result { let tag = tag.into(); - let mut groups = indexmap::IndexMap::new(); + let mut groups: indexmap::IndexMap> = indexmap::IndexMap::new(); for value in values { - let group_key = value.get_data_by_key(column_name.borrow_spanned()); + let group_key = get_data_by_key(&value, column_name.borrow_spanned()); if group_key.is_none() { let possibilities = value.data_descriptors(); @@ -99,7 +100,7 @@ pub fn group( } } - let group_key = group_key.unwrap().as_string()?; + let group_key = group_key.unwrap().as_string()?.to_string(); let group = groups.entry(group_key).or_insert(vec![]); group.push(value); } @@ -107,7 +108,7 @@ pub fn group( let mut out = TaggedDictBuilder::new(&tag); for (k, v) in groups.iter() { - out.insert_untagged(k, UntaggedValue::table(v)); + out.insert_untagged(k, value::table(v)); } Ok(out.into_value()) @@ -116,20 +117,21 @@ pub fn group( #[cfg(test)] mod tests { use crate::commands::group_by::group; - use crate::data::base::{UntaggedValue, Value}; + use crate::data::value; use indexmap::IndexMap; + use nu_protocol::Value; use nu_source::*; fn string(input: impl Into) -> Value { - UntaggedValue::string(input.into()).into_untagged_value() + value::string(input.into()).into_untagged_value() } fn row(entries: IndexMap) -> Value { - UntaggedValue::row(entries).into_untagged_value() + value::row(entries).into_untagged_value() } fn table(list: &Vec) -> Value { - UntaggedValue::table(list).into_untagged_value() + value::table(list).into_untagged_value() } fn nu_releases_commiters() -> Vec { diff --git a/src/commands/help.rs b/src/commands/help.rs index 3958f558b4..cc44442d97 100644 --- a/src/commands/help.rs +++ b/src/commands/help.rs @@ -1,8 +1,12 @@ use crate::commands::PerItemCommand; +use crate::data::base::property_get::get_data_by_key; use crate::data::{command_dict, TaggedDictBuilder}; -use crate::errors::ShellError; -use crate::parser::registry::{self, NamedType, PositionalType}; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{ + CallInfo, NamedType, PositionalType, Primitive, ReturnSuccess, Signature, SyntaxShape, + UntaggedValue, Value, +}; use nu_source::SpannedItem; pub struct Help; @@ -12,7 +16,7 @@ impl PerItemCommand for Help { "help" } - fn signature(&self) -> registry::Signature { + fn signature(&self) -> Signature { Signature::build("help").rest(SyntaxShape::Any, "the name of command(s) to get help on") } @@ -45,8 +49,7 @@ impl PerItemCommand for Help { short_desc.insert_untagged("name", cmd); short_desc.insert_untagged( "description", - value - .get_data_by_key("usage".spanned_unknown()) + get_data_by_key(&value, "usage".spanned_unknown()) .unwrap() .as_string() .unwrap(), @@ -149,7 +152,7 @@ impl PerItemCommand for Help { } help.push_back(ReturnSuccess::value( - UntaggedValue::string(long_desc).into_value(tag.clone()), + value::string(long_desc).into_value(tag.clone()), )); } } @@ -167,9 +170,7 @@ You can also learn more at https://book.nushell.sh"#; let mut output_stream = VecDeque::new(); - output_stream.push_back(ReturnSuccess::value( - UntaggedValue::string(msg).into_value(tag), - )); + output_stream.push_back(ReturnSuccess::value(value::string(msg).into_value(tag))); Ok(output_stream.to_output_stream()) } diff --git a/src/commands/histogram.rs b/src/commands/histogram.rs index bed6e798d5..38c2fa0c44 100644 --- a/src/commands/histogram.rs +++ b/src/commands/histogram.rs @@ -5,9 +5,10 @@ use crate::commands::reduce_by::reduce; use crate::commands::t_sort_by::columns_sorted; use crate::commands::t_sort_by::t_sort; use crate::commands::WholeStreamCommand; -use crate::data::TaggedDictBuilder; -use crate::errors::ShellError; +use crate::data::{value, TaggedDictBuilder}; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; use nu_source::Tagged; use num_traits::cast::ToPrimitive; @@ -90,11 +91,11 @@ pub fn histogram( let mut fact = TaggedDictBuilder::new(&name); let value: Tagged = group_labels.get(idx).unwrap().clone(); - fact.insert_value(&column, UntaggedValue::string(value.item).into_value(value.tag)); + fact.insert_value(&column, value::string(value.item).into_value(value.tag)); if let Value { value: UntaggedValue::Primitive(Primitive::Int(ref num)), .. } = percentage.clone() { let string = std::iter::repeat("*").take(num.to_i32().unwrap() as usize).collect::(); - fact.insert_untagged(&frequency_column_name, UntaggedValue::string(string)); + fact.insert_untagged(&frequency_column_name, value::string(string)); } idx = idx + 1; @@ -145,9 +146,9 @@ fn percentages(values: &Value, max: Value, tag: impl Into) -> Result UntaggedValue::number(0).into_value(&tag), + _ => value::number(0).into_value(&tag), }) .collect::>(); UntaggedValue::Table(data).into_value(&tag) diff --git a/src/commands/history.rs b/src/commands/history.rs index 9c4fc7e80c..11b7896582 100644 --- a/src/commands/history.rs +++ b/src/commands/history.rs @@ -1,8 +1,9 @@ use crate::cli::History as HistoryFile; use crate::commands::PerItemCommand; -use crate::errors::ShellError; -use crate::parser::registry::{self}; +use crate::data::value; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{CallInfo, ReturnSuccess, Signature, Value}; use std::fs::File; use std::io::{BufRead, BufReader}; @@ -13,7 +14,7 @@ impl PerItemCommand for History { "history" } - fn signature(&self) -> registry::Signature { + fn signature(&self) -> Signature { Signature::build("history") } @@ -37,7 +38,7 @@ impl PerItemCommand for History { let reader = BufReader::new(file); for line in reader.lines() { if let Ok(line) = line { - yield ReturnSuccess::value(UntaggedValue::string(line).into_value(tag.clone())); + yield ReturnSuccess::value(value::string(line).into_value(tag.clone())); } } } else { diff --git a/src/commands/last.rs b/src/commands/last.rs index 35d84de861..dc74116069 100644 --- a/src/commands/last.rs +++ b/src/commands/last.rs @@ -1,7 +1,8 @@ use crate::commands::WholeStreamCommand; -use crate::errors::ShellError; -use crate::parser::CommandRegistry; +use crate::context::CommandRegistry; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, Value}; use nu_source::Tagged; pub struct Last; diff --git a/src/commands/lines.rs b/src/commands/lines.rs index 0338d91e94..32f0523044 100644 --- a/src/commands/lines.rs +++ b/src/commands/lines.rs @@ -1,8 +1,8 @@ use crate::commands::WholeStreamCommand; -use crate::data::Primitive; -use crate::errors::ShellError; use crate::prelude::*; use log::trace; +use nu_errors::ShellError; +use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue}; pub struct Lines; diff --git a/src/commands/ls.rs b/src/commands/ls.rs index ddb58ebaf4..0bd7a465b7 100644 --- a/src/commands/ls.rs +++ b/src/commands/ls.rs @@ -1,6 +1,7 @@ use crate::commands::WholeStreamCommand; -use crate::errors::ShellError; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Signature, SyntaxShape}; use nu_source::Tagged; use std::path::PathBuf; diff --git a/src/commands/macros.rs b/src/commands/macros.rs index 4a83f5e069..eb2368c050 100644 --- a/src/commands/macros.rs +++ b/src/commands/macros.rs @@ -45,8 +45,8 @@ macro_rules! command { stringify!($config_name) } - fn config(&self) -> $crate::parser::registry::Signature { - $crate::parser::registry::Signature { + fn config(&self) -> $nu_parser::registry::Signature { + $nu_parser::registry::Signature { name: self.name().to_string(), positional: vec![$($mandatory_positional)*], rest_positional: false, @@ -54,13 +54,13 @@ macro_rules! command { is_sink: false, named: { - use $crate::parser::registry::NamedType; + use $nu_parser::registry::NamedType; #[allow(unused_mut)] let mut named: indexmap::IndexMap = indexmap::IndexMap::new(); $( - named.insert(stringify!($named_param).to_string(), $crate::parser::registry::NamedType::$named_kind); + named.insert(stringify!($named_param).to_string(), $nu_parser::registry::NamedType::$named_kind); )* named @@ -250,7 +250,7 @@ macro_rules! command { Rest { $($rest)* } Signature { name: $config_name, - mandatory_positional: vec![ $($mandatory_positional)* $crate::parser::registry::PositionalType::mandatory_block( + mandatory_positional: vec![ $($mandatory_positional)* $nu_parser::registry::PositionalType::mandatory_block( stringify!($param_name) ), ], optional_positional: vec![ $($optional_positional)* ], @@ -305,7 +305,7 @@ macro_rules! command { Rest { $($rest)* } Signature { name: $config_name, - mandatory_positional: vec![ $($mandatory_positional)* $crate::parser::registry::PositionalType::mandatory( + mandatory_positional: vec![ $($mandatory_positional)* $nu_parser::registry::PositionalType::mandatory( stringify!($param_name), <$param_kind>::syntax_type() ), ], optional_positional: vec![ $($optional_positional)* ], diff --git a/src/commands/map_max_by.rs b/src/commands/map_max_by.rs index 7b34f05432..416d5f56e4 100644 --- a/src/commands/map_max_by.rs +++ b/src/commands/map_max_by.rs @@ -1,6 +1,8 @@ use crate::commands::WholeStreamCommand; -use crate::parser::hir::SyntaxShape; +use crate::data::value; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; use nu_source::Tagged; use num_traits::cast::ToPrimitive; @@ -101,9 +103,9 @@ pub fn map_max( } _ => acc, }); - UntaggedValue::number(data).into_value(&tag) + value::number(data).into_value(&tag) } - _ => UntaggedValue::number(0).into_value(&tag), + _ => value::number(0).into_value(&tag), }) .collect(); @@ -120,9 +122,9 @@ pub fn map_max( } _ => max, }); - UntaggedValue::number(datasets).into_value(&tag) + value::number(datasets).into_value(&tag) } - _ => UntaggedValue::number(-1).into_value(&tag), + _ => value::number(-1).into_value(&tag), }; Ok(results) @@ -137,20 +139,20 @@ mod tests { use crate::commands::reduce_by::reduce; use crate::commands::t_sort_by::t_sort; use crate::prelude::*; - use crate::Value; use indexmap::IndexMap; + use nu_protocol::{UntaggedValue, Value}; use nu_source::*; fn int(s: impl Into) -> Value { - UntaggedValue::int(s).into_untagged_value() + value::int(s).into_untagged_value() } fn string(input: impl Into) -> Value { - UntaggedValue::string(input.into()).into_untagged_value() + value::string(input.into()).into_untagged_value() } fn row(entries: IndexMap) -> Value { - UntaggedValue::row(entries).into_untagged_value() + value::row(entries).into_untagged_value() } fn nu_releases_evaluated_by_default_one() -> Value { diff --git a/src/commands/mkdir.rs b/src/commands/mkdir.rs index 561f5c4c96..befce8ad24 100644 --- a/src/commands/mkdir.rs +++ b/src/commands/mkdir.rs @@ -1,7 +1,8 @@ use crate::commands::command::RunnablePerItemContext; -use crate::errors::ShellError; -use crate::parser::registry::{CommandRegistry, Signature}; +use crate::context::CommandRegistry; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{CallInfo, Signature, SyntaxShape, Value}; use nu_source::Tagged; use std::path::PathBuf; diff --git a/src/commands/mv.rs b/src/commands/mv.rs index 6e90d1087f..91f395e6f2 100644 --- a/src/commands/mv.rs +++ b/src/commands/mv.rs @@ -1,8 +1,8 @@ use crate::commands::command::RunnablePerItemContext; -use crate::errors::ShellError; -use crate::parser::hir::SyntaxShape; -use crate::parser::registry::{CommandRegistry, Signature}; +use crate::context::CommandRegistry; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{CallInfo, Signature, SyntaxShape, Value}; use nu_source::Tagged; use std::path::PathBuf; diff --git a/src/commands/next.rs b/src/commands/next.rs index 359f262312..2813da31dc 100644 --- a/src/commands/next.rs +++ b/src/commands/next.rs @@ -1,7 +1,7 @@ -use crate::commands::command::CommandAction; use crate::commands::WholeStreamCommand; -use crate::errors::ShellError; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{CommandAction, ReturnSuccess, Signature}; pub struct Next; diff --git a/src/commands/nth.rs b/src/commands/nth.rs index b57b7a413f..94e0e0005c 100644 --- a/src/commands/nth.rs +++ b/src/commands/nth.rs @@ -1,7 +1,8 @@ use crate::commands::WholeStreamCommand; -use crate::errors::ShellError; -use crate::parser::CommandRegistry; +use crate::context::CommandRegistry; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{ReturnSuccess, Signature, SyntaxShape}; use nu_source::Tagged; #[derive(Deserialize)] diff --git a/src/commands/open.rs b/src/commands/open.rs index 47fc2ecc8b..63b02355cb 100644 --- a/src/commands/open.rs +++ b/src/commands/open.rs @@ -1,12 +1,11 @@ use crate::commands::UnevaluatedCallInfo; -use crate::data::Value; -use crate::errors::ShellError; -use crate::parser::hir::SyntaxShape; -use crate::parser::registry::Signature; +use crate::data::value; use crate::prelude::*; -use nu_source::AnchorLocation; -use nu_source::Span; +use nu_errors::ShellError; +use nu_protocol::{CallInfo, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; +use nu_source::{AnchorLocation, Span}; use std::path::{Path, PathBuf}; + pub struct Open; impl PerItemCommand for Open { @@ -91,7 +90,7 @@ fn run( ctrl_c: raw_args.ctrl_c, shell_manager: raw_args.shell_manager, call_info: UnevaluatedCallInfo { - args: crate::parser::hir::Call { + args: nu_parser::hir::Call { head: raw_args.call_info.args.head, positional: None, named: None, @@ -141,7 +140,7 @@ pub async fn fetch( Ok(s) => Ok(( cwd.extension() .map(|name| name.to_string_lossy().to_string()), - UntaggedValue::string(s), + value::string(s), Tag { span, anchor: Some(AnchorLocation::File(cwd.to_string_lossy().to_string())), @@ -159,7 +158,7 @@ pub async fn fetch( Ok(s) => Ok(( cwd.extension() .map(|name| name.to_string_lossy().to_string()), - UntaggedValue::string(s), + value::string(s), Tag { span, anchor: Some(AnchorLocation::File( @@ -169,7 +168,7 @@ pub async fn fetch( )), Err(_) => Ok(( None, - UntaggedValue::binary(bytes), + value::binary(bytes), Tag { span, anchor: Some(AnchorLocation::File( @@ -181,7 +180,7 @@ pub async fn fetch( } else { Ok(( None, - UntaggedValue::binary(bytes), + value::binary(bytes), Tag { span, anchor: Some(AnchorLocation::File( @@ -200,7 +199,7 @@ pub async fn fetch( Ok(s) => Ok(( cwd.extension() .map(|name| name.to_string_lossy().to_string()), - UntaggedValue::string(s), + value::string(s), Tag { span, anchor: Some(AnchorLocation::File( @@ -210,7 +209,7 @@ pub async fn fetch( )), Err(_) => Ok(( None, - UntaggedValue::binary(bytes), + value::binary(bytes), Tag { span, anchor: Some(AnchorLocation::File( @@ -222,7 +221,7 @@ pub async fn fetch( } else { Ok(( None, - UntaggedValue::binary(bytes), + value::binary(bytes), Tag { span, anchor: Some(AnchorLocation::File( @@ -234,7 +233,7 @@ pub async fn fetch( } _ => Ok(( None, - UntaggedValue::binary(bytes), + value::binary(bytes), Tag { span, anchor: Some(AnchorLocation::File( diff --git a/src/commands/pick.rs b/src/commands/pick.rs index a6cdbf040a..a33fbda3b6 100644 --- a/src/commands/pick.rs +++ b/src/commands/pick.rs @@ -1,8 +1,9 @@ use crate::commands::WholeStreamCommand; use crate::context::CommandRegistry; use crate::data::base::select_fields; -use crate::errors::ShellError; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Signature, SyntaxShape}; use nu_source::Tagged; #[derive(Deserialize)] diff --git a/src/commands/pivot.rs b/src/commands/pivot.rs index 86d25c4d4b..586fb71d0e 100644 --- a/src/commands/pivot.rs +++ b/src/commands/pivot.rs @@ -1,7 +1,10 @@ use crate::commands::WholeStreamCommand; -use crate::errors::ShellError; +use crate::data::base::property_get::get_data_by_key; +use crate::data::value; use crate::prelude::*; use crate::TaggedDictBuilder; +use nu_errors::ShellError; +use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, Value}; use nu_source::{SpannedItem, Tagged}; pub struct Pivot; @@ -61,7 +64,7 @@ pub fn pivot(args: PivotArgs, context: RunnableContext) -> Result = vec![]; if args.rest.len() > 0 && args.header_row { yield Err(ShellError::labeled_error("Can not provide header names and use header row", "using header row", context.name)); @@ -71,10 +74,10 @@ pub fn pivot(args: PivotArgs, context: RunnableContext) -> Result { if let Ok(s) = x.as_string() { - headers.push(s); + headers.push(s.to_string()); } else { yield Err(ShellError::labeled_error("Header row needs string headers", "used non-string headers", context.name)); return; @@ -111,17 +114,17 @@ pub fn pivot(args: PivotArgs, context: RunnableContext) -> Result { dict.insert_value(headers[column_num].clone(), x.clone()); } _ => { - dict.insert_untagged(headers[column_num].clone(), UntaggedValue::nothing()); + dict.insert_untagged(headers[column_num].clone(), value::nothing()); } } column_num += 1; diff --git a/src/commands/plugin.rs b/src/commands/plugin.rs index c7dc318717..6c37b321a2 100644 --- a/src/commands/plugin.rs +++ b/src/commands/plugin.rs @@ -1,9 +1,10 @@ use crate::commands::WholeStreamCommand; -use crate::errors::ShellError; -use crate::parser::registry; +use crate::data::value; use crate::prelude::*; use derive_new::new; use log::trace; +use nu_errors::ShellError; +use nu_protocol::{Primitive, ReturnSuccess, ReturnValue, Signature, UntaggedValue, Value}; use serde::{self, Deserialize, Serialize}; use std::io::prelude::*; use std::io::BufReader; @@ -39,7 +40,7 @@ pub enum NuResult { pub struct PluginCommand { name: String, path: String, - config: registry::Signature, + config: Signature, } impl WholeStreamCommand for PluginCommand { @@ -47,7 +48,7 @@ impl WholeStreamCommand for PluginCommand { &self.name } - fn signature(&self) -> registry::Signature { + fn signature(&self) -> Signature { self.config.clone() } @@ -264,7 +265,7 @@ pub fn filter_plugin( pub struct PluginSink { name: String, path: String, - config: registry::Signature, + config: Signature, } impl WholeStreamCommand for PluginSink { @@ -272,7 +273,7 @@ impl WholeStreamCommand for PluginSink { &self.name } - fn signature(&self) -> registry::Signature { + fn signature(&self) -> Signature { self.config.clone() } @@ -315,7 +316,7 @@ pub fn sink_plugin( // Needed for async_stream to type check if false { - yield ReturnSuccess::value(UntaggedValue::nothing().into_untagged_value()); + yield ReturnSuccess::value(value::nothing().into_untagged_value()); } }; Ok(OutputStream::new(stream)) diff --git a/src/commands/post.rs b/src/commands/post.rs index 1d4d1e7856..63c445b6ee 100644 --- a/src/commands/post.rs +++ b/src/commands/post.rs @@ -1,11 +1,12 @@ use crate::commands::UnevaluatedCallInfo; -use crate::data::base::{UntaggedValue, Value}; -use crate::errors::ShellError; -use crate::parser::hir::SyntaxShape; -use crate::parser::registry::Signature; +use crate::data::value; use crate::prelude::*; use base64::encode; use mime::Mime; +use nu_errors::ShellError; +use nu_protocol::{ + CallInfo, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value, +}; use nu_source::AnchorLocation; use std::path::PathBuf; use std::str::FromStr; @@ -81,13 +82,16 @@ fn run( })? { file => file.clone(), }; - let path_str = path.as_string()?; + let path_str = path.as_string()?.to_string(); 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().to_string()); let password = call_info .args .get("password") - .map(|x| x.as_string().unwrap()); + .map(|x| x.as_string().unwrap().to_string()); let registry = registry.clone(); let raw_args = raw_args.clone(); @@ -115,7 +119,7 @@ fn run( ctrl_c: raw_args.ctrl_c, shell_manager: raw_args.shell_manager, call_info: UnevaluatedCallInfo { - args: crate::parser::hir::Call { + args: nu_parser::hir::Call { head: raw_args.call_info.args.head, positional: None, named: None, @@ -259,7 +263,7 @@ pub async fn post( ctrl_c: raw_args.ctrl_c, shell_manager: raw_args.shell_manager, call_info: UnevaluatedCallInfo { - args: crate::parser::hir::Call { + args: nu_parser::hir::Call { head: raw_args.call_info.args.head, positional: None, named: None, @@ -316,7 +320,7 @@ pub async fn post( match (content_type.type_(), content_type.subtype()) { (mime::APPLICATION, mime::XML) => Ok(( Some("xml".to_string()), - UntaggedValue::string(r.body_string().await.map_err(|_| { + value::string(r.body_string().await.map_err(|_| { ShellError::labeled_error( "Could not load text from remote url", "could not load", @@ -330,7 +334,7 @@ pub async fn post( )), (mime::APPLICATION, mime::JSON) => Ok(( Some("json".to_string()), - UntaggedValue::string(r.body_string().await.map_err(|_| { + value::string(r.body_string().await.map_err(|_| { ShellError::labeled_error( "Could not load text from remote url", "could not load", @@ -352,7 +356,7 @@ pub async fn post( })?; Ok(( None, - UntaggedValue::binary(buf), + value::binary(buf), Tag { anchor: Some(AnchorLocation::Url(location.to_string())), span: tag.span, @@ -369,7 +373,7 @@ pub async fn post( })?; Ok(( Some(image_ty.to_string()), - UntaggedValue::binary(buf), + value::binary(buf), Tag { anchor: Some(AnchorLocation::Url(location.to_string())), span: tag.span, @@ -378,7 +382,7 @@ pub async fn post( } (mime::TEXT, mime::HTML) => Ok(( Some("html".to_string()), - UntaggedValue::string(r.body_string().await.map_err(|_| { + value::string(r.body_string().await.map_err(|_| { ShellError::labeled_error( "Could not load text from remote url", "could not load", @@ -404,7 +408,7 @@ pub async fn post( Ok(( path_extension, - UntaggedValue::string(r.body_string().await.map_err(|_| { + value::string(r.body_string().await.map_err(|_| { ShellError::labeled_error( "Could not load text from remote url", "could not load", @@ -419,7 +423,7 @@ pub async fn post( } (ty, sub_ty) => Ok(( None, - UntaggedValue::string(format!( + value::string(format!( "Not yet supported MIME type: {} {}", ty, sub_ty )), @@ -432,7 +436,7 @@ pub async fn post( } None => Ok(( None, - UntaggedValue::string(format!("No content type found")), + value::string(format!("No content type found")), Tag { anchor: Some(AnchorLocation::Url(location.to_string())), span: tag.span, diff --git a/src/commands/prepend.rs b/src/commands/prepend.rs index de2cc499f1..6adb7c7ec5 100644 --- a/src/commands/prepend.rs +++ b/src/commands/prepend.rs @@ -1,7 +1,8 @@ use crate::commands::WholeStreamCommand; -use crate::errors::ShellError; -use crate::parser::CommandRegistry; +use crate::context::CommandRegistry; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Signature, SyntaxShape, Value}; #[derive(Deserialize)] struct PrependArgs { diff --git a/src/commands/prev.rs b/src/commands/prev.rs index 970cce3436..e2646716df 100644 --- a/src/commands/prev.rs +++ b/src/commands/prev.rs @@ -1,6 +1,6 @@ -use crate::commands::command::CommandAction; -use crate::errors::ShellError; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{CommandAction, ReturnSuccess, Signature}; use crate::commands::WholeStreamCommand; diff --git a/src/commands/pwd.rs b/src/commands/pwd.rs index 37e2668bdb..4ff64424d4 100644 --- a/src/commands/pwd.rs +++ b/src/commands/pwd.rs @@ -1,7 +1,7 @@ use crate::commands::WholeStreamCommand; -use crate::errors::ShellError; -use crate::parser::registry::Signature; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::Signature; pub struct PWD; diff --git a/src/commands/reduce_by.rs b/src/commands/reduce_by.rs index 24ad5950e9..3992276e12 100644 --- a/src/commands/reduce_by.rs +++ b/src/commands/reduce_by.rs @@ -1,6 +1,7 @@ use crate::commands::WholeStreamCommand; -use crate::parser::hir::SyntaxShape; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; use nu_source::Tagged; use num_traits::cast::ToPrimitive; @@ -134,9 +135,9 @@ pub fn reduce( } = d { acc = reduce_with(acc, x.clone()); - UntaggedValue::number(acc).into_value(&tag) + value::number(acc).into_value(&tag) } else { - UntaggedValue::number(0).into_value(&tag) + value::number(0).into_value(&tag) } }) .collect::>(); @@ -163,24 +164,24 @@ mod tests { use crate::commands::reduce_by::{reduce, reducer_for, Reduce}; use crate::commands::t_sort_by::t_sort; use crate::prelude::*; - use crate::Value; use indexmap::IndexMap; + use nu_protocol::{UntaggedValue, Value}; use nu_source::*; fn int(s: impl Into) -> Value { - UntaggedValue::int(s).into_untagged_value() + value::int(s).into_untagged_value() } fn string(input: impl Into) -> Value { - UntaggedValue::string(input.into()).into_untagged_value() + value::string(input.into()).into_untagged_value() } fn row(entries: IndexMap) -> Value { - UntaggedValue::row(entries).into_untagged_value() + value::row(entries).into_untagged_value() } fn table(list: &Vec) -> Value { - UntaggedValue::table(list).into_untagged_value() + value::table(list).into_untagged_value() } fn nu_releases_sorted_by_date() -> Value { diff --git a/src/commands/reject.rs b/src/commands/reject.rs index 8df4cfcd37..519a0d371d 100644 --- a/src/commands/reject.rs +++ b/src/commands/reject.rs @@ -1,7 +1,8 @@ use crate::commands::WholeStreamCommand; use crate::data::base::reject_fields; -use crate::errors::ShellError; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Signature, SyntaxShape}; use nu_source::Tagged; #[derive(Deserialize)] diff --git a/src/commands/reverse.rs b/src/commands/reverse.rs index 8b81297249..fd70090d02 100644 --- a/src/commands/reverse.rs +++ b/src/commands/reverse.rs @@ -1,7 +1,8 @@ use crate::commands::WholeStreamCommand; -use crate::errors::ShellError; -use crate::parser::CommandRegistry; +use crate::context::CommandRegistry; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::Signature; pub struct Reverse; diff --git a/src/commands/rm.rs b/src/commands/rm.rs index c1f4104137..9b8f67ffe3 100644 --- a/src/commands/rm.rs +++ b/src/commands/rm.rs @@ -1,8 +1,8 @@ use crate::commands::command::RunnablePerItemContext; -use crate::errors::ShellError; -use crate::parser::hir::SyntaxShape; -use crate::parser::registry::{CommandRegistry, Signature}; +use crate::context::CommandRegistry; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{CallInfo, Signature, SyntaxShape, Value}; use nu_source::Tagged; use std::path::PathBuf; diff --git a/src/commands/save.rs b/src/commands/save.rs index 9c065dadd8..3bb87029cd 100644 --- a/src/commands/save.rs +++ b/src/commands/save.rs @@ -1,7 +1,7 @@ use crate::commands::{UnevaluatedCallInfo, WholeStreamCommand}; -use crate::data::Value; -use crate::errors::ShellError; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; use nu_source::Tagged; use std::path::{Path, PathBuf}; @@ -185,7 +185,7 @@ fn save( ctrl_c, shell_manager, call_info: UnevaluatedCallInfo { - args: crate::parser::hir::Call { + args: nu_parser::hir::Call { head: raw_args.call_info.args.head, positional: None, named: None, diff --git a/src/commands/shells.rs b/src/commands/shells.rs index aac5f8e7d7..7112237f0e 100644 --- a/src/commands/shells.rs +++ b/src/commands/shells.rs @@ -1,7 +1,8 @@ use crate::commands::WholeStreamCommand; use crate::data::TaggedDictBuilder; -use crate::errors::ShellError; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::Signature; use std::sync::atomic::Ordering; pub struct Shells; diff --git a/src/commands/size.rs b/src/commands/size.rs index 80dcdbd082..5a637ea94c 100644 --- a/src/commands/size.rs +++ b/src/commands/size.rs @@ -1,7 +1,8 @@ use crate::commands::WholeStreamCommand; -use crate::data::{TaggedDictBuilder, Value}; -use crate::errors::ShellError; +use crate::data::{value, TaggedDictBuilder}; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value}; pub struct Size; @@ -76,11 +77,11 @@ fn count(contents: &str, tag: impl Into) -> Value { let mut dict = TaggedDictBuilder::new(tag); //TODO: add back in name when we have it in the tag - //dict.insert("name", UntaggedValue::string(name)); - dict.insert_untagged("lines", UntaggedValue::int(lines)); - dict.insert_untagged("words", UntaggedValue::int(words)); - dict.insert_untagged("chars", UntaggedValue::int(chars)); - dict.insert_untagged("max length", UntaggedValue::int(bytes)); + //dict.insert("name", value::string(name)); + dict.insert_untagged("lines", value::int(lines)); + dict.insert_untagged("words", value::int(words)); + dict.insert_untagged("chars", value::int(chars)); + dict.insert_untagged("max length", value::int(bytes)); dict.into_value() } diff --git a/src/commands/skip_while.rs b/src/commands/skip_while.rs index 9e1cfe14c5..2407ffe5a6 100644 --- a/src/commands/skip_while.rs +++ b/src/commands/skip_while.rs @@ -1,14 +1,14 @@ use crate::commands::WholeStreamCommand; -use crate::data::base::Block; -use crate::errors::ShellError; use crate::prelude::*; use log::trace; +use nu_errors::ShellError; +use nu_protocol::{Evaluate, Scope, Signature, SyntaxShape}; pub struct SkipWhile; #[derive(Deserialize)] pub struct SkipWhileArgs { - condition: Block, + condition: Evaluate, } impl WholeStreamCommand for SkipWhile { @@ -45,7 +45,7 @@ pub fn skip_while( ) -> Result { let objects = input.values.skip_while(move |item| { trace!("ITEM = {:?}", item); - let result = condition.invoke(&item); + let result = condition.invoke(&Scope::new(item.clone())); trace!("RESULT = {:?}", result); let return_value = match result { diff --git a/src/commands/sort_by.rs b/src/commands/sort_by.rs index 8d6378a8c4..ed4180ef30 100644 --- a/src/commands/sort_by.rs +++ b/src/commands/sort_by.rs @@ -1,6 +1,8 @@ use crate::commands::WholeStreamCommand; -use crate::errors::ShellError; +use crate::data::base::property_get::get_data_by_key; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Signature, SyntaxShape, Value}; use nu_source::Tagged; pub struct SortBy; @@ -39,10 +41,10 @@ fn sort_by( Ok(OutputStream::new(async_stream! { let mut vec = context.input.drain_vec().await; - let calc_key = |item: &crate::data::base::Value| { + let calc_key = |item: &Value| { rest.iter() - .map(|f| item.get_data_by_key(f.borrow_spanned()).map(|i| i.clone())) - .collect::>>() + .map(|f| get_data_by_key(item, f.borrow_spanned()).map(|i| i.clone())) + .collect::>>() }; vec.sort_by_cached_key(calc_key); diff --git a/src/commands/split_by.rs b/src/commands/split_by.rs index 7821d3cfcb..876550db5e 100644 --- a/src/commands/split_by.rs +++ b/src/commands/split_by.rs @@ -1,8 +1,8 @@ use crate::commands::WholeStreamCommand; -use crate::data::base::UntaggedValue; use crate::data::TaggedDictBuilder; -use crate::errors::ShellError; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{ReturnSuccess, Signature, SpannedTypeName, SyntaxShape, UntaggedValue, Value}; use nu_source::Tagged; pub struct SplitBy; @@ -104,7 +104,7 @@ pub fn split( .or_insert(indexmap::IndexMap::new()); s.insert( group_key.clone(), - UntaggedValue::table(&subset).into_value(tag), + value::table(&subset).into_value(tag), ); } other => { @@ -144,7 +144,7 @@ pub fn split( let mut out = TaggedDictBuilder::new(&origin_tag); for (k, v) in splits.into_iter() { - out.insert_untagged(k, UntaggedValue::row(v)); + out.insert_untagged(k, value::row(v)); } Ok(out.into_value()) @@ -154,20 +154,21 @@ mod tests { use crate::commands::group_by::group; use crate::commands::split_by::split; - use crate::data::base::{UntaggedValue, Value}; + use crate::data::value; use indexmap::IndexMap; + use nu_protocol::Value; use nu_source::*; fn string(input: impl Into) -> Value { - UntaggedValue::string(input.into()).into_untagged_value() + value::string(input.into()).into_untagged_value() } fn row(entries: IndexMap) -> Value { - UntaggedValue::row(entries).into_untagged_value() + value::row(entries).into_untagged_value() } fn table(list: &Vec) -> Value { - UntaggedValue::table(list).into_untagged_value() + value::table(list).into_untagged_value() } fn nu_releases_grouped_by_date() -> Value { @@ -213,7 +214,7 @@ mod tests { assert_eq!( split(&for_key, &nu_releases_grouped_by_date(), Tag::unknown()).unwrap(), - UntaggedValue::row(indexmap! { + value::row(indexmap! { "EC".into() => row(indexmap! { "August 23-2019".into() => table(&vec![ row(indexmap!{"name".into() => string("AR"), "country".into() => string("EC"), "date".into() => string("August 23-2019")}) @@ -260,7 +261,7 @@ mod tests { row(indexmap!{"name".into() => string("AR"), "country".into() => string("EC"), "date".into() => string("August 23-2019")}) ]), "Sept 24-2019".into() => table(&vec![ - row(indexmap!{"name".into() => UntaggedValue::string("JT").into_value(Tag::from(Span::new(5,10))), "date".into() => string("Sept 24-2019")}) + row(indexmap!{"name".into() => value::string("JT").into_value(Tag::from(Span::new(5,10))), "date".into() => string("Sept 24-2019")}) ]), "October 10-2019".into() => table(&vec![ row(indexmap!{"name".into() => string("YK"), "country".into() => string("US"), "date".into() => string("October 10-2019")}) diff --git a/src/commands/split_column.rs b/src/commands/split_column.rs index 874c6ebb66..8ed5a61d83 100644 --- a/src/commands/split_column.rs +++ b/src/commands/split_column.rs @@ -1,8 +1,9 @@ use crate::commands::WholeStreamCommand; -use crate::data::{Primitive, TaggedDictBuilder}; -use crate::errors::ShellError; +use crate::data::TaggedDictBuilder; use crate::prelude::*; use log::trace; +use nu_errors::ShellError; +use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue}; use nu_source::Tagged; #[derive(Deserialize)] diff --git a/src/commands/split_row.rs b/src/commands/split_row.rs index 209e25c578..e0a803b713 100644 --- a/src/commands/split_row.rs +++ b/src/commands/split_row.rs @@ -1,8 +1,8 @@ use crate::commands::WholeStreamCommand; -use crate::data::Primitive; -use crate::errors::ShellError; use crate::prelude::*; use log::trace; +use nu_errors::ShellError; +use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue}; use nu_source::Tagged; #[derive(Deserialize)] diff --git a/src/commands/t_sort_by.rs b/src/commands/t_sort_by.rs index e0e639108a..70bd635475 100644 --- a/src/commands/t_sort_by.rs +++ b/src/commands/t_sort_by.rs @@ -1,8 +1,10 @@ use crate::commands::WholeStreamCommand; -use crate::data::{TaggedDictBuilder, TaggedListBuilder}; -use crate::errors::ShellError; +use crate::data::base::property_get::get_data_by_key; +use crate::data::{value, TaggedDictBuilder, TaggedListBuilder}; use crate::prelude::*; use chrono::{DateTime, NaiveDate, Utc}; +use nu_errors::ShellError; +use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; use nu_source::Tagged; pub struct TSortBy; @@ -68,7 +70,7 @@ fn t_sort_by( if show_columns { for label in columns_sorted(column_grouped_by_name, &values[0], &name).into_iter() { - yield ReturnSuccess::value(UntaggedValue::string(label.item).into_value(label.tag)); + yield ReturnSuccess::value(value::string(label.item).into_value(label.tag)); } } else { match t_sort(column_grouped_by_name, None, &values[0], name) { @@ -102,7 +104,7 @@ pub fn columns_sorted( Ok(parsed) => UntaggedValue::Primitive(Primitive::Date( DateTime::::from_utc(parsed.and_hms(12, 34, 56), Utc), )), - Err(_) => UntaggedValue::string(k), + Err(_) => value::string(k), }; date.into_untagged_value() @@ -118,7 +120,7 @@ pub fn columns_sorted( value: UntaggedValue::Primitive(Primitive::Date(d)), .. } => format!("{}", d.format("%B %d-%Y")), - _ => k.as_string().unwrap(), + _ => k.as_string().unwrap().to_string(), }) .collect(); @@ -168,7 +170,7 @@ pub fn t_sort( let results: Vec> = split_labels .iter() .map(|split| { - let groups = dataset.get_data_by_key(split.borrow_spanned()); + let groups = get_data_by_key(&dataset, split.borrow_spanned()); sorted_labels .clone() @@ -195,10 +197,10 @@ pub fn t_sort( return Ok(UntaggedValue::Table(outer.list).into_value(&origin_tag)); } - Some(_) => return Ok(UntaggedValue::nothing().into_value(&origin_tag)), + Some(_) => return Ok(value::nothing().into_value(&origin_tag)), } } - None => return Ok(UntaggedValue::nothing().into_value(&origin_tag)), + None => return Ok(value::nothing().into_value(&origin_tag)), } } #[cfg(test)] @@ -206,20 +208,21 @@ mod tests { use crate::commands::group_by::group; use crate::commands::t_sort_by::{columns_sorted, t_sort}; - use crate::data::base::{UntaggedValue, Value}; + use crate::data::value; use indexmap::IndexMap; + use nu_protocol::{UntaggedValue, Value}; use nu_source::*; fn string(input: impl Into) -> Value { - UntaggedValue::string(input.into()).into_untagged_value() + value::string(input.into()).into_untagged_value() } fn row(entries: IndexMap) -> Value { - UntaggedValue::row(entries).into_untagged_value() + value::row(entries).into_untagged_value() } fn table(list: &Vec) -> Value { - UntaggedValue::table(list).into_untagged_value() + value::table(list).into_untagged_value() } fn nu_releases_grouped_by_date() -> Value { diff --git a/src/commands/table.rs b/src/commands/table.rs index 71ee30c824..4fce36e437 100644 --- a/src/commands/table.rs +++ b/src/commands/table.rs @@ -1,7 +1,9 @@ use crate::commands::WholeStreamCommand; -use crate::errors::ShellError; +use crate::data::value; use crate::format::TableView; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; pub struct Table; @@ -56,7 +58,7 @@ fn table(args: CommandArgs, registry: &CommandRegistry) -> Result Result { - tags.insert_untagged("anchor", UntaggedValue::string(source)); + tags.insert_untagged("anchor", value::string(source)); } Some(AnchorLocation::Url(source)) => { - tags.insert_untagged("anchor", UntaggedValue::string(source)); + tags.insert_untagged("anchor", value::string(source)); } _ => {} } diff --git a/src/commands/to_bson.rs b/src/commands/to_bson.rs index 9156532b7e..9fab91a9d1 100644 --- a/src/commands/to_bson.rs +++ b/src/commands/to_bson.rs @@ -1,8 +1,12 @@ use crate::commands::WholeStreamCommand; -use crate::data::{Dictionary, Primitive, Value}; +use crate::data::value; use crate::prelude::*; -use crate::UnspannedPathMember; use bson::{encode_document, oid::ObjectId, spec::BinarySubtype, Bson, Document}; +use nu_errors::{CoerceInto, ShellError}; +use nu_protocol::{ + Dictionary, Primitive, ReturnSuccess, Signature, SpannedTypeName, UnspannedPathMember, + UntaggedValue, Value, +}; use std::convert::TryInto; pub struct ToBSON; @@ -190,7 +194,7 @@ fn get_binary_subtype<'a>(tagged_value: &'a Value) -> Result Err(ShellError::type_error( "bson binary", - tagged_value.type_name().spanned(tagged_value.span()), + tagged_value.spanned_type_name(), )), } } @@ -269,7 +273,7 @@ fn to_bson(args: CommandArgs, registry: &CommandRegistry) -> Result yield ReturnSuccess::value( - UntaggedValue::binary(x).into_value(&name_tag), + value::binary(x).into_value(&name_tag), ), _ => yield Err(ShellError::labeled_error_with_secondary( "Expected a table with BSON-compatible structure.tag() from pipeline", diff --git a/src/commands/to_csv.rs b/src/commands/to_csv.rs index 03643cc691..2ce9b9d6e4 100644 --- a/src/commands/to_csv.rs +++ b/src/commands/to_csv.rs @@ -1,7 +1,8 @@ use crate::commands::to_delimited_data::to_delimited_data; use crate::commands::WholeStreamCommand; -use crate::data::{Primitive, Value}; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Primitive, Signature, UntaggedValue, Value}; pub struct ToCSV; diff --git a/src/commands/to_delimited_data.rs b/src/commands/to_delimited_data.rs index 8494ce5377..ceadfef803 100644 --- a/src/commands/to_delimited_data.rs +++ b/src/commands/to_delimited_data.rs @@ -1,7 +1,9 @@ -use crate::data::{Primitive, Value}; +use crate::data::base::property_get::get_data_by_key; use crate::prelude::*; use csv::WriterBuilder; use indexmap::{indexset, IndexSet}; +use nu_errors::ShellError; +use nu_protocol::{Primitive, ReturnSuccess, UntaggedValue, Value}; use nu_source::Spanned; fn from_value_to_delimited_string( @@ -55,7 +57,7 @@ fn from_value_to_delimited_string( for l in list { let mut row = vec![]; for desc in &merged_descriptors { - match l.get_data_by_key(desc.borrow_spanned()) { + match get_data_by_key(l, desc.borrow_spanned()) { Some(s) => { row.push(to_string_tagged_value(&s)?); } @@ -129,10 +131,10 @@ fn to_string_tagged_value(v: &Value) -> Result { let tmp = format!("{}", b); Ok(tmp) } - UntaggedValue::Primitive(Primitive::Boolean(_)) => Ok(v.as_string()?), - UntaggedValue::Primitive(Primitive::Decimal(_)) => Ok(v.as_string()?), - UntaggedValue::Primitive(Primitive::Int(_)) => Ok(v.as_string()?), - UntaggedValue::Primitive(Primitive::Path(_)) => Ok(v.as_string()?), + UntaggedValue::Primitive(Primitive::Boolean(_)) => Ok(v.as_string()?.to_string()), + UntaggedValue::Primitive(Primitive::Decimal(_)) => Ok(v.as_string()?.to_string()), + UntaggedValue::Primitive(Primitive::Int(_)) => Ok(v.as_string()?.to_string()), + UntaggedValue::Primitive(Primitive::Path(_)) => Ok(v.as_string()?.to_string()), UntaggedValue::Table(_) => return Ok(String::from("[Table]")), UntaggedValue::Row(_) => return Ok(String::from("[Row]")), UntaggedValue::Primitive(Primitive::String(s)) => return Ok(s.to_string()), diff --git a/src/commands/to_json.rs b/src/commands/to_json.rs index b1dba6910b..10244a2260 100644 --- a/src/commands/to_json.rs +++ b/src/commands/to_json.rs @@ -1,7 +1,7 @@ use crate::commands::WholeStreamCommand; -use crate::data::base::{Primitive, UntaggedValue, Value}; use crate::prelude::*; -use crate::UnspannedPathMember; +use nu_errors::{CoerceInto, ShellError}; +use nu_protocol::{Primitive, ReturnSuccess, Signature, UnspannedPathMember, UntaggedValue, Value}; pub struct ToJSON; diff --git a/src/commands/to_sqlite.rs b/src/commands/to_sqlite.rs index b8a278e74a..0237b53e58 100644 --- a/src/commands/to_sqlite.rs +++ b/src/commands/to_sqlite.rs @@ -1,7 +1,8 @@ use crate::commands::WholeStreamCommand; -use crate::data::{Dictionary, Primitive, Value}; use crate::prelude::*; use hex::encode; +use nu_errors::ShellError; +use nu_protocol::{Dictionary, Primitive, ReturnSuccess, Signature, UntaggedValue, Value}; use rusqlite::{Connection, NO_PARAMS}; use std::io::Read; @@ -195,7 +196,7 @@ fn sqlite_input_stream_to_bytes(values: Vec) -> Result Result { diff --git a/src/commands/to_toml.rs b/src/commands/to_toml.rs index 71ff12ebee..7504d7def6 100644 --- a/src/commands/to_toml.rs +++ b/src/commands/to_toml.rs @@ -1,7 +1,7 @@ use crate::commands::WholeStreamCommand; -use crate::data::{Primitive, Value}; use crate::prelude::*; -use crate::UnspannedPathMember; +use nu_errors::{CoerceInto, ShellError}; +use nu_protocol::{Primitive, ReturnSuccess, Signature, UnspannedPathMember, UntaggedValue, Value}; pub struct ToTOML; diff --git a/src/commands/to_tsv.rs b/src/commands/to_tsv.rs index f567215e59..3177e1dca9 100644 --- a/src/commands/to_tsv.rs +++ b/src/commands/to_tsv.rs @@ -1,6 +1,8 @@ use crate::commands::to_delimited_data::to_delimited_data; use crate::commands::WholeStreamCommand; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::Signature; pub struct ToTSV; diff --git a/src/commands/to_url.rs b/src/commands/to_url.rs index 3cb12ac045..71f5db1554 100644 --- a/src/commands/to_url.rs +++ b/src/commands/to_url.rs @@ -1,6 +1,8 @@ use crate::commands::WholeStreamCommand; -use crate::data::Value; +use crate::data::value; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{ReturnSuccess, Signature, UntaggedValue, Value}; pub struct ToURL; @@ -41,7 +43,7 @@ fn to_url(args: CommandArgs, registry: &CommandRegistry) -> Result { - row_vec.push((k.clone(), s)); + row_vec.push((k.clone(), s.to_string())); } _ => { yield Err(ShellError::labeled_error_with_secondary( @@ -57,7 +59,7 @@ fn to_url(args: CommandArgs, registry: &CommandRegistry) -> Result { - yield ReturnSuccess::value(UntaggedValue::string(s).into_value(&tag)); + yield ReturnSuccess::value(value::string(s).into_value(&tag)); } _ => { yield Err(ShellError::labeled_error( diff --git a/src/commands/to_yaml.rs b/src/commands/to_yaml.rs index 3b3556726b..243ee80875 100644 --- a/src/commands/to_yaml.rs +++ b/src/commands/to_yaml.rs @@ -1,7 +1,7 @@ use crate::commands::WholeStreamCommand; -use crate::data::{Primitive, Value}; use crate::prelude::*; -use crate::UnspannedPathMember; +use nu_errors::{CoerceInto, ShellError}; +use nu_protocol::{Primitive, ReturnSuccess, Signature, UnspannedPathMember, UntaggedValue, Value}; pub struct ToYAML; diff --git a/src/commands/trim.rs b/src/commands/trim.rs index de10249dcf..3119fe511d 100644 --- a/src/commands/trim.rs +++ b/src/commands/trim.rs @@ -1,7 +1,8 @@ use crate::commands::WholeStreamCommand; -use crate::errors::ShellError; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{ReturnSuccess, Signature}; pub struct Trim; @@ -34,7 +35,7 @@ fn trim(args: CommandArgs, _registry: &CommandRegistry) -> Result Result registry::Signature { + fn signature(&self) -> Signature { Signature::build("where").required( "condition", SyntaxShape::Block, @@ -26,7 +26,7 @@ impl PerItemCommand for Where { fn run( &self, call_info: &CallInfo, - _registry: ®istry::CommandRegistry, + _registry: &CommandRegistry, _raw_args: &RawCommandArgs, input: Value, ) -> Result { @@ -37,7 +37,7 @@ impl PerItemCommand for Where { value: UntaggedValue::Block(block), .. } => { - let result = block.invoke(&input_clone); + let result = block.invoke(&Scope::new(input_clone.clone())); match result { Ok(v) => { if v.is_true() { diff --git a/src/commands/which_.rs b/src/commands/which_.rs index cc68adf59a..933f1b77d0 100644 --- a/src/commands/which_.rs +++ b/src/commands/which_.rs @@ -1,9 +1,7 @@ -use crate::data::Value; -use crate::errors::ShellError; -use crate::prelude::*; - use crate::commands::WholeStreamCommand; -use crate::parser::registry::Signature; +use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Primitive, Signature, SyntaxShape, UntaggedValue, Value}; pub struct Which; diff --git a/src/context.rs b/src/context.rs index 5535e9c1d4..3696944130 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,12 +1,12 @@ 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::shell::shell_manager::ShellManager; use crate::stream::{InputStream, OutputStream}; use indexmap::IndexMap; -use nu_source::Tag; -use nu_source::Text; +use nu_errors::ShellError; +use nu_parser::{hir, hir::syntax_shape::ExpandContext, hir::syntax_shape::SignatureRegistry}; +use nu_protocol::{errln, Signature}; +use nu_source::{Tag, Text}; use std::error::Error; use std::sync::atomic::AtomicBool; use std::sync::{Arc, Mutex}; @@ -16,6 +16,17 @@ pub struct CommandRegistry { registry: Arc>>>, } +impl SignatureRegistry for CommandRegistry { + fn has(&self, name: &str) -> bool { + let registry = self.registry.lock().unwrap(); + registry.contains_key(name) + } + fn get(&self, name: &str) -> Option { + let registry = self.registry.lock().unwrap(); + registry.get(name).map(|command| command.signature()) + } +} + impl CommandRegistry { pub fn new() -> CommandRegistry { CommandRegistry { @@ -76,7 +87,11 @@ impl Context { &'context self, source: &'context Text, ) -> ExpandContext<'context> { - ExpandContext::new(&self.registry, source, self.shell_manager.homedir()) + ExpandContext::new( + Box::new(self.registry.clone()), + source, + self.shell_manager.homedir(), + ) } pub(crate) fn basic() -> Result> { diff --git a/src/data.rs b/src/data.rs index a0968e3085..80518ee6b6 100644 --- a/src/data.rs +++ b/src/data.rs @@ -3,10 +3,10 @@ pub(crate) mod command; pub(crate) mod config; pub(crate) mod dict; pub(crate) mod files; -pub(crate) mod into; +pub mod primitive; pub(crate) mod types; +pub mod value; -pub(crate) use base::{Primitive, Value}; pub(crate) use command::command_dict; -pub(crate) use dict::{Dictionary, TaggedDictBuilder, TaggedListBuilder}; +pub(crate) use dict::{TaggedDictBuilder, TaggedListBuilder}; pub(crate) use files::dir_entry_dict; diff --git a/src/data/base.rs b/src/data/base.rs index 605e2fc216..54341467f7 100644 --- a/src/data/base.rs +++ b/src/data/base.rs @@ -1,222 +1,26 @@ -mod debug; -mod property_get; +pub(crate) mod property_get; pub(crate) mod shape; use crate::context::CommandRegistry; -use crate::data::base::shape::{Column, InlineShape, TypeShape}; -use crate::data::TaggedDictBuilder; -use crate::errors::ShellError; -use crate::evaluate::{evaluate_baseline_expr, Scope}; -use crate::parser::hir::path::{ColumnPath, PathMember}; -use crate::parser::{hir, Operator}; -use crate::prelude::*; +use crate::data::base::property_get::ValueExt; +use crate::data::{value, TaggedDictBuilder}; +use crate::evaluate::evaluate_baseline_expr; +use bigdecimal::BigDecimal; use chrono::{DateTime, Utc}; -use chrono_humanize::Humanize; use derive_new::new; -use indexmap::IndexMap; use log::trace; -use nu_source::{AnchorLocation, PrettyDebug, SpannedItem, Tagged, TaggedItem, Text}; +use nu_errors::ShellError; +use nu_parser::{hir, Operator}; +use nu_protocol::{ + Evaluate, EvaluateTrait, Primitive, Scope, ShellTypeName, SpannedTypeName, UntaggedValue, Value, +}; +use nu_source::{Tag, Text}; +use num_bigint::BigInt; +use num_traits::Zero; +use query_interface::{interfaces, vtable_for, ObjectHash}; use serde::{Deserialize, Serialize}; -use std::path::PathBuf; use std::time::SystemTime; -mod serde_bigint { - use num_traits::cast::FromPrimitive; - use num_traits::cast::ToPrimitive; - - pub fn serialize(big_int: &super::BigInt, serializer: S) -> Result - where - S: serde::Serializer, - { - serde::Serialize::serialize( - &big_int - .to_i64() - .ok_or(serde::ser::Error::custom("expected a i64-sized bignum"))?, - serializer, - ) - } - - pub fn deserialize<'de, D>(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let x: i64 = serde::Deserialize::deserialize(deserializer)?; - Ok(super::BigInt::from_i64(x) - .ok_or(serde::de::Error::custom("expected a i64-sized bignum"))?) - } -} - -mod serde_bigdecimal { - use num_traits::cast::FromPrimitive; - use num_traits::cast::ToPrimitive; - - pub fn serialize(big_decimal: &super::BigDecimal, serializer: S) -> Result - where - S: serde::Serializer, - { - serde::Serialize::serialize( - &big_decimal - .to_f64() - .ok_or(serde::ser::Error::custom("expected a f64-sized bignum"))?, - serializer, - ) - } - - pub fn deserialize<'de, D>(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let x: f64 = serde::Deserialize::deserialize(deserializer)?; - Ok(super::BigDecimal::from_f64(x) - .ok_or(serde::de::Error::custom("expected a f64-sized bigdecimal"))?) - } -} - -#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Deserialize, Serialize)] -pub enum Primitive { - Nothing, - #[serde(with = "serde_bigint")] - Int(BigInt), - #[serde(with = "serde_bigdecimal")] - Decimal(BigDecimal), - Bytes(u64), - String(String), - ColumnPath(ColumnPath), - Pattern(String), - Boolean(bool), - Date(DateTime), - Duration(u64), // Duration in seconds - Path(PathBuf), - #[serde(with = "serde_bytes")] - Binary(Vec), - - // Stream markers (used as bookend markers rather than actual values) - BeginningOfStream, - EndOfStream, -} - -impl ShellTypeName for Primitive { - fn type_name(&self) -> &'static str { - match self { - Primitive::Nothing => "nothing", - Primitive::Int(_) => "integer", - Primitive::Decimal(_) => "decimal", - Primitive::Bytes(_) => "bytes", - Primitive::String(_) => "string", - Primitive::ColumnPath(_) => "column path", - Primitive::Pattern(_) => "pattern", - Primitive::Boolean(_) => "boolean", - Primitive::Date(_) => "date", - Primitive::Duration(_) => "duration", - Primitive::Path(_) => "file path", - Primitive::Binary(_) => "binary", - Primitive::BeginningOfStream => "marker", - Primitive::EndOfStream => "marker", - } - } -} - -impl From for Primitive { - fn from(decimal: BigDecimal) -> Primitive { - Primitive::Decimal(decimal) - } -} - -impl From for Primitive { - fn from(float: f64) -> Primitive { - Primitive::Decimal(BigDecimal::from_f64(float).unwrap()) - } -} - -impl Primitive { - pub fn number(number: impl Into) -> Primitive { - let number = number.into(); - - match number { - Number::Int(int) => Primitive::Int(int), - Number::Decimal(decimal) => Primitive::Decimal(decimal), - } - } - - pub fn format(&self, field_name: Option<&String>) -> String { - match self { - Primitive::Nothing => String::new(), - Primitive::BeginningOfStream => String::new(), - Primitive::EndOfStream => String::new(), - Primitive::Path(p) => format!("{}", p.display()), - Primitive::Bytes(b) => { - let byte = byte_unit::Byte::from_bytes(*b as u128); - - if byte.get_bytes() == 0u128 { - return "—".to_string(); - } - - let byte = byte.get_appropriate_unit(false); - - match byte.get_unit() { - byte_unit::ByteUnit::B => format!("{} B ", byte.get_value()), - _ => format!("{}", byte.format(1)), - } - } - Primitive::Duration(sec) => format_duration(*sec), - Primitive::Int(i) => format!("{}", i), - Primitive::Decimal(decimal) => format!("{}", decimal), - Primitive::Pattern(s) => format!("{}", s), - Primitive::String(s) => format!("{}", s), - Primitive::ColumnPath(p) => { - let mut members = p.iter(); - let mut f = String::new(); - - f.push_str( - &members - .next() - .expect("BUG: column path with zero members") - .display(), - ); - - for member in members { - f.push_str("."); - f.push_str(&member.display()) - } - - f - } - Primitive::Boolean(b) => match (b, field_name) { - (true, None) => format!("Yes"), - (false, None) => format!("No"), - (true, Some(s)) if !s.is_empty() => format!("{}", s), - (false, Some(s)) if !s.is_empty() => format!(""), - (true, Some(_)) => format!("Yes"), - (false, Some(_)) => format!("No"), - }, - Primitive::Binary(_) => format!(""), - Primitive::Date(d) => format!("{}", d.humanize()), - } - } - - pub fn style(&self) -> &'static str { - match self { - Primitive::Bytes(0) => "c", // centre 'missing' indicator - Primitive::Int(_) | Primitive::Bytes(_) | Primitive::Decimal(_) => "r", - _ => "", - } - } -} - -fn format_duration(sec: u64) -> String { - let (minutes, seconds) = (sec / 60, sec % 60); - let (hours, minutes) = (minutes / 60, minutes % 60); - let (days, hours) = (hours / 24, hours % 24); - - match (days, hours, minutes, seconds) { - (0, 0, 0, 1) => format!("1 sec"), - (0, 0, 0, s) => format!("{} secs", s), - (0, 0, m, s) => format!("{}:{:02}", m, s), - (0, h, m, s) => format!("{}:{:02}:{:02}", h, m, s), - (d, h, m, s) => format!("{}:{:02}:{:02}:{:02}", d, h, m, s), - } -} - #[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, new, Serialize)] pub struct Operation { pub(crate) left: Value, @@ -231,12 +35,13 @@ pub struct Block { pub(crate) tag: Tag, } -impl Block { - pub fn invoke(&self, value: &Value) -> Result { - let scope = Scope::new(value.clone()); +interfaces!(Block: dyn ObjectHash); +#[typetag::serde] +impl EvaluateTrait for Block { + fn invoke(&self, scope: &Scope) -> Result { if self.expressions.len() == 0 { - return Ok(UntaggedValue::nothing().into_value(&self.tag)); + return Ok(value::nothing().into_value(&self.tag)); } let mut last = None; @@ -260,231 +65,10 @@ impl Block { Ok(last.unwrap()) } -} -#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Serialize, Deserialize)] -pub enum UntaggedValue { - Primitive(Primitive), - Row(crate::data::Dictionary), - Table(Vec), - - // Errors are a type of value too - Error(ShellError), - - Block(Block), -} - -#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)] -pub struct Value { - pub value: UntaggedValue, - pub tag: Tag, -} - -impl std::ops::Deref for Value { - type Target = UntaggedValue; - - fn deref(&self) -> &Self::Target { - &self.value - } -} - -impl Into for Value { - fn into(self) -> UntaggedValue { - self.value - } -} - -impl<'a> Into<&'a UntaggedValue> for &'a Value { - fn into(self) -> &'a UntaggedValue { - &self.value - } -} - -impl HasSpan for Value { - fn span(&self) -> Span { - self.tag.span - } -} - -impl ShellTypeName for Value { - fn type_name(&self) -> &'static str { - ShellTypeName::type_name(&self.value) - } -} - -impl ShellTypeName for UntaggedValue { - fn type_name(&self) -> &'static str { - match &self { - UntaggedValue::Primitive(p) => p.type_name(), - UntaggedValue::Row(_) => "row", - UntaggedValue::Table(_) => "table", - UntaggedValue::Error(_) => "error", - UntaggedValue::Block(_) => "block", - } - } -} - -impl Into for Number { - fn into(self) -> UntaggedValue { - match self { - Number::Int(int) => UntaggedValue::int(int), - Number::Decimal(decimal) => UntaggedValue::decimal(decimal), - } - } -} - -impl Into for &Number { - fn into(self) -> UntaggedValue { - match self { - Number::Int(int) => UntaggedValue::int(int.clone()), - Number::Decimal(decimal) => UntaggedValue::decimal(decimal.clone()), - } - } -} - -impl Value { - pub fn anchor(&self) -> Option { - self.tag.anchor() - } - - pub fn anchor_name(&self) -> Option { - self.tag.anchor_name() - } - - pub fn tag(&self) -> Tag { - self.tag.clone() - } - - pub fn into_parts(self) -> (UntaggedValue, Tag) { - (self.value, self.tag) - } - - pub(crate) fn as_path(&self) -> Result { - match &self.value { - UntaggedValue::Primitive(Primitive::Path(path)) => Ok(path.clone()), - UntaggedValue::Primitive(Primitive::String(path_str)) => { - Ok(PathBuf::from(&path_str).clone()) - } - _ => Err(ShellError::type_error("Path", self.spanned_type_name())), - } - } - - pub fn tagged_type_name(&self) -> Tagged { - let name = self.type_name().to_string(); - name.tagged(self.tag.clone()) - } - - pub(crate) fn compare( - &self, - operator: &Operator, - other: &Value, - ) -> Result { - match operator { - _ => { - let coerced = coerce_compare(self, other)?; - let ordering = coerced.compare(); - - use std::cmp::Ordering; - - let result = match (operator, ordering) { - (Operator::Equal, Ordering::Equal) => true, - (Operator::NotEqual, Ordering::Less) - | (Operator::NotEqual, Ordering::Greater) => true, - (Operator::LessThan, Ordering::Less) => true, - (Operator::GreaterThan, Ordering::Greater) => true, - (Operator::GreaterThanOrEqual, Ordering::Greater) - | (Operator::GreaterThanOrEqual, Ordering::Equal) => true, - (Operator::LessThanOrEqual, Ordering::Less) - | (Operator::LessThanOrEqual, Ordering::Equal) => true, - _ => false, - }; - - Ok(result) - } - } - } -} - -impl PrettyDebug for &Value { - fn pretty(&self) -> DebugDocBuilder { - PrettyDebug::pretty(*self) - } -} - -impl PrettyDebug for Value { - fn pretty(&self) -> DebugDocBuilder { - match &self.value { - UntaggedValue::Primitive(p) => p.pretty(), - UntaggedValue::Row(row) => row.pretty_builder().nest(1).group().into(), - UntaggedValue::Table(table) => { - b::delimit("[", b::intersperse(table, b::space()), "]").nest() - } - UntaggedValue::Error(_) => b::error("error"), - UntaggedValue::Block(_) => b::opaque("block"), - } - } -} - -impl std::convert::TryFrom<&Value> for Block { - type Error = ShellError; - - fn try_from(value: &Value) -> Result { - match &value.value { - UntaggedValue::Block(block) => Ok(block.clone()), - _ => Err(ShellError::type_error( - "Block", - value.type_name().spanned(value.tag.span), - )), - } - } -} - -impl std::convert::TryFrom<&Value> for i64 { - type Error = ShellError; - - fn try_from(value: &Value) -> Result { - match &value.value { - UntaggedValue::Primitive(Primitive::Int(int)) => { - int.tagged(&value.tag).coerce_into("converting to i64") - } - _ => Err(ShellError::type_error("Integer", value.spanned_type_name())), - } - } -} - -impl std::convert::TryFrom<&Value> for String { - type Error = ShellError; - - fn try_from(value: &Value) -> Result { - match &value.value { - UntaggedValue::Primitive(Primitive::String(s)) => Ok(s.clone()), - _ => Err(ShellError::type_error("String", value.spanned_type_name())), - } - } -} - -impl std::convert::TryFrom<&Value> for Vec { - type Error = ShellError; - - fn try_from(value: &Value) -> Result, ShellError> { - match &value.value { - UntaggedValue::Primitive(Primitive::Binary(b)) => Ok(b.clone()), - _ => Err(ShellError::type_error("Binary", value.spanned_type_name())), - } - } -} - -impl<'a> std::convert::TryFrom<&'a Value> for &'a crate::data::Dictionary { - type Error = ShellError; - - fn try_from(value: &'a Value) -> Result<&'a crate::data::Dictionary, ShellError> { - match &value.value { - UntaggedValue::Row(d) => Ok(d), - _ => Err(ShellError::type_error( - "Dictionary", - value.spanned_type_name(), - )), - } + fn clone_box(&self) -> Evaluate { + let block = self.clone(); + Evaluate::new(block) } } @@ -508,188 +92,6 @@ impl std::convert::TryFrom> for Switch { } } -impl UntaggedValue { - pub fn into_value(self, tag: impl Into) -> Value { - Value { - value: self, - tag: tag.into(), - } - } - - pub fn into_untagged_value(self) -> Value { - Value { - value: self, - tag: Tag::unknown(), - } - } - - pub fn retag(self, tag: impl Into) -> Value { - Value { - value: self, - tag: tag.into(), - } - } - - pub fn data_descriptors(&self) -> Vec { - match self { - UntaggedValue::Primitive(_) => vec![], - UntaggedValue::Row(columns) => columns - .entries - .keys() - .into_iter() - .map(|x| x.to_string()) - .collect(), - UntaggedValue::Block(_) => vec![], - UntaggedValue::Table(_) => vec![], - UntaggedValue::Error(_) => vec![], - } - } - - #[allow(unused)] - pub(crate) fn format_type(&self, width: usize) -> String { - TypeShape::from_value(self).colored_string(width) - } - - pub(crate) fn format_leaf(&self) -> DebugDocBuilder { - InlineShape::from_value(self).format().pretty() - } - - #[allow(unused)] - pub(crate) fn format_for_column(&self, column: impl Into) -> DebugDocBuilder { - InlineShape::from_value(self) - .format_for_column(column) - .pretty() - } - - pub(crate) fn style_leaf(&self) -> &'static str { - match self { - UntaggedValue::Primitive(p) => p.style(), - _ => "", - } - } - - pub(crate) fn is_true(&self) -> bool { - match self { - UntaggedValue::Primitive(Primitive::Boolean(true)) => true, - _ => false, - } - } - - pub(crate) fn is_some(&self) -> bool { - !self.is_none() - } - - pub(crate) fn is_none(&self) -> bool { - match self { - UntaggedValue::Primitive(Primitive::Nothing) => true, - _ => false, - } - } - - pub(crate) fn is_error(&self) -> bool { - match self { - UntaggedValue::Error(_err) => true, - _ => false, - } - } - - pub(crate) fn expect_error(&self) -> ShellError { - match self { - UntaggedValue::Error(err) => err.clone(), - _ => panic!("Don't call expect_error without first calling is_error"), - } - } - - pub fn expect_string(&self) -> &str { - match self { - UntaggedValue::Primitive(Primitive::String(string)) => &string[..], - _ => panic!("expect_string assumes that the value must be a string"), - } - } - - #[allow(unused)] - pub fn row(entries: IndexMap) -> UntaggedValue { - UntaggedValue::Row(entries.into()) - } - - pub fn table(list: &Vec) -> UntaggedValue { - UntaggedValue::Table(list.to_vec()) - } - - pub fn string(s: impl Into) -> UntaggedValue { - UntaggedValue::Primitive(Primitive::String(s.into())) - } - - pub fn column_path(s: Vec>) -> UntaggedValue { - UntaggedValue::Primitive(Primitive::ColumnPath(ColumnPath::new( - s.into_iter().map(|p| p.into()).collect(), - ))) - } - - pub fn int(i: impl Into) -> UntaggedValue { - UntaggedValue::Primitive(Primitive::Int(i.into())) - } - - pub fn pattern(s: impl Into) -> UntaggedValue { - UntaggedValue::Primitive(Primitive::String(s.into())) - } - - pub fn path(s: impl Into) -> UntaggedValue { - UntaggedValue::Primitive(Primitive::Path(s.into())) - } - - pub fn bytes(s: impl Into) -> UntaggedValue { - UntaggedValue::Primitive(Primitive::Bytes(s.into())) - } - - pub fn decimal(s: impl Into) -> UntaggedValue { - UntaggedValue::Primitive(Primitive::Decimal(s.into())) - } - - pub fn binary(binary: Vec) -> UntaggedValue { - UntaggedValue::Primitive(Primitive::Binary(binary)) - } - - pub fn number(s: impl Into) -> UntaggedValue { - let num = s.into(); - - match num { - Number::Int(int) => UntaggedValue::int(int), - Number::Decimal(decimal) => UntaggedValue::decimal(decimal), - } - } - - pub fn boolean(s: impl Into) -> UntaggedValue { - UntaggedValue::Primitive(Primitive::Boolean(s.into())) - } - - pub fn duration(secs: u64) -> UntaggedValue { - UntaggedValue::Primitive(Primitive::Duration(secs)) - } - - pub fn system_date(s: SystemTime) -> UntaggedValue { - UntaggedValue::Primitive(Primitive::Date(s.into())) - } - - pub fn date_from_str(s: Tagged<&str>) -> Result { - let date = DateTime::parse_from_rfc3339(s.item).map_err(|err| { - ShellError::labeled_error( - &format!("Date parse error: {}", err), - "original value", - s.tag, - ) - })?; - - let date = date.with_timezone(&chrono::offset::Utc); - - Ok(UntaggedValue::Primitive(Primitive::Date(date))) - } - - pub fn nothing() -> UntaggedValue { - UntaggedValue::Primitive(Primitive::Nothing) - } -} - pub(crate) fn select_fields(obj: &Value, fields: &[String], tag: impl Into) -> Value { let mut out = TaggedDictBuilder::new(tag); @@ -697,7 +99,7 @@ pub(crate) fn select_fields(obj: &Value, fields: &[String], tag: impl Into) for field in fields { match descs.iter().find(|d| *d == field) { - None => out.insert_untagged(field, UntaggedValue::nothing()), + None => out.insert_untagged(field, value::nothing()), Some(desc) => out.insert_value(desc.clone(), obj.get_data(desc).borrow().clone()), } } @@ -721,7 +123,7 @@ pub(crate) fn reject_fields(obj: &Value, fields: &[String], tag: impl Into) out.into_value() } -enum CompareValues { +pub(crate) enum CompareValues { Ints(BigInt, BigInt), Decimals(BigDecimal, BigDecimal), String(String, String), @@ -730,7 +132,7 @@ enum CompareValues { } impl CompareValues { - fn compare(&self) -> std::cmp::Ordering { + pub fn compare(&self) -> std::cmp::Ordering { match self { CompareValues::Ints(left, right) => left.cmp(right), CompareValues::Decimals(left, right) => left.cmp(right), @@ -747,11 +149,11 @@ impl CompareValues { } } -fn coerce_compare( - left: &Value, - right: &Value, +pub(crate) fn coerce_compare( + left: &UntaggedValue, + right: &UntaggedValue, ) -> Result { - match (&left.value, &right.value) { + match (left, right) { (UntaggedValue::Primitive(left), UntaggedValue::Primitive(right)) => { coerce_compare_primitive(left, right) } @@ -791,30 +193,28 @@ fn coerce_compare_primitive( } #[cfg(test)] mod tests { - - use super::UntaggedValue; - use crate::parser::hir::path::PathMember; - use crate::ColumnPath as ColumnPathValue; - use crate::ShellError; - use crate::Value; + use super::value; + use crate::data::base::property_get::{as_column_path, ValueExt}; use indexmap::IndexMap; + use nu_errors::ShellError; + use nu_protocol::{ColumnPath as ColumnPathValue, PathMember, Value}; use nu_source::*; use num_bigint::BigInt; fn string(input: impl Into) -> Value { - UntaggedValue::string(input.into()).into_untagged_value() + value::string(input.into()).into_untagged_value() } fn int(input: impl Into) -> Value { - UntaggedValue::int(input.into()).into_untagged_value() + value::int(input.into()).into_untagged_value() } fn row(entries: IndexMap) -> Value { - UntaggedValue::row(entries).into_untagged_value() + value::row(entries).into_untagged_value() } fn table(list: &Vec) -> Value { - UntaggedValue::table(list).into_untagged_value() + value::table(list).into_untagged_value() } fn error_callback( @@ -824,14 +224,12 @@ mod tests { } fn column_path(paths: &Vec) -> Tagged { - table(&paths.iter().cloned().collect()) - .as_column_path() - .unwrap() + as_column_path(&table(&paths.iter().cloned().collect())).unwrap() } #[test] fn gets_matching_field_from_a_row() { - let row = UntaggedValue::row(indexmap! { + let row = value::row(indexmap! { "amigos".into() => table(&vec![string("andres"),string("jonathan"),string("yehuda")]) }) .into_untagged_value(); @@ -852,7 +250,7 @@ mod tests { let (version, tag) = string("0.4.0").into_parts(); - let value = UntaggedValue::row(indexmap! { + let value = value::row(indexmap! { "package".into() => row(indexmap! { "name".into() => string("nu"), @@ -875,7 +273,7 @@ mod tests { let (_, tag) = string("Andrés N. Robalino").into_parts(); - let value = UntaggedValue::row(indexmap! { + let value = value::row(indexmap! { "package".into() => row(indexmap! { "name".into() => string("nu"), "version".into() => string("0.4.0"), @@ -909,7 +307,7 @@ mod tests { let (_, tag) = string("Andrés N. Robalino").into_parts(); - let value = UntaggedValue::row(indexmap! { + let value = value::row(indexmap! { "package".into() => row(indexmap! { "name".into() => string("nu"), "version".into() => string("0.4.0"), @@ -926,7 +324,7 @@ mod tests { .into_value(tag) .get_data_by_column_path(&field_path, Box::new(error_callback("package.authors.0"))) .unwrap(), - UntaggedValue::row(indexmap! { + value::row(indexmap! { "name".into() => string("Andrés N. Robalino") }) ); @@ -938,7 +336,7 @@ mod tests { let (_, tag) = string("Andrés N. Robalino").into_parts(); - let value = UntaggedValue::row(indexmap! { + let value = value::row(indexmap! { "package".into() => row(indexmap! { "name".into() => string("nu"), "version".into() => string("0.4.0"), @@ -958,7 +356,7 @@ mod tests { Box::new(error_callback("package.authors.\"0\"")) ) .unwrap(), - UntaggedValue::row(indexmap! { + value::row(indexmap! { "name".into() => string("Andrés N. Robalino") }) ); @@ -968,7 +366,7 @@ mod tests { fn replaces_matching_field_from_a_row() { let field_path = column_path(&vec![string("amigos")]); - let sample = UntaggedValue::row(indexmap! { + let sample = value::row(indexmap! { "amigos".into() => table(&vec![ string("andres"), string("jonathan"), @@ -994,7 +392,7 @@ mod tests { string("los.3.caballeros"), ]); - let sample = UntaggedValue::row(indexmap! { + let sample = value::row(indexmap! { "package".into() => row(indexmap! { "authors".into() => row(indexmap! { "los.3.mosqueteros".into() => table(&vec![string("andres::yehuda::jonathan")]), @@ -1014,7 +412,7 @@ mod tests { assert_eq!( actual, - UntaggedValue::row(indexmap! { + value::row(indexmap! { "package".into() => row(indexmap! { "authors".into() => row(indexmap! { "los.3.mosqueteros".into() => table(&vec![string("andres::yehuda::jonathan")]), @@ -1031,7 +429,7 @@ mod tests { string("nu.version.arepa"), ]); - let sample = UntaggedValue::row(indexmap! { + let sample = value::row(indexmap! { "shell_policy".into() => row(indexmap! { "releases".into() => table(&vec![ row(indexmap! { @@ -1066,7 +464,7 @@ mod tests { assert_eq!( actual, - UntaggedValue::row(indexmap! { + value::row(indexmap! { "shell_policy".into() => row(indexmap! { "releases".into() => table(&vec![ row(indexmap! { diff --git a/src/data/base/property_get.rs b/src/data/base/property_get.rs index 047484918d..b447524802 100644 --- a/src/data/base/property_get.rs +++ b/src/data/base/property_get.rs @@ -1,318 +1,416 @@ -use crate::errors::ExpectedRange; -use crate::parser::hir::path::{PathMember, UnspannedPathMember}; +use crate::data::value; use crate::prelude::*; -use crate::ColumnPath; -use crate::SpannedTypeName; +use nu_errors::{ExpectedRange, ShellError}; +use nu_protocol::{ + ColumnPath, PathMember, Primitive, ShellTypeName, SpannedTypeName, UnspannedPathMember, + UntaggedValue, Value, +}; use nu_source::{Spanned, SpannedItem, Tagged}; -impl Value { - pub(crate) fn get_data_by_member(&self, name: &PathMember) -> Result { - match &self.value { - // If the value is a row, the member is a column name - UntaggedValue::Row(o) => match &name.unspanned { - // If the member is a string, get the data - UnspannedPathMember::String(string) => o - .get_data_by_key(string[..].spanned(name.span)) - .ok_or_else(|| { - ShellError::missing_property( - "row".spanned(self.tag.span), - string.spanned(name.span), - ) - }), +pub trait ValueExt { + fn into_parts(self) -> (UntaggedValue, Tag); + fn get_data(&self, desc: &String) -> MaybeOwned<'_, Value>; + fn get_data_by_key(&self, name: Spanned<&str>) -> Option; + fn get_data_by_member(&self, name: &PathMember) -> Result; + fn get_data_by_column_path( + &self, + path: &ColumnPath, + callback: Box ShellError>, + ) -> Result; + fn insert_data_at_path(&self, path: &str, new_value: Value) -> Option; + fn insert_data_at_member( + &mut self, + member: &PathMember, + new_value: Value, + ) -> Result<(), ShellError>; + fn insert_data_at_column_path( + &self, + split_path: &ColumnPath, + new_value: Value, + ) -> Result; + fn replace_data_at_column_path( + &self, + split_path: &ColumnPath, + replaced_value: Value, + ) -> Option; + fn as_column_path(&self) -> Result, ShellError>; + fn as_path_member(&self) -> Result; + fn as_string(&self) -> Result; +} - // If the member is a number, it's an error - UnspannedPathMember::Int(_) => Err(ShellError::invalid_integer_index( - "row".spanned(self.tag.span), - name.span, - )), - }, - - // If the value is a table - UntaggedValue::Table(l) => { - match &name.unspanned { - // If the member is a string, map over the member - UnspannedPathMember::String(string) => { - let mut out = vec![]; - - for item in l { - match item { - Value { - value: UntaggedValue::Row(o), - .. - } => match o.get_data_by_key(string[..].spanned(name.span)) { - Some(v) => out.push(v), - None => {} - }, - _ => {} - } - } - - if out.len() == 0 { - Err(ShellError::missing_property( - "table".spanned(self.tag.span), - string.spanned(name.span), - )) - } else { - Ok(UntaggedValue::Table(out) - .into_value(Tag::new(self.anchor(), name.span))) - } - } - UnspannedPathMember::Int(int) => { - let index = int.to_usize().ok_or_else(|| { - ShellError::range_error( - ExpectedRange::Usize, - &"massive integer".spanned(name.span), - "indexing", - ) - })?; - - match self.get_data_by_index(index.spanned(self.tag.span)) { - Some(v) => Ok(v.clone()), - None => Err(ShellError::range_error( - 0..(l.len()), - &int.spanned(name.span), - "indexing", - )), - } - } - } - } - other => Err(ShellError::type_error( - "row or table", - other.type_name().spanned(self.tag.span), - )), - } +impl ValueExt for Value { + fn into_parts(self) -> (UntaggedValue, Tag) { + (self.value, self.tag) } - pub fn get_data_by_column_path( + fn get_data(&self, desc: &String) -> MaybeOwned<'_, Value> { + get_data(self, desc) + } + + fn get_data_by_key(&self, name: Spanned<&str>) -> Option { + get_data_by_key(self, name) + } + + fn get_data_by_member(&self, name: &PathMember) -> Result { + get_data_by_member(self, name) + } + + fn get_data_by_column_path( &self, path: &ColumnPath, callback: Box ShellError>, ) -> Result { - let mut current = self.clone(); - - for p in path.iter() { - let value = current.get_data_by_member(p); - - match value { - Ok(v) => current = v.clone(), - Err(e) => return Err(callback((¤t.clone(), &p.clone(), e))), - } - } - - Ok(current) + get_data_by_column_path(self, path, callback) } - pub fn insert_data_at_path(&self, path: &str, new_value: Value) -> Option { - let mut new_obj = self.clone(); - - let split_path: Vec<_> = path.split(".").collect(); - - if let UntaggedValue::Row(ref mut o) = new_obj.value { - let mut current = o; - - if split_path.len() == 1 { - // Special case for inserting at the top level - current.entries.insert( - path.to_string(), - new_value.value.clone().into_value(&self.tag), - ); - return Some(new_obj); - } - - for idx in 0..split_path.len() { - match current.entries.get_mut(split_path[idx]) { - Some(next) => { - if idx == (split_path.len() - 2) { - match &mut next.value { - UntaggedValue::Row(o) => { - o.entries.insert( - split_path[idx + 1].to_string(), - new_value.value.clone().into_value(&self.tag), - ); - } - _ => {} - } - - return Some(new_obj.clone()); - } else { - match next.value { - UntaggedValue::Row(ref mut o) => { - current = o; - } - _ => return None, - } - } - } - _ => return None, - } - } - } - - None + fn insert_data_at_path(&self, path: &str, new_value: Value) -> Option { + insert_data_at_path(self, path, new_value) } - pub fn insert_data_at_member( + fn insert_data_at_member( &mut self, member: &PathMember, new_value: Value, ) -> Result<(), ShellError> { - match &mut self.value { - UntaggedValue::Row(dict) => match &member.unspanned { - UnspannedPathMember::String(key) => Ok({ - dict.insert_data_at_key(key, new_value); - }), - UnspannedPathMember::Int(_) => Err(ShellError::type_error( - "column name", - "integer".spanned(member.span), - )), - }, - UntaggedValue::Table(array) => match &member.unspanned { - UnspannedPathMember::String(_) => Err(ShellError::type_error( - "list index", - "string".spanned(member.span), - )), - UnspannedPathMember::Int(int) => Ok({ - let int = int.to_usize().ok_or_else(|| { - ShellError::range_error( - ExpectedRange::Usize, - &"bigger number".spanned(member.span), - "inserting into a list", - ) - })?; - - insert_data_at_index(array, int.tagged(member.span), new_value.clone())?; - }), - }, - other => match &member.unspanned { - UnspannedPathMember::String(_) => Err(ShellError::type_error( - "row", - other.type_name().spanned(self.span()), - )), - UnspannedPathMember::Int(_) => Err(ShellError::type_error( - "table", - other.type_name().spanned(self.span()), - )), - }, - } + insert_data_at_member(self, member, new_value) } - pub fn insert_data_at_column_path( + fn insert_data_at_column_path( &self, split_path: &ColumnPath, new_value: Value, ) -> Result { - let (last, front) = split_path.split_last(); - let mut original = self.clone(); - - let mut current: &mut Value = &mut original; - - for member in front { - let type_name = current.spanned_type_name(); - - current = current.get_mut_data_by_member(&member).ok_or_else(|| { - ShellError::missing_property( - member.plain_string(std::usize::MAX).spanned(member.span), - type_name, - ) - })? - } - - current.insert_data_at_member(&last, new_value)?; - - Ok(original) + insert_data_at_column_path(self, split_path, new_value) } - pub fn replace_data_at_column_path( + fn replace_data_at_column_path( &self, split_path: &ColumnPath, replaced_value: Value, ) -> Option { - let mut new_obj: Value = self.clone(); - let mut current = &mut new_obj; - let split_path = split_path.members(); + replace_data_at_column_path(self, split_path, replaced_value) + } - for idx in 0..split_path.len() { - match current.get_mut_data_by_member(&split_path[idx]) { - Some(next) => { - if idx == (split_path.len() - 1) { - *next = replaced_value.value.into_value(&self.tag); - return Some(new_obj); + fn as_column_path(&self) -> Result, ShellError> { + as_column_path(self) + } + + fn as_path_member(&self) -> Result { + as_path_member(self) + } + + fn as_string(&self) -> Result { + as_string(self) + } +} + +pub(crate) fn get_data_by_member(value: &Value, name: &PathMember) -> Result { + match &value.value { + // If the value is a row, the member is a column name + UntaggedValue::Row(o) => match &name.unspanned { + // If the member is a string, get the data + UnspannedPathMember::String(string) => o + .get_data_by_key(string[..].spanned(name.span)) + .ok_or_else(|| { + ShellError::missing_property( + "row".spanned(value.tag.span), + string.spanned(name.span), + ) + }), + + // If the member is a number, it's an error + UnspannedPathMember::Int(_) => Err(ShellError::invalid_integer_index( + "row".spanned(value.tag.span), + name.span, + )), + }, + + // If the value is a table + UntaggedValue::Table(l) => { + match &name.unspanned { + // If the member is a string, map over the member + UnspannedPathMember::String(string) => { + let mut out = vec![]; + + for item in l { + match item { + Value { + value: UntaggedValue::Row(o), + .. + } => match o.get_data_by_key(string[..].spanned(name.span)) { + Some(v) => out.push(v), + None => {} + }, + _ => {} + } + } + + if out.len() == 0 { + Err(ShellError::missing_property( + "table".spanned(value.tag.span), + string.spanned(name.span), + )) } else { - current = next; + Ok(UntaggedValue::Table(out) + .into_value(Tag::new(value.anchor(), name.span))) } } - None => { - return None; + UnspannedPathMember::Int(int) => { + let index = int.to_usize().ok_or_else(|| { + ShellError::range_error( + ExpectedRange::Usize, + &"massive integer".spanned(name.span), + "indexing", + ) + })?; + + match get_data_by_index(value, index.spanned(value.tag.span)) { + Some(v) => Ok(v.clone()), + None => Err(ShellError::range_error( + 0..(l.len()), + &int.spanned(name.span), + "indexing", + )), + } } } } + other => Err(ShellError::type_error( + "row or table", + other.type_name().spanned(value.tag.span), + )), + } +} - None +pub fn get_data_by_column_path( + value: &Value, + path: &ColumnPath, + callback: Box ShellError>, +) -> Result { + let mut current = value.clone(); + + for p in path.iter() { + let value = get_data_by_member(¤t, p); + + match value { + Ok(v) => current = v.clone(), + Err(e) => return Err(callback((¤t.clone(), &p.clone(), e))), + } } - pub fn as_column_path(&self) -> Result, ShellError> { - match &self.value { - UntaggedValue::Table(table) => { - let mut out: Vec = vec![]; + Ok(current) +} - for item in table { - out.push(item.as_path_member()?); +pub fn insert_data_at_path(value: &Value, path: &str, new_value: Value) -> Option { + let mut new_obj = value.clone(); + + let split_path: Vec<_> = path.split(".").collect(); + + if let UntaggedValue::Row(ref mut o) = new_obj.value { + let mut current = o; + + if split_path.len() == 1 { + // Special case for inserting at the top level + current.entries.insert( + path.to_string(), + new_value.value.clone().into_value(&value.tag), + ); + return Some(new_obj); + } + + for idx in 0..split_path.len() { + match current.entries.get_mut(split_path[idx]) { + Some(next) => { + if idx == (split_path.len() - 2) { + match &mut next.value { + UntaggedValue::Row(o) => { + o.entries.insert( + split_path[idx + 1].to_string(), + new_value.value.clone().into_value(&value.tag), + ); + } + _ => {} + } + + return Some(new_obj.clone()); + } else { + match next.value { + UntaggedValue::Row(ref mut o) => { + current = o; + } + _ => return None, + } + } } - - Ok(ColumnPath::new(out).tagged(&self.tag)) + _ => return None, } + } + } - UntaggedValue::Primitive(Primitive::String(s)) => { - Ok(ColumnPath::new(vec![PathMember::string(s, &self.tag.span)]).tagged(&self.tag)) - } + None +} - UntaggedValue::Primitive(Primitive::ColumnPath(path)) => { - Ok(path.clone().tagged(self.tag.clone())) - } - - other => Err(ShellError::type_error( - "column path", - other.type_name().spanned(self.span()), +pub fn insert_data_at_member( + value: &mut Value, + member: &PathMember, + new_value: Value, +) -> Result<(), ShellError> { + match &mut value.value { + UntaggedValue::Row(dict) => match &member.unspanned { + UnspannedPathMember::String(key) => Ok({ + dict.insert_data_at_key(key, new_value); + }), + UnspannedPathMember::Int(_) => Err(ShellError::type_error( + "column name", + "integer".spanned(member.span), )), + }, + UntaggedValue::Table(array) => match &member.unspanned { + UnspannedPathMember::String(_) => Err(ShellError::type_error( + "list index", + "string".spanned(member.span), + )), + UnspannedPathMember::Int(int) => Ok({ + let int = int.to_usize().ok_or_else(|| { + ShellError::range_error( + ExpectedRange::Usize, + &"bigger number".spanned(member.span), + "inserting into a list", + ) + })?; + + insert_data_at_index(array, int.tagged(member.span), new_value.clone())?; + }), + }, + other => match &member.unspanned { + UnspannedPathMember::String(_) => Err(ShellError::type_error( + "row", + other.type_name().spanned(value.span()), + )), + UnspannedPathMember::Int(_) => Err(ShellError::type_error( + "table", + other.type_name().spanned(value.span()), + )), + }, + } +} + +pub fn insert_data_at_column_path( + value: &Value, + split_path: &ColumnPath, + new_value: Value, +) -> Result { + let (last, front) = split_path.split_last(); + let mut original = value.clone(); + + let mut current: &mut Value = &mut original; + + for member in front { + let type_name = current.spanned_type_name(); + + current = get_mut_data_by_member(current, &member).ok_or_else(|| { + ShellError::missing_property( + member.plain_string(std::usize::MAX).spanned(member.span), + type_name, + ) + })? + } + + insert_data_at_member(current, &last, new_value)?; + + Ok(original) +} + +pub fn replace_data_at_column_path( + value: &Value, + split_path: &ColumnPath, + replaced_value: Value, +) -> Option { + let mut new_obj: Value = value.clone(); + let mut current = &mut new_obj; + let split_path = split_path.members(); + + for idx in 0..split_path.len() { + match get_mut_data_by_member(current, &split_path[idx]) { + Some(next) => { + if idx == (split_path.len() - 1) { + *next = replaced_value.value.into_value(&value.tag); + return Some(new_obj); + } else { + current = next; + } + } + None => { + return None; + } } } - pub fn as_path_member(&self) -> Result { - match &self.value { - UntaggedValue::Primitive(primitive) => match primitive { - Primitive::Int(int) => Ok(PathMember::int(int.clone(), self.tag.span)), - Primitive::String(string) => Ok(PathMember::string(string, self.tag.span)), - other => Err(ShellError::type_error( - "path member", - other.type_name().spanned(self.span()), - )), - }, + None +} + +pub fn as_column_path(value: &Value) -> Result, ShellError> { + match &value.value { + UntaggedValue::Table(table) => { + let mut out: Vec = vec![]; + + for item in table { + out.push(as_path_member(item)?); + } + + Ok(ColumnPath::new(out).tagged(&value.tag)) + } + + UntaggedValue::Primitive(Primitive::String(s)) => { + Ok(ColumnPath::new(vec![PathMember::string(s, &value.tag.span)]).tagged(&value.tag)) + } + + UntaggedValue::Primitive(Primitive::ColumnPath(path)) => { + Ok(path.clone().tagged(value.tag.clone())) + } + + other => Err(ShellError::type_error( + "column path", + other.type_name().spanned(value.span()), + )), + } +} + +pub fn as_path_member(value: &Value) -> Result { + match &value.value { + UntaggedValue::Primitive(primitive) => match primitive { + Primitive::Int(int) => Ok(PathMember::int(int.clone(), value.tag.span)), + Primitive::String(string) => Ok(PathMember::string(string, value.tag.span)), other => Err(ShellError::type_error( "path member", - other.type_name().spanned(self.span()), + other.type_name().spanned(value.span()), )), - } + }, + other => Err(ShellError::type_error( + "path member", + other.type_name().spanned(value.span()), + )), } +} - pub fn as_string(&self) -> Result { - match &self.value { - UntaggedValue::Primitive(Primitive::String(s)) => Ok(s.clone()), - UntaggedValue::Primitive(Primitive::Boolean(x)) => Ok(format!("{}", x)), - UntaggedValue::Primitive(Primitive::Decimal(x)) => Ok(format!("{}", x)), - UntaggedValue::Primitive(Primitive::Int(x)) => Ok(format!("{}", x)), - UntaggedValue::Primitive(Primitive::Bytes(x)) => Ok(format!("{}", x)), - UntaggedValue::Primitive(Primitive::Path(x)) => Ok(format!("{}", x.display())), - UntaggedValue::Primitive(Primitive::ColumnPath(path)) => { - Ok(path.iter().map(|member| member.display()).join(".")) - } - // TODO: this should definitely be more general with better errors - other => Err(ShellError::labeled_error( - "Expected string", - other.type_name(), - &self.tag, - )), +pub fn as_string(value: &Value) -> Result { + match &value.value { + UntaggedValue::Primitive(Primitive::String(s)) => Ok(s.clone()), + UntaggedValue::Primitive(Primitive::Boolean(x)) => Ok(format!("{}", x)), + UntaggedValue::Primitive(Primitive::Decimal(x)) => Ok(format!("{}", x)), + UntaggedValue::Primitive(Primitive::Int(x)) => Ok(format!("{}", x)), + UntaggedValue::Primitive(Primitive::Bytes(x)) => Ok(format!("{}", x)), + UntaggedValue::Primitive(Primitive::Path(x)) => Ok(format!("{}", x.display())), + UntaggedValue::Primitive(Primitive::ColumnPath(path)) => { + Ok(path.iter().map(|member| member.display()).join(".")) } + + // TODO: this should definitely be more general with better errors + other => Err(ShellError::labeled_error( + "Expected string", + other.type_name(), + &value.tag, + )), } } @@ -333,88 +431,89 @@ fn insert_data_at_index( } } -impl Value { - pub fn get_data(&self, desc: &String) -> MaybeOwned<'_, Value> { - match &self.value { - UntaggedValue::Primitive(_) => MaybeOwned::Borrowed(self), - UntaggedValue::Row(o) => o.get_data(desc), - UntaggedValue::Block(_) | UntaggedValue::Table(_) | UntaggedValue::Error(_) => { - MaybeOwned::Owned(UntaggedValue::nothing().into_untagged_value()) - } +pub fn get_data<'value>(value: &'value Value, desc: &String) -> MaybeOwned<'value, Value> { + match &value.value { + UntaggedValue::Primitive(_) => MaybeOwned::Borrowed(value), + UntaggedValue::Row(o) => o.get_data(desc), + UntaggedValue::Block(_) | UntaggedValue::Table(_) | UntaggedValue::Error(_) => { + MaybeOwned::Owned(value::nothing().into_untagged_value()) } } +} - pub(crate) fn get_data_by_index(&self, idx: Spanned) -> Option { - match &self.value { - UntaggedValue::Table(value_set) => { - let value = value_set.get(idx.item)?; - Some( - value - .value - .clone() - .into_value(Tag::new(value.anchor(), idx.span)), - ) - } - _ => None, +pub(crate) fn get_data_by_index(value: &Value, idx: Spanned) -> Option { + match &value.value { + UntaggedValue::Table(value_set) => { + let value = value_set.get(idx.item)?; + Some( + value + .value + .clone() + .into_value(Tag::new(value.anchor(), idx.span)), + ) } + _ => None, } +} - pub(crate) fn get_data_by_key(&self, name: Spanned<&str>) -> Option { - match &self.value { - UntaggedValue::Row(o) => o.get_data_by_key(name), - UntaggedValue::Table(l) => { - let mut out = vec![]; +pub(crate) fn get_data_by_key(value: &Value, name: Spanned<&str>) -> Option { + match &value.value { + UntaggedValue::Row(o) => o.get_data_by_key(name), + UntaggedValue::Table(l) => { + let mut out = vec![]; + for item in l { + match item { + Value { + value: UntaggedValue::Row(o), + .. + } => match o.get_data_by_key(name) { + Some(v) => out.push(v), + None => out.push(value::nothing().into_untagged_value()), + }, + _ => out.push(value::nothing().into_untagged_value()), + } + } + + if out.len() > 0 { + Some(UntaggedValue::Table(out).into_value(name.span)) + } else { + None + } + } + _ => None, + } +} + +pub(crate) fn get_mut_data_by_member<'value>( + value: &'value mut Value, + name: &PathMember, +) -> Option<&'value mut Value> { + match &mut value.value { + UntaggedValue::Row(o) => match &name.unspanned { + UnspannedPathMember::String(string) => o.get_mut_data_by_key(&string), + UnspannedPathMember::Int(_) => None, + }, + UntaggedValue::Table(l) => match &name.unspanned { + UnspannedPathMember::String(string) => { for item in l { match item { Value { value: UntaggedValue::Row(o), .. - } => match o.get_data_by_key(name) { - Some(v) => out.push(v), - None => out.push(UntaggedValue::nothing().into_untagged_value()), + } => match o.get_mut_data_by_key(&string) { + Some(v) => return Some(v), + None => {} }, - _ => out.push(UntaggedValue::nothing().into_untagged_value()), + _ => {} } } - - if out.len() > 0 { - Some(UntaggedValue::Table(out).into_value(name.span)) - } else { - None - } + None } - _ => None, - } - } - - pub(crate) fn get_mut_data_by_member(&mut self, name: &PathMember) -> Option<&mut Value> { - match &mut self.value { - UntaggedValue::Row(o) => match &name.unspanned { - UnspannedPathMember::String(string) => o.get_mut_data_by_key(&string), - UnspannedPathMember::Int(_) => None, - }, - UntaggedValue::Table(l) => match &name.unspanned { - UnspannedPathMember::String(string) => { - for item in l { - match item { - Value { - value: UntaggedValue::Row(o), - .. - } => match o.get_mut_data_by_key(&string) { - Some(v) => return Some(v), - None => {} - }, - _ => {} - } - } - None - } - UnspannedPathMember::Int(int) => { - let index = int.to_usize()?; - l.get_mut(index) - } - }, - _ => None, - } + UnspannedPathMember::Int(int) => { + let index = int.to_usize()?; + l.get_mut(index) + } + }, + _ => None, } } diff --git a/src/data/base/shape.rs b/src/data/base/shape.rs index 11044720f1..0cb086a434 100644 --- a/src/data/base/shape.rs +++ b/src/data/base/shape.rs @@ -1,12 +1,14 @@ -use crate::data::base::{Block, ColumnPath}; -use crate::data::dict::Dictionary; +use crate::data::primitive::format_primitive; use crate::prelude::*; use chrono::{DateTime, Utc}; use chrono_humanize::Humanize; use derive_new::new; use indexmap::IndexMap; -use nu_source::DebugDoc; -use nu_source::{b, PrettyDebug}; +use nu_errors::ShellError; +use nu_protocol::{ + ColumnPath, Dictionary, Evaluate, Primitive, ShellTypeName, UntaggedValue, Value, +}; +use nu_source::{b, DebugDoc, PrettyDebug}; use std::collections::BTreeMap; use std::fmt::Debug; use std::hash::Hash; @@ -339,7 +341,7 @@ impl PrettyDebug for FormatInlineShape { }), InlineShape::Date(date) => b::primitive(date.humanize()), InlineShape::Duration(duration) => { - b::description(Primitive::Duration(*duration).format(None)) + b::description(format_primitive(&Primitive::Duration(*duration), None)) } InlineShape::Path(path) => b::primitive(path.display()), InlineShape::Binary => b::opaque(""), @@ -475,13 +477,7 @@ pub enum Shape { Row(Vec), Table { from: usize, to: usize }, Error(ShellError), - Block(Block), -} - -impl Value { - pub fn shape(&self) -> Shape { - Shape::for_value(self) - } + Block(Evaluate), } impl Shape { @@ -502,32 +498,6 @@ impl Shape { Shape::Row(dict.keys().map(|key| Column::String(key.clone())).collect()) } - pub fn kind(&self) -> String { - match self { - Shape::Primitive(primitive) => primitive, - Shape::Row(row) => { - return row - .iter() - .map(|c| match c { - Column::String(s) => s.clone(), - Column::Value => format!(""), - }) - .join(", ") - } - Shape::Table { .. } => "table", - Shape::Error(_) => "error", - Shape::Block(_) => "block", - } - .to_string() - } - - pub fn describe_str(&self) -> String { - let mut v = vec![]; - self.describe(&mut v) - .expect("it isn't possible to fail to write into a memory buffer"); - String::from_utf8_lossy(&v[..]).to_string() - } - pub fn describe(&self, w: &mut impl Write) -> Result<(), std::io::Error> { match self { Shape::Primitive(desc) => write!(w, "[{}]", desc), @@ -559,7 +529,7 @@ impl Shape { .expect("Writing into a Vec can't fail"); let string = String::from_utf8_lossy(&out); - UntaggedValue::string(string).into_untagged_value() + value::string(string).into_untagged_value() } } @@ -589,7 +559,7 @@ impl Shapes { vec![dict! { "type" => shape.to_value(), - "rows" => UntaggedValue::string("all") + "rows" => value::string("all") }] } else { self.shapes @@ -599,7 +569,7 @@ impl Shapes { dict! { "type" => shape.to_value(), - "rows" => UntaggedValue::string(format!("[ {} ]", rows)) + "rows" => value::string(format!("[ {} ]", rows)) } }) .collect() diff --git a/src/data/command.rs b/src/data/command.rs index d47bc26e4c..3eb504a422 100644 --- a/src/data/command.rs +++ b/src/data/command.rs @@ -1,7 +1,7 @@ use crate::commands::command::Command; -use crate::data::{TaggedDictBuilder, TaggedListBuilder, Value}; -use crate::parser::registry::{NamedType, PositionalType, Signature}; +use crate::data::{TaggedDictBuilder, TaggedListBuilder}; use crate::prelude::*; +use nu_protocol::{NamedType, PositionalType, Signature, Value}; use std::ops::Deref; pub(crate) fn command_dict(command: Arc, tag: impl Into) -> Value { @@ -9,18 +9,18 @@ pub(crate) fn command_dict(command: Arc, tag: impl Into) -> Value let mut cmd_dict = TaggedDictBuilder::new(&tag); - cmd_dict.insert_untagged("name", UntaggedValue::string(command.name())); + cmd_dict.insert_untagged("name", value::string(command.name())); cmd_dict.insert_untagged( "type", - UntaggedValue::string(match command.deref() { + value::string(match command.deref() { Command::WholeStream(_) => "Command", Command::PerItem(_) => "Filter", }), ); cmd_dict.insert_value("signature", signature_dict(command.signature(), tag)); - cmd_dict.insert_untagged("usage", UntaggedValue::string(command.usage())); + cmd_dict.insert_untagged("usage", value::string(command.usage())); cmd_dict.into_value() } @@ -30,11 +30,11 @@ fn for_spec(name: &str, ty: &str, required: bool, tag: impl Into) -> Value let mut spec = TaggedDictBuilder::new(tag); - spec.insert_untagged("name", UntaggedValue::string(name)); - spec.insert_untagged("type", UntaggedValue::string(ty)); + spec.insert_untagged("name", value::string(name)); + spec.insert_untagged("type", value::string(ty)); spec.insert_untagged( "required", - UntaggedValue::string(if required { "yes" } else { "no" }), + value::string(if required { "yes" } else { "no" }), ); spec.into_value() diff --git a/src/data/config.rs b/src/data/config.rs index 8f74e7ff21..9e0bdfcbea 100644 --- a/src/data/config.rs +++ b/src/data/config.rs @@ -1,11 +1,11 @@ use crate::commands::from_toml::convert_toml_value_to_nu_value; use crate::commands::to_toml::value_to_toml_value; -use crate::data::{Dictionary, Value}; -use crate::errors::ShellError; use crate::prelude::*; use app_dirs::*; use indexmap::IndexMap; use log::trace; +use nu_errors::ShellError; +use nu_protocol::{Dictionary, ShellTypeName, UntaggedValue, Value}; use serde::{Deserialize, Serialize}; use std::fs::{self, OpenOptions}; use std::io; diff --git a/src/data/dict.rs b/src/data/dict.rs index 5f48a9a4b7..bbdcf5bd19 100644 --- a/src/data/dict.rs +++ b/src/data/dict.rs @@ -1,19 +1,8 @@ -use crate::data::base::{Primitive, UntaggedValue, Value}; use crate::prelude::*; use derive_new::new; -use getset::Getters; use indexmap::IndexMap; -use nu_source::Spanned; -use nu_source::{b, PrettyDebug}; -use pretty::{BoxAllocator, DocAllocator}; -use serde::{Deserialize, Serialize}; -use std::cmp::{Ordering, PartialOrd}; - -#[derive(Debug, Default, Eq, PartialEq, Serialize, Deserialize, Clone, Getters, new)] -pub struct Dictionary { - #[get = "pub"] - pub entries: IndexMap, -} +use nu_protocol::{Dictionary, Primitive, UntaggedValue, Value}; +use nu_source::{b, PrettyDebug, Spanned}; #[derive(Debug, new)] struct DebugEntry<'a> { @@ -27,87 +16,17 @@ impl<'a> PrettyDebug for DebugEntry<'a> { } } -impl PrettyDebug for Dictionary { - fn pretty(&self) -> DebugDocBuilder { - BoxAllocator - .text("(") - .append( - BoxAllocator - .intersperse( - self.entries() - .iter() - .map(|(key, value)| DebugEntry::new(key, value).to_doc()), - BoxAllocator.space(), - ) - .nest(1) - .group(), - ) - .append(BoxAllocator.text(")")) - .into() - } +pub trait DictionaryExt { + fn get_data(&self, desc: &String) -> MaybeOwned<'_, Value>; + + fn keys(&self) -> indexmap::map::Keys; + fn get_data_by_key(&self, name: Spanned<&str>) -> Option; + fn get_mut_data_by_key(&mut self, name: &str) -> Option<&mut Value>; + fn insert_data_at_key(&mut self, name: &str, value: Value); } -impl PartialOrd for Dictionary { - fn partial_cmp(&self, other: &Dictionary) -> Option { - let this: Vec<&String> = self.entries.keys().collect(); - let that: Vec<&String> = other.entries.keys().collect(); - - if this != that { - return this.partial_cmp(&that); - } - - let this: Vec<&Value> = self.entries.values().collect(); - let that: Vec<&Value> = self.entries.values().collect(); - - this.partial_cmp(&that) - } -} - -impl From> for Dictionary { - fn from(input: IndexMap) -> Dictionary { - let mut out = IndexMap::default(); - - for (key, value) in input { - out.insert(key, value); - } - - Dictionary::new(out) - } -} - -impl Ord for Dictionary { - fn cmp(&self, other: &Dictionary) -> Ordering { - let this: Vec<&String> = self.entries.keys().collect(); - let that: Vec<&String> = other.entries.keys().collect(); - - if this != that { - return this.cmp(&that); - } - - let this: Vec<&Value> = self.entries.values().collect(); - let that: Vec<&Value> = self.entries.values().collect(); - - this.cmp(&that) - } -} - -impl PartialOrd for Dictionary { - fn partial_cmp(&self, _other: &Value) -> Option { - Some(Ordering::Less) - } -} - -impl PartialEq for Dictionary { - fn eq(&self, other: &Value) -> bool { - match &other.value { - UntaggedValue::Row(d) => self == d, - _ => false, - } - } -} - -impl Dictionary { - pub fn get_data(&self, desc: &String) -> MaybeOwned<'_, Value> { +impl DictionaryExt for Dictionary { + fn get_data(&self, desc: &String) -> MaybeOwned<'_, Value> { match self.entries.get(desc) { Some(v) => MaybeOwned::Borrowed(v), None => MaybeOwned::Owned( @@ -116,11 +35,11 @@ impl Dictionary { } } - pub fn keys(&self) -> impl Iterator { + fn keys(&self) -> indexmap::map::Keys { self.entries.keys() } - pub(crate) fn get_data_by_key(&self, name: Spanned<&str>) -> Option { + fn get_data_by_key(&self, name: Spanned<&str>) -> Option { let result = self .entries .iter() @@ -135,7 +54,7 @@ impl Dictionary { ) } - pub(crate) fn get_mut_data_by_key(&mut self, name: &str) -> Option<&mut Value> { + fn get_mut_data_by_key(&mut self, name: &str) -> Option<&mut Value> { match self .entries .iter_mut() @@ -146,7 +65,7 @@ impl Dictionary { } } - pub(crate) fn insert_data_at_key(&mut self, name: &str, value: Value) { + fn insert_data_at_key(&mut self, name: &str, value: Value) { self.entries.insert(name.to_string(), value); } } diff --git a/src/data/files.rs b/src/data/files.rs index 3a2a99ee31..aec410e0e5 100644 --- a/src/data/files.rs +++ b/src/data/files.rs @@ -1,6 +1,7 @@ -use crate::data::{TaggedDictBuilder, Value}; -use crate::errors::ShellError; +use crate::data::TaggedDictBuilder; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::Value; #[derive(Debug)] pub enum FileType { @@ -16,7 +17,7 @@ pub(crate) fn dir_entry_dict( full: bool, ) -> Result { let mut dict = TaggedDictBuilder::new(tag); - dict.insert_untagged("name", UntaggedValue::string(filename.to_string_lossy())); + dict.insert_untagged("name", value::string(filename.to_string_lossy())); let kind = if metadata.is_dir() { FileType::Directory @@ -26,39 +27,36 @@ pub(crate) fn dir_entry_dict( FileType::Symlink }; - dict.insert_untagged("type", UntaggedValue::string(format!("{:?}", kind))); + dict.insert_untagged("type", value::string(format!("{:?}", kind))); if full { dict.insert_untagged( "readonly", - UntaggedValue::boolean(metadata.permissions().readonly()), + value::boolean(metadata.permissions().readonly()), ); #[cfg(unix)] { use std::os::unix::fs::PermissionsExt; let mode = metadata.permissions().mode(); - dict.insert_untagged( - "mode", - UntaggedValue::string(umask::Mode::from(mode).to_string()), - ); + dict.insert_untagged("mode", value::string(umask::Mode::from(mode).to_string())); } } - dict.insert_untagged("size", UntaggedValue::bytes(metadata.len() as u64)); + dict.insert_untagged("size", value::bytes(metadata.len() as u64)); match metadata.created() { - Ok(c) => dict.insert_untagged("created", UntaggedValue::system_date(c)), + Ok(c) => dict.insert_untagged("created", value::system_date(c)), Err(_) => {} } match metadata.accessed() { - Ok(a) => dict.insert_untagged("accessed", UntaggedValue::system_date(a)), + Ok(a) => dict.insert_untagged("accessed", value::system_date(a)), Err(_) => {} } match metadata.modified() { - Ok(m) => dict.insert_untagged("modified", UntaggedValue::system_date(m)), + Ok(m) => dict.insert_untagged("modified", value::system_date(m)), Err(_) => {} } diff --git a/src/data/into.rs b/src/data/into.rs deleted file mode 100644 index 1fe6c52cfd..0000000000 --- a/src/data/into.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::data::base::{Primitive, UntaggedValue}; - -impl From for UntaggedValue { - fn from(input: Primitive) -> UntaggedValue { - UntaggedValue::Primitive(input) - } -} - -impl From for UntaggedValue { - fn from(input: String) -> UntaggedValue { - UntaggedValue::Primitive(Primitive::String(input)) - } -} diff --git a/src/data/primitive.rs b/src/data/primitive.rs new file mode 100644 index 0000000000..2123e9e946 --- /dev/null +++ b/src/data/primitive.rs @@ -0,0 +1,91 @@ +use chrono_humanize::Humanize; +use nu_parser::Number; +use nu_protocol::Primitive; +use nu_source::PrettyDebug; + +pub fn number(number: impl Into) -> Primitive { + let number = number.into(); + + match number { + Number::Int(int) => Primitive::Int(int), + Number::Decimal(decimal) => Primitive::Decimal(decimal), + } +} + +pub fn format_primitive(primitive: &Primitive, field_name: Option<&String>) -> String { + match primitive { + Primitive::Nothing => String::new(), + Primitive::BeginningOfStream => String::new(), + Primitive::EndOfStream => String::new(), + Primitive::Path(p) => format!("{}", p.display()), + Primitive::Bytes(b) => { + let byte = byte_unit::Byte::from_bytes(*b as u128); + + if byte.get_bytes() == 0u128 { + return "—".to_string(); + } + + let byte = byte.get_appropriate_unit(false); + + match byte.get_unit() { + byte_unit::ByteUnit::B => format!("{} B ", byte.get_value()), + _ => format!("{}", byte.format(1)), + } + } + Primitive::Duration(sec) => format_duration(*sec), + Primitive::Int(i) => format!("{}", i), + Primitive::Decimal(decimal) => format!("{}", decimal), + Primitive::Pattern(s) => format!("{}", s), + Primitive::String(s) => format!("{}", s), + Primitive::ColumnPath(p) => { + let mut members = p.iter(); + let mut f = String::new(); + + f.push_str( + &members + .next() + .expect("BUG: column path with zero members") + .display(), + ); + + for member in members { + f.push_str("."); + f.push_str(&member.display()) + } + + f + } + Primitive::Boolean(b) => match (b, field_name) { + (true, None) => format!("Yes"), + (false, None) => format!("No"), + (true, Some(s)) if !s.is_empty() => format!("{}", s), + (false, Some(s)) if !s.is_empty() => format!(""), + (true, Some(_)) => format!("Yes"), + (false, Some(_)) => format!("No"), + }, + Primitive::Binary(_) => format!(""), + Primitive::Date(d) => format!("{}", d.humanize()), + } +} + +pub fn style_primitive(primitive: &Primitive) -> &'static str { + match primitive { + Primitive::Bytes(0) => "c", // centre 'missing' indicator + Primitive::Int(_) | Primitive::Bytes(_) | Primitive::Decimal(_) => "r", + _ => "", + } +} + +fn format_duration(sec: u64) -> String { + let (minutes, seconds) = (sec / 60, sec % 60); + let (hours, minutes) = (minutes / 60, minutes % 60); + let (days, hours) = (hours / 24, hours % 24); + + match (days, hours, minutes, seconds) { + (0, 0, 0, 1) => format!("1 sec"), + (0, 0, 0, s) => format!("{} secs", s), + (0, 0, m, s) => format!("{}:{:02}", m, s), + (0, h, m, s) => format!("{}:{:02}:{:02}", h, m, s), + (d, h, m, s) => format!("{}:{:02}:{:02}:{:02}", d, h, m, s), + } +} diff --git a/src/data/process.rs b/src/data/process.rs index 0e166d2f90..8772beba44 100644 --- a/src/data/process.rs +++ b/src/data/process.rs @@ -9,18 +9,18 @@ pub(crate) fn process_dict(proc: &sysinfo::Process, tag: impl Into) -> Valu let cmd = proc.cmd(); let cmd_value = if cmd.len() == 0 { - UntaggedValue::nothing() + value::nothing() } else { - UntaggedValue::string(join(cmd, "")) + value::string(join(cmd, "")) }; - dict.insert("pid", UntaggedValue::int(proc.pid() as i64)); - dict.insert("status", UntaggedValue::string(proc.status().to_string())); - dict.insert("cpu", UntaggedValue::number(proc.cpu_usage())); + dict.insert("pid", value::int(proc.pid() as i64)); + dict.insert("status", value::string(proc.status().to_string())); + dict.insert("cpu", value::number(proc.cpu_usage())); match cmd_value { UntaggedValue::Primitive(Primitive::Nothing) => { - dict.insert("name", UntaggedValue::string(proc.name())); + dict.insert("name", value::string(proc.name())); } _ => dict.insert("name", cmd_value), } diff --git a/src/data/types.rs b/src/data/types.rs index ce5684d4eb..d140f31e22 100644 --- a/src/data/types.rs +++ b/src/data/types.rs @@ -1,5 +1,7 @@ use crate::prelude::*; use log::trace; +use nu_errors::{CoerceInto, ShellError}; +use nu_protocol::{Primitive, SpannedTypeName, UntaggedValue, Value}; use nu_source::Tagged; pub trait ExtractType: Sized { @@ -28,10 +30,7 @@ impl ExtractType for bool { value: UntaggedValue::Primitive(Primitive::Nothing), .. } => Ok(false), - other => Err(ShellError::type_error( - "Boolean", - other.type_name().spanned(other.span()), - )), + other => Err(ShellError::type_error("Boolean", other.spanned_type_name())), } } } @@ -45,10 +44,7 @@ impl ExtractType for std::path::PathBuf { value: UntaggedValue::Primitive(Primitive::Path(p)), .. } => Ok(p.clone()), - other => Err(ShellError::type_error( - "Path", - other.type_name().spanned(other.span()), - )), + other => Err(ShellError::type_error("Path", other.spanned_type_name())), } } } @@ -62,10 +58,7 @@ impl ExtractType for i64 { value: UntaggedValue::Primitive(Primitive::Int(int)), .. } => Ok(int.tagged(&value.tag).coerce_into("converting to i64")?), - other => Err(ShellError::type_error( - "Integer", - other.type_name().spanned(other.span()), - )), + other => Err(ShellError::type_error("Integer", other.spanned_type_name())), } } } @@ -79,10 +72,7 @@ impl ExtractType for u64 { value: UntaggedValue::Primitive(Primitive::Int(int)), .. } => Ok(int.tagged(&value.tag).coerce_into("converting to u64")?), - other => Err(ShellError::type_error( - "Integer", - other.type_name().spanned(other.span()), - )), + other => Err(ShellError::type_error("Integer", other.spanned_type_name())), } } } @@ -96,10 +86,7 @@ impl ExtractType for String { value: UntaggedValue::Primitive(Primitive::String(string)), .. } => Ok(string.clone()), - other => Err(ShellError::type_error( - "String", - other.type_name().spanned(other.span()), - )), + other => Err(ShellError::type_error("String", other.spanned_type_name())), } } } diff --git a/src/data/value.rs b/src/data/value.rs new file mode 100644 index 0000000000..5088c6621b --- /dev/null +++ b/src/data/value.rs @@ -0,0 +1,152 @@ +use crate::data::base::coerce_compare; +use crate::data::base::shape::{Column, InlineShape, TypeShape}; +use crate::data::primitive::style_primitive; +use crate::data::value; +use bigdecimal::BigDecimal; +use chrono::DateTime; +use indexmap::IndexMap; +use nu_errors::ShellError; +use nu_parser::Number; +use nu_parser::Operator; +use nu_protocol::{ColumnPath, PathMember, Primitive, UntaggedValue, Value}; +use nu_source::{DebugDocBuilder, PrettyDebug, Tagged}; +use num_bigint::BigInt; +use std::path::PathBuf; +use std::time::SystemTime; + +#[allow(unused)] +pub fn row(entries: IndexMap) -> UntaggedValue { + UntaggedValue::Row(entries.into()) +} + +pub fn table(list: &Vec) -> UntaggedValue { + UntaggedValue::Table(list.to_vec()) +} + +pub fn string(s: impl Into) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::String(s.into())) +} + +pub fn column_path(s: Vec>) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::ColumnPath(ColumnPath::new( + s.into_iter().map(|p| p.into()).collect(), + ))) +} + +pub fn int(i: impl Into) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::Int(i.into())) +} + +pub fn pattern(s: impl Into) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::String(s.into())) +} + +pub fn path(s: impl Into) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::Path(s.into())) +} + +pub fn bytes(s: impl Into) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::Bytes(s.into())) +} + +pub fn decimal(s: impl Into) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::Decimal(s.into())) +} + +pub fn binary(binary: Vec) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::Binary(binary)) +} + +pub fn number(s: impl Into) -> UntaggedValue { + let num = s.into(); + + match num { + Number::Int(int) => value::int(int), + Number::Decimal(decimal) => value::decimal(decimal), + } +} + +pub fn boolean(s: impl Into) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::Boolean(s.into())) +} + +pub fn duration(secs: u64) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::Duration(secs)) +} + +pub fn system_date(s: SystemTime) -> UntaggedValue { + UntaggedValue::Primitive(Primitive::Date(s.into())) +} + +pub fn date_from_str(s: Tagged<&str>) -> Result { + let date = DateTime::parse_from_rfc3339(s.item).map_err(|err| { + ShellError::labeled_error( + &format!("Date parse error: {}", err), + "original value", + s.tag, + ) + })?; + + let date = date.with_timezone(&chrono::offset::Utc); + + Ok(UntaggedValue::Primitive(Primitive::Date(date))) +} + +pub fn nothing() -> UntaggedValue { + UntaggedValue::Primitive(Primitive::Nothing) +} + +pub fn compare_values( + operator: &Operator, + left: &UntaggedValue, + right: &UntaggedValue, +) -> Result { + match operator { + _ => { + let coerced = coerce_compare(left, right)?; + let ordering = coerced.compare(); + + use std::cmp::Ordering; + + let result = match (operator, ordering) { + (Operator::Equal, Ordering::Equal) => true, + (Operator::NotEqual, Ordering::Less) | (Operator::NotEqual, Ordering::Greater) => { + true + } + (Operator::LessThan, Ordering::Less) => true, + (Operator::GreaterThan, Ordering::Greater) => true, + (Operator::GreaterThanOrEqual, Ordering::Greater) + | (Operator::GreaterThanOrEqual, Ordering::Equal) => true, + (Operator::LessThanOrEqual, Ordering::Less) + | (Operator::LessThanOrEqual, Ordering::Equal) => true, + _ => false, + }; + + Ok(result) + } + } +} + +pub fn format_type<'a>(value: impl Into<&'a UntaggedValue>, width: usize) -> String { + TypeShape::from_value(value.into()).colored_string(width) +} + +pub fn format_leaf<'a>(value: impl Into<&'a UntaggedValue>) -> DebugDocBuilder { + InlineShape::from_value(value.into()).format().pretty() +} + +pub fn style_leaf<'a>(value: impl Into<&'a UntaggedValue>) -> &'static str { + match value.into() { + UntaggedValue::Primitive(p) => style_primitive(p), + _ => "", + } +} + +pub fn format_for_column<'a>( + value: impl Into<&'a UntaggedValue>, + column: impl Into, +) -> DebugDocBuilder { + InlineShape::from_value(value.into()) + .format_for_column(column) + .pretty() +} diff --git a/src/parser/deserializer.rs b/src/deserializer.rs similarity index 97% rename from src/parser/deserializer.rs rename to src/deserializer.rs index 5121e08d70..12db815e12 100644 --- a/src/parser/deserializer.rs +++ b/src/deserializer.rs @@ -1,8 +1,9 @@ -use crate::data::base::Block; -use crate::prelude::*; -use crate::ColumnPath; +use crate::data::base::property_get::ValueExt; +use crate::data::value; use log::trace; -use nu_source::Tagged; +use nu_errors::{CoerceInto, ShellError}; +use nu_protocol::{CallInfo, ColumnPath, Evaluate, Primitive, ShellTypeName, UntaggedValue, Value}; +use nu_source::{HasSpan, SpannedItem, Tagged, TaggedItem}; use serde::de; use std::path::PathBuf; @@ -55,7 +56,7 @@ impl<'de> ConfigDeserializer<'de> { self.stack.push(DeserializerItem { key_struct_field: Some((name.to_string(), name)), - val: value.unwrap_or_else(|| UntaggedValue::nothing().into_value(&self.call.name_tag)), + val: value.unwrap_or_else(|| value::nothing().into_value(&self.call.name_tag)), }); Ok(()) @@ -348,7 +349,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut ConfigDeserializer<'de> { return visit::(value.val, name, fields, visitor); } - if name == "Block" { + if name == "Evaluate" { let block = match value.val { Value { value: UntaggedValue::Block(block), @@ -361,7 +362,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut ConfigDeserializer<'de> { )) } }; - return visit::(block, name, fields, visitor); + return visit::(block, name, fields, visitor); } if name == "ColumnPath" { diff --git a/src/env/host.rs b/src/env/host.rs index bd3bd17d53..b8fd61d26b 100644 --- a/src/env/host.rs +++ b/src/env/host.rs @@ -1,5 +1,6 @@ use crate::prelude::*; use language_reporting::termcolor; +use nu_errors::ShellError; use std::fmt::Debug; pub trait Host: Debug + Send { diff --git a/src/evaluate/evaluate_args.rs b/src/evaluate/evaluate_args.rs new file mode 100644 index 0000000000..0ba59d5bd0 --- /dev/null +++ b/src/evaluate/evaluate_args.rs @@ -0,0 +1,58 @@ +// TODO: Temporary redirect +use crate::context::CommandRegistry; +use crate::data::value; +use crate::evaluate::evaluate_baseline_expr; +use indexmap::IndexMap; +use nu_errors::ShellError; +use nu_parser::hir; +use nu_protocol::{EvaluatedArgs, Scope, Value}; +use nu_source::Text; + +pub(crate) fn evaluate_args( + call: &hir::Call, + registry: &CommandRegistry, + scope: &Scope, + source: &Text, +) -> Result { + let positional: Result>, _> = call + .positional + .as_ref() + .map(|p| { + p.iter() + .map(|e| evaluate_baseline_expr(e, registry, scope, source)) + .collect() + }) + .transpose(); + + let positional = positional?; + + let named: Result>, ShellError> = call + .named + .as_ref() + .map(|n| { + let mut results = IndexMap::new(); + + for (name, value) in n.named.iter() { + match value { + hir::NamedValue::PresentSwitch(tag) => { + results.insert(name.clone(), value::boolean(true).into_value(tag)); + } + hir::NamedValue::Value(expr) => { + results.insert( + name.clone(), + evaluate_baseline_expr(expr, registry, scope, source)?, + ); + } + + _ => {} + }; + } + + Ok(results) + }) + .transpose(); + + let named = named?; + + Ok(EvaluatedArgs::new(positional, named)) +} diff --git a/src/evaluate/evaluator.rs b/src/evaluate/evaluator.rs index 3700ce50f3..4a3d3a1ccb 100644 --- a/src/evaluate/evaluator.rs +++ b/src/evaluate/evaluator.rs @@ -1,48 +1,17 @@ +use crate::context::CommandRegistry; use crate::data::base::Block; -use crate::errors::ArgumentError; +use crate::data::value; use crate::evaluate::operator::apply_operator; -use crate::parser::hir::path::{ColumnPath, UnspannedPathMember}; -use crate::parser::{ - hir::{self, Expression, RawExpression}, - CommandRegistry, -}; use crate::prelude::*; use crate::TaggedDictBuilder; -use indexmap::IndexMap; use log::trace; +use nu_errors::{ArgumentError, ShellError}; +use nu_parser::hir::{self, Expression, RawExpression}; +use nu_protocol::{ + ColumnPath, Evaluate, Primitive, Scope, UnspannedPathMember, UntaggedValue, Value, +}; use nu_source::Text; -#[derive(Debug)] -pub struct Scope { - it: Value, - vars: IndexMap, -} - -impl Scope { - pub fn new(it: Value) -> Scope { - Scope { - it, - vars: IndexMap::new(), - } - } -} - -impl Scope { - pub(crate) fn empty() -> Scope { - Scope { - it: UntaggedValue::nothing().into_untagged_value(), - vars: IndexMap::new(), - } - } - - pub(crate) fn it_value(value: Value) -> Scope { - Scope { - it: value, - vars: IndexMap::new(), - } - } -} - pub(crate) fn evaluate_baseline_expr( expr: &Expression, registry: &CommandRegistry, @@ -59,9 +28,9 @@ pub(crate) fn evaluate_baseline_expr( "Invalid external word".spanned(tag.span), ArgumentError::InvalidExternalWord, )), - RawExpression::FilePath(path) => Ok(UntaggedValue::path(path.clone()).into_value(tag)), + RawExpression::FilePath(path) => Ok(value::path(path.clone()).into_value(tag)), RawExpression::Synthetic(hir::Synthetic::String(s)) => { - Ok(UntaggedValue::string(s).into_untagged_value()) + Ok(value::string(s).into_untagged_value()) } RawExpression::Variable(var) => evaluate_reference(var, scope, source, tag), RawExpression::Command(_) => evaluate_command(tag, scope, source), @@ -90,12 +59,12 @@ pub(crate) fn evaluate_baseline_expr( Ok(UntaggedValue::Table(exprs).into_value(tag)) } - RawExpression::Block(block) => { - Ok( - UntaggedValue::Block(Block::new(block.clone(), source.clone(), tag.clone())) - .into_value(&tag), - ) - } + RawExpression::Block(block) => Ok(UntaggedValue::Block(Evaluate::new(Block::new( + block.clone(), + source.clone(), + tag.clone(), + ))) + .into_value(&tag)), RawExpression::Path(path) => { let value = evaluate_baseline_expr(path.head(), registry, scope, source)?; let mut item = value; @@ -149,17 +118,11 @@ fn evaluate_literal(literal: &hir::Literal, source: &Text) -> Value { UntaggedValue::Primitive(Primitive::ColumnPath(ColumnPath::new(members))) .into_value(&literal.span) } - hir::RawLiteral::Number(int) => UntaggedValue::number(int.clone()).into_value(literal.span), + hir::RawLiteral::Number(int) => value::number(int.clone()).into_value(literal.span), hir::RawLiteral::Size(int, unit) => unit.compute(&int).into_value(literal.span), - hir::RawLiteral::String(tag) => { - UntaggedValue::string(tag.slice(source)).into_value(literal.span) - } - hir::RawLiteral::GlobPattern(pattern) => { - UntaggedValue::pattern(pattern).into_value(literal.span) - } - hir::RawLiteral::Bare => { - UntaggedValue::string(literal.span.slice(source)).into_value(literal.span) - } + hir::RawLiteral::String(tag) => value::string(tag.slice(source)).into_value(literal.span), + hir::RawLiteral::GlobPattern(pattern) => value::pattern(pattern).into_value(literal.span), + hir::RawLiteral::Bare => value::string(literal.span.slice(source)).into_value(literal.span), } } @@ -177,32 +140,32 @@ fn evaluate_reference( let mut dict = TaggedDictBuilder::new(&tag); for v in std::env::vars() { if v.0 != "PATH" && v.0 != "Path" { - dict.insert_untagged(v.0, UntaggedValue::string(v.1)); + dict.insert_untagged(v.0, value::string(v.1)); } } Ok(dict.into_value()) } x if x == "nu:config" => { let config = crate::data::config::read(tag.clone(), &None)?; - Ok(UntaggedValue::row(config).into_value(tag)) + Ok(value::row(config).into_value(tag)) } x if x == "nu:path" => { let mut table = vec![]; match std::env::var_os("PATH") { Some(paths) => { for path in std::env::split_paths(&paths) { - table.push(UntaggedValue::path(path).into_value(&tag)); + table.push(value::path(path).into_value(&tag)); } } _ => {} } - Ok(UntaggedValue::table(&table).into_value(tag)) + Ok(value::table(&table).into_value(tag)) } x => Ok(scope .vars .get(x) .map(|v| v.clone()) - .unwrap_or_else(|| UntaggedValue::nothing().into_value(tag))), + .unwrap_or_else(|| value::nothing().into_value(tag))), }, } } diff --git a/src/evaluate/mod.rs b/src/evaluate/mod.rs index f8133808e0..a94d84372f 100644 --- a/src/evaluate/mod.rs +++ b/src/evaluate/mod.rs @@ -1,4 +1,5 @@ +pub(crate) mod evaluate_args; pub(crate) mod evaluator; pub(crate) mod operator; -pub(crate) use evaluator::{evaluate_baseline_expr, Scope}; +pub(crate) use evaluator::evaluate_baseline_expr; diff --git a/src/evaluate/operator.rs b/src/evaluate/operator.rs index ba450a5137..2d55bc15ba 100644 --- a/src/evaluate/operator.rs +++ b/src/evaluate/operator.rs @@ -1,6 +1,6 @@ -use crate::data::base::{Primitive, UntaggedValue, Value}; -use crate::parser::Operator; -use crate::traits::ShellTypeName; +use crate::data::value; +use nu_parser::Operator; +use nu_protocol::{Primitive, ShellTypeName, UntaggedValue, Value}; use std::ops::Not; pub fn apply_operator( @@ -14,12 +14,12 @@ pub fn apply_operator( | Operator::LessThan | Operator::GreaterThan | Operator::LessThanOrEqual - | Operator::GreaterThanOrEqual => left.compare(op, right).map(UntaggedValue::boolean), - Operator::Dot => Ok(UntaggedValue::boolean(false)), - Operator::Contains => contains(left, right).map(UntaggedValue::boolean), - Operator::NotContains => contains(left, right) - .map(Not::not) - .map(UntaggedValue::boolean), + | Operator::GreaterThanOrEqual => { + value::compare_values(op, left, right).map(value::boolean) + } + Operator::Dot => Ok(value::boolean(false)), + Operator::Contains => contains(left, right).map(value::boolean), + Operator::NotContains => contains(left, right).map(Not::not).map(value::boolean), } } diff --git a/src/format.rs b/src/format.rs index 6cdd5b256e..bc464a0de6 100644 --- a/src/format.rs +++ b/src/format.rs @@ -4,9 +4,9 @@ pub(crate) mod list; pub(crate) mod table; use crate::prelude::*; +use nu_errors::ShellError; pub(crate) use entries::EntriesView; - pub(crate) use table::TableView; pub(crate) trait RenderView { diff --git a/src/format/entries.rs b/src/format/entries.rs index 7dd891bd97..0584ce4695 100644 --- a/src/format/entries.rs +++ b/src/format/entries.rs @@ -1,5 +1,8 @@ +use crate::data::value; use crate::format::RenderView; use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::Value; use derive_new::new; @@ -21,7 +24,7 @@ impl EntriesView { for desc in descs { let value = value.get_data(&desc); - let formatted_value = value.borrow().format_leaf().plain_string(75); + let formatted_value = value::format_leaf(value.borrow()).plain_string(75); entries.push((desc.clone(), formatted_value)) } diff --git a/src/format/generic.rs b/src/format/generic.rs index 3379325113..f0860c7933 100644 --- a/src/format/generic.rs +++ b/src/format/generic.rs @@ -1,7 +1,10 @@ -use crate::data::Value; +use crate::data::primitive::format_primitive; +use crate::data::value::format_leaf; use crate::format::{EntriesView, RenderView, TableView}; use crate::prelude::*; use derive_new::new; +use nu_errors::ShellError; +use nu_protocol::{UntaggedValue, Value}; // A list is printed one line at a time with an optional separator between groups #[derive(new)] @@ -13,7 +16,7 @@ impl RenderView for GenericView<'_> { fn render_view(&self, host: &mut dyn Host) -> Result<(), ShellError> { let tag = &self.value.tag; match &self.value.value { - UntaggedValue::Primitive(p) => Ok(host.stdout(&p.format(None))), + UntaggedValue::Primitive(p) => Ok(host.stdout(&format_primitive(p, None))), UntaggedValue::Table(l) => { let view = TableView::from_list(l, 0); @@ -31,8 +34,8 @@ impl RenderView for GenericView<'_> { } b @ UntaggedValue::Block(_) => { - let printed = b.format_leaf().plain_string(host.width()); - let view = EntriesView::from_value(&UntaggedValue::string(printed).into_value(tag)); + let printed = format_leaf(b).plain_string(host.width()); + let view = EntriesView::from_value(&value::string(printed).into_value(tag)); view.render_view(host)?; Ok(()) } diff --git a/src/format/list.rs b/src/format/list.rs index 6b945e1fd9..073940adff 100644 --- a/src/format/list.rs +++ b/src/format/list.rs @@ -1,6 +1,7 @@ use crate::format::RenderView; use crate::prelude::*; use derive_new::new; +use nu_errors::ShellError; // A list is printed one line at a time with an optional separator between groups diff --git a/src/format/table.rs b/src/format/table.rs index e956f171ec..7bb496bd77 100644 --- a/src/format/table.rs +++ b/src/format/table.rs @@ -1,8 +1,9 @@ -use crate::data::Value; +use crate::data::value::{format_leaf, style_leaf}; use crate::format::RenderView; use crate::prelude::*; use derive_new::new; -use nu_source::PrettyDebug; +use nu_errors::ShellError; +use nu_protocol::{UntaggedValue, Value}; use textwrap::fill; use prettytable::format::{FormatBuilder, LinePosition, LineSeparator}; @@ -67,10 +68,10 @@ impl TableView { value: UntaggedValue::Row(..), .. } => ( - UntaggedValue::nothing().format_leaf().plain_string(100000), - UntaggedValue::nothing().style_leaf(), + format_leaf(&value::nothing()).plain_string(100000), + style_leaf(&value::nothing()), ), - _ => (value.format_leaf().plain_string(100000), value.style_leaf()), + _ => (format_leaf(value).plain_string(100000), style_leaf(value)), } } else { match value { @@ -80,13 +81,13 @@ impl TableView { } => { let data = value.get_data(d); ( - data.borrow().format_leaf().plain_string(100000), - data.borrow().style_leaf(), + format_leaf(data.borrow()).plain_string(100000), + style_leaf(data.borrow()), ) } _ => ( - UntaggedValue::nothing().format_leaf().plain_string(100000), - UntaggedValue::nothing().style_leaf(), + format_leaf(&value::nothing()).plain_string(100000), + style_leaf(&value::nothing()), ), } } diff --git a/src/lib.rs b/src/lib.rs index 6da0736934..6f86ad8b84 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,30 +11,25 @@ mod cli; mod commands; mod context; mod data; +mod deserializer; mod env; -mod errors; mod evaluate; mod format; mod git; -mod parser; -mod plugin; mod shell; mod stream; -mod traits; mod utils; -pub use crate::commands::command::{CallInfo, ReturnSuccess, ReturnValue}; +pub use crate::cli::cli; +pub use crate::data::base::property_get::ValueExt; +pub use crate::data::config::{config_path, APP_INFO}; +pub use crate::data::dict::{TaggedDictBuilder, TaggedListBuilder}; +pub use crate::data::primitive; +pub use crate::data::value; pub use crate::env::host::BasicHost; -pub use crate::parser::hir::path::{ColumnPath, PathMember, UnspannedPathMember}; -pub use crate::parser::hir::SyntaxShape; -pub use crate::parser::parse::token_tree_builder::TokenTreeBuilder; -pub use crate::plugin::{serve_plugin, Plugin}; -pub use crate::traits::{ShellTypeName, SpannedTypeName}; pub use crate::utils::{did_you_mean, AbsoluteFile, AbsolutePath, RelativePath}; -pub use cli::cli; -pub use data::base::{Primitive, UntaggedValue, Value}; -pub use data::config::{config_path, APP_INFO}; -pub use data::dict::{Dictionary, TaggedDictBuilder, TaggedListBuilder}; -pub use errors::{CoerceInto, ShellError}; +pub use nu_parser::TokenTreeBuilder; pub use num_traits::cast::ToPrimitive; -pub use parser::registry::{EvaluatedArgs, NamedType, PositionalType, Signature}; + +// TODO: Temporary redirect +pub use nu_protocol::{serve_plugin, Plugin}; diff --git a/src/parser.rs b/src/parser.rs deleted file mode 100644 index 597c069a1c..0000000000 --- a/src/parser.rs +++ /dev/null @@ -1,32 +0,0 @@ -pub(crate) mod debug; -pub(crate) mod deserializer; -pub(crate) mod hir; -pub(crate) mod parse; -pub(crate) mod parse_command; -pub(crate) mod registry; - -use crate::errors::ShellError; - -pub(crate) use deserializer::ConfigDeserializer; -pub(crate) use hir::syntax_shape::flat_shape::FlatShape; -pub(crate) use hir::TokensIterator; -pub(crate) use parse::call_node::CallNode; -pub(crate) use parse::files::Files; -pub(crate) use parse::flag::{Flag, FlagKind}; -pub(crate) use parse::operator::Operator; -pub(crate) use parse::parser::pipeline; -pub(crate) use parse::token_tree::{DelimitedNode, Delimiter, TokenNode}; -pub(crate) use parse::tokens::{RawNumber, UnspannedToken}; -pub(crate) use parse::unit::Unit; -pub(crate) use registry::CommandRegistry; - -use nu_source::nom_input; - -pub fn parse(input: &str) -> Result { - let _ = pretty_env_logger::try_init(); - - match pipeline(nom_input(input)) { - Ok((_rest, val)) => Ok(val), - Err(err) => Err(ShellError::parse_error(err)), - } -} diff --git a/src/parser/debug.rs b/src/parser/debug.rs deleted file mode 100644 index cf6770c6f9..0000000000 --- a/src/parser/debug.rs +++ /dev/null @@ -1,51 +0,0 @@ -use nu_source::ShellAnnotation; -use pretty::{Render, RenderAnnotated}; -use std::io; -use termcolor::WriteColor; - -pub struct TermColored<'a, W> { - color_stack: Vec, - upstream: &'a mut W, -} - -impl<'a, W> TermColored<'a, W> { - pub fn new(upstream: &'a mut W) -> TermColored<'a, W> { - TermColored { - color_stack: Vec::new(), - upstream, - } - } -} - -impl<'a, W> Render for TermColored<'a, W> -where - W: io::Write, -{ - type Error = io::Error; - - fn write_str(&mut self, s: &str) -> io::Result { - self.upstream.write(s.as_bytes()) - } - - fn write_str_all(&mut self, s: &str) -> io::Result<()> { - self.upstream.write_all(s.as_bytes()) - } -} - -impl<'a, W> RenderAnnotated for TermColored<'a, W> -where - W: WriteColor, -{ - fn push_annotation(&mut self, ann: &ShellAnnotation) -> Result<(), Self::Error> { - self.color_stack.push(*ann); - self.upstream.set_color(&(*ann).into()) - } - - fn pop_annotation(&mut self) -> Result<(), Self::Error> { - self.color_stack.pop(); - match self.color_stack.last() { - Some(previous) => self.upstream.set_color(&(*previous).into()), - None => self.upstream.reset(), - } - } -} diff --git a/src/plugins/average.rs b/src/plugins/average.rs index 8f852110b3..560aa6562c 100644 --- a/src/plugins/average.rs +++ b/src/plugins/average.rs @@ -1,6 +1,7 @@ -use nu::{ - serve_plugin, CallInfo, CoerceInto, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, - Signature, UntaggedValue, Value, +use nu::{serve_plugin, value, Plugin}; +use nu_errors::{CoerceInto, ShellError}; +use nu_protocol::{ + CallInfo, Primitive, ReturnSuccess, ReturnValue, Signature, UntaggedValue, Value, }; use nu_source::TaggedItem; @@ -26,7 +27,7 @@ impl Average { value: UntaggedValue::Primitive(Primitive::Int(j)), tag, }) => { - self.total = Some(UntaggedValue::int(i + j).into_value(tag)); + self.total = Some(value::int(i + j).into_value(tag)); self.count += 1; Ok(()) } @@ -46,7 +47,7 @@ impl Average { value: UntaggedValue::Primitive(Primitive::Bytes(j)), tag, }) => { - self.total = Some(UntaggedValue::bytes(b + j).into_value(tag)); + self.total = Some(value::bytes(b + j).into_value(tag)); self.count += 1; Ok(()) } diff --git a/src/plugins/binaryview.rs b/src/plugins/binaryview.rs index db00d89aab..07ea73e5e3 100644 --- a/src/plugins/binaryview.rs +++ b/src/plugins/binaryview.rs @@ -1,7 +1,7 @@ use crossterm::{cursor, terminal, Attribute, RawScreen}; -use nu::{ - outln, serve_plugin, CallInfo, Plugin, Primitive, ShellError, Signature, UntaggedValue, Value, -}; +use nu::{serve_plugin, Plugin}; +use nu_errors::ShellError; +use nu_protocol::{outln, CallInfo, Primitive, Signature, UntaggedValue, Value}; use nu_source::AnchorLocation; use pretty_hex::*; diff --git a/src/plugins/docker.rs b/src/plugins/docker.rs index 51936c3c6a..a2a80d6c11 100644 --- a/src/plugins/docker.rs +++ b/src/plugins/docker.rs @@ -48,10 +48,7 @@ fn process_docker_output(cmd_output: &str, tag: Tag) -> Result, Shell let mut dict = TaggedDictBuilder::new(&tag); for (i, v) in values.iter().enumerate() { - dict.insert( - header[i].to_string(), - UntaggedValue::string(v.trim().to_string()), - ); + dict.insert(header[i].to_string(), value::string(v.trim().to_string())); } output.push(dict.into_value()); diff --git a/src/plugins/edit.rs b/src/plugins/edit.rs index 14e5c17e88..91e6ee5437 100644 --- a/src/plugins/edit.rs +++ b/src/plugins/edit.rs @@ -1,6 +1,8 @@ -use nu::{ - serve_plugin, CallInfo, ColumnPath, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, - Signature, SpannedTypeName, SyntaxShape, UntaggedValue, Value, +use nu::{serve_plugin, Plugin, ValueExt}; +use nu_errors::ShellError; +use nu_protocol::{ + CallInfo, ColumnPath, Primitive, ReturnSuccess, ReturnValue, Signature, SpannedTypeName, + SyntaxShape, UntaggedValue, Value, }; use nu_source::Tagged; diff --git a/src/plugins/embed.rs b/src/plugins/embed.rs index 53f0eaebdb..cce9698679 100644 --- a/src/plugins/embed.rs +++ b/src/plugins/embed.rs @@ -1,9 +1,11 @@ #[macro_use] extern crate indexmap; -use nu::{ - serve_plugin, CallInfo, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, Signature, - SpannedTypeName, SyntaxShape, UntaggedValue, Value, +use nu::{serve_plugin, value, Plugin}; +use nu_errors::ShellError; +use nu_protocol::{ + CallInfo, Primitive, ReturnSuccess, ReturnValue, Signature, SpannedTypeName, SyntaxShape, + UntaggedValue, Value, }; use nu_source::Tag; @@ -56,11 +58,11 @@ impl Plugin for Embed { } fn end_filter(&mut self) -> Result, ShellError> { - let row = UntaggedValue::row(indexmap! { + let row = value::row(indexmap! { match &self.field { Some(key) => key.clone(), None => "root".into(), - } => UntaggedValue::table(&self.values).into_value(Tag::unknown()), + } => value::table(&self.values).into_value(Tag::unknown()), }) .into_untagged_value(); diff --git a/src/plugins/format.rs b/src/plugins/format.rs index dda875ab86..d6b352c762 100644 --- a/src/plugins/format.rs +++ b/src/plugins/format.rs @@ -1,6 +1,7 @@ -use nu::{ - serve_plugin, CallInfo, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, Signature, - SyntaxShape, UntaggedValue, Value, +use nu::{serve_plugin, value, Plugin}; +use nu_errors::ShellError; +use nu_protocol::{ + CallInfo, Primitive, ReturnSuccess, ReturnValue, Signature, SyntaxShape, UntaggedValue, Value, }; use nom::{ @@ -114,7 +115,7 @@ impl Plugin for Format { } return Ok(vec![ReturnSuccess::value( - UntaggedValue::string(output).into_untagged_value(), + value::string(output).into_untagged_value(), )]); } _ => {} diff --git a/src/plugins/inc.rs b/src/plugins/inc.rs index dc0f3acd31..08887cfee5 100644 --- a/src/plugins/inc.rs +++ b/src/plugins/inc.rs @@ -1,6 +1,8 @@ -use nu::{ - did_you_mean, serve_plugin, CallInfo, ColumnPath, Plugin, Primitive, ReturnSuccess, - ReturnValue, ShellError, ShellTypeName, Signature, SyntaxShape, UntaggedValue, Value, +use nu::{did_you_mean, serve_plugin, value, Plugin, ValueExt}; +use nu_errors::ShellError; +use nu_protocol::{ + CallInfo, ColumnPath, Primitive, ReturnSuccess, ReturnValue, ShellTypeName, Signature, + SyntaxShape, UntaggedValue, Value, }; use nu_source::{span_for_spanned_list, HasSpan, SpannedItem, Tagged}; @@ -35,7 +37,7 @@ impl Inc { Some(Action::SemVerAction(act_on)) => { let mut ver = match semver::Version::parse(&input) { Ok(parsed_ver) => parsed_ver, - Err(_) => return Ok(UntaggedValue::string(input.to_string())), + Err(_) => return Ok(value::string(input.to_string())), }; match act_on { @@ -44,11 +46,11 @@ impl Inc { SemVerAction::Patch => ver.increment_patch(), } - UntaggedValue::string(ver.to_string()) + value::string(ver.to_string()) } Some(Action::Default) | None => match input.parse::() { - Ok(v) => UntaggedValue::string(format!("{}", v + 1)), - Err(_) => UntaggedValue::string(input), + Ok(v) => value::string(format!("{}", v + 1)), + Err(_) => value::string(input), }, }; @@ -78,10 +80,10 @@ impl Inc { fn inc(&self, value: Value) -> Result { match &value.value { UntaggedValue::Primitive(Primitive::Int(i)) => { - Ok(UntaggedValue::int(i + 1).into_value(value.tag())) + Ok(value::int(i + 1).into_value(value.tag())) } UntaggedValue::Primitive(Primitive::Bytes(b)) => { - Ok(UntaggedValue::bytes(b + 1 as u64).into_value(value.tag())) + Ok(value::bytes(b + 1 as u64).into_value(value.tag())) } UntaggedValue::Primitive(Primitive::String(ref s)) => { Ok(self.apply(&s)?.into_value(value.tag())) @@ -224,9 +226,10 @@ mod tests { use super::{Inc, SemVerAction}; use indexmap::IndexMap; - use nu::{ - CallInfo, EvaluatedArgs, PathMember, Plugin, ReturnSuccess, TaggedDictBuilder, - UnspannedPathMember, UntaggedValue, Value, + use nu::{value, Plugin, TaggedDictBuilder}; + use nu_protocol::{ + CallInfo, EvaluatedArgs, PathMember, ReturnSuccess, UnspannedPathMember, UntaggedValue, + Value, }; use nu_source::{Span, Tag}; @@ -246,7 +249,7 @@ mod tests { fn with_long_flag(&mut self, name: &str) -> &mut Self { self.flags.insert( name.to_string(), - UntaggedValue::boolean(true).into_value(Tag::unknown()), + value::boolean(true).into_value(Tag::unknown()), ); self } @@ -260,7 +263,7 @@ mod tests { .collect(); self.positionals - .push(UntaggedValue::column_path(fields).into_untagged_value()); + .push(value::column_path(fields).into_untagged_value()); self } @@ -274,7 +277,7 @@ mod tests { fn cargo_sample_record(with_version: &str) -> Value { let mut package = TaggedDictBuilder::new(Tag::unknown()); - package.insert_untagged("version", UntaggedValue::string(with_version)); + package.insert_untagged("version", value::string(with_version)); package.into_value() } @@ -357,21 +360,21 @@ mod tests { fn incs_major() { let mut inc = Inc::new(); inc.for_semver(SemVerAction::Major); - assert_eq!(inc.apply("0.1.3").unwrap(), UntaggedValue::string("1.0.0")); + assert_eq!(inc.apply("0.1.3").unwrap(), value::string("1.0.0")); } #[test] fn incs_minor() { let mut inc = Inc::new(); inc.for_semver(SemVerAction::Minor); - assert_eq!(inc.apply("0.1.3").unwrap(), UntaggedValue::string("0.2.0")); + assert_eq!(inc.apply("0.1.3").unwrap(), value::string("0.2.0")); } #[test] fn incs_patch() { let mut inc = Inc::new(); inc.for_semver(SemVerAction::Patch); - assert_eq!(inc.apply("0.1.3").unwrap(), UntaggedValue::string("0.1.4")); + assert_eq!(inc.apply("0.1.3").unwrap(), value::string("0.1.4")); } #[test] @@ -396,7 +399,7 @@ mod tests { .. }) => assert_eq!( *o.get_data(&String::from("version")).borrow(), - UntaggedValue::string(String::from("1.0.0")).into_untagged_value() + value::string(String::from("1.0.0")).into_untagged_value() ), _ => {} } @@ -424,7 +427,7 @@ mod tests { .. }) => assert_eq!( *o.get_data(&String::from("version")).borrow(), - UntaggedValue::string(String::from("0.2.0")).into_untagged_value() + value::string(String::from("0.2.0")).into_untagged_value() ), _ => {} } @@ -453,7 +456,7 @@ mod tests { .. }) => assert_eq!( *o.get_data(&field).borrow(), - UntaggedValue::string(String::from("0.1.4")).into_untagged_value() + value::string(String::from("0.1.4")).into_untagged_value() ), _ => {} } diff --git a/src/plugins/insert.rs b/src/plugins/insert.rs index 20eacbd993..9f99bcfb15 100644 --- a/src/plugins/insert.rs +++ b/src/plugins/insert.rs @@ -1,6 +1,8 @@ -use nu::{ - serve_plugin, CallInfo, ColumnPath, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, - ShellTypeName, Signature, SpannedTypeName, SyntaxShape, UntaggedValue, Value, +use nu::{serve_plugin, Plugin, ValueExt}; +use nu_errors::ShellError; +use nu_protocol::{ + CallInfo, ColumnPath, Primitive, ReturnSuccess, ReturnValue, ShellTypeName, Signature, + SpannedTypeName, SyntaxShape, UntaggedValue, Value, }; use nu_source::SpannedItem; diff --git a/src/plugins/match.rs b/src/plugins/match.rs index 271425aa8e..b513073eaf 100644 --- a/src/plugins/match.rs +++ b/src/plugins/match.rs @@ -1,6 +1,7 @@ -use nu::{ - serve_plugin, CallInfo, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, Signature, - SyntaxShape, UntaggedValue, Value, +use nu::{serve_plugin, Plugin}; +use nu_errors::ShellError; +use nu_protocol::{ + CallInfo, Primitive, ReturnSuccess, ReturnValue, Signature, SyntaxShape, UntaggedValue, Value, }; use regex::Regex; diff --git a/src/plugins/parse.rs b/src/plugins/parse.rs index 5e45c2d561..8354cafb10 100644 --- a/src/plugins/parse.rs +++ b/src/plugins/parse.rs @@ -1,6 +1,7 @@ -use nu::{ - serve_plugin, CallInfo, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, Signature, - SyntaxShape, TaggedDictBuilder, UntaggedValue, Value, +use nu::{serve_plugin, value, Plugin, TaggedDictBuilder}; +use nu_errors::ShellError; +use nu_protocol::{ + CallInfo, Primitive, ReturnSuccess, ReturnValue, Signature, SyntaxShape, UntaggedValue, Value, }; use nom::{ @@ -139,10 +140,7 @@ impl Plugin for Parse { let mut dict = TaggedDictBuilder::new(tag); for (idx, column_name) in self.column_names.iter().enumerate() { - dict.insert_untagged( - column_name, - UntaggedValue::string(&cap[idx + 1].to_string()), - ); + dict.insert_untagged(column_name, value::string(&cap[idx + 1].to_string())); } results.push(ReturnSuccess::value(dict.into_value())); diff --git a/src/plugins/ps.rs b/src/plugins/ps.rs index 49098702d9..3c3d7f4644 100644 --- a/src/plugins/ps.rs +++ b/src/plugins/ps.rs @@ -5,10 +5,9 @@ use heim::process::{self as process, Process, ProcessResult}; use heim::units::{ratio, Ratio}; use std::usize; -use nu::{ - serve_plugin, CallInfo, Plugin, ReturnSuccess, ReturnValue, ShellError, Signature, - TaggedDictBuilder, UntaggedValue, Value, -}; +use nu::{serve_plugin, value, Plugin, TaggedDictBuilder}; +use nu_errors::ShellError; +use nu_protocol::{CallInfo, ReturnSuccess, ReturnValue, Signature, Value}; use nu_source::Tag; use std::time::Duration; @@ -43,14 +42,14 @@ async fn ps(tag: Tag) -> Vec { while let Some(res) = processes.next().await { if let Ok((process, usage)) = res { let mut dict = TaggedDictBuilder::new(&tag); - dict.insert_untagged("pid", UntaggedValue::int(process.pid())); + dict.insert_untagged("pid", value::int(process.pid())); if let Ok(name) = process.name().await { - dict.insert_untagged("name", UntaggedValue::string(name)); + dict.insert_untagged("name", value::string(name)); } if let Ok(status) = process.status().await { - dict.insert_untagged("status", UntaggedValue::string(format!("{:?}", status))); + dict.insert_untagged("status", value::string(format!("{:?}", status))); } - dict.insert_untagged("cpu", UntaggedValue::number(usage.get::())); + dict.insert_untagged("cpu", value::number(usage.get::())); output.push(dict.into_value()); } } diff --git a/src/plugins/skip.rs b/src/plugins/skip.rs index 9b64e3dfc0..1bf0982125 100644 --- a/src/plugins/skip.rs +++ b/src/plugins/skip.rs @@ -1,6 +1,7 @@ -use nu::{ - serve_plugin, CallInfo, CoerceInto, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, - Signature, SyntaxShape, UntaggedValue, Value, +use nu::{serve_plugin, Plugin}; +use nu_errors::{CoerceInto, ShellError}; +use nu_protocol::{ + CallInfo, Primitive, ReturnSuccess, ReturnValue, Signature, SyntaxShape, UntaggedValue, Value, }; use nu_source::TaggedItem; diff --git a/src/plugins/str.rs b/src/plugins/str.rs index bb9e9017d3..dde12e72ee 100644 --- a/src/plugins/str.rs +++ b/src/plugins/str.rs @@ -1,6 +1,8 @@ -use nu::{ - did_you_mean, serve_plugin, CallInfo, ColumnPath, Plugin, Primitive, ReturnSuccess, - ReturnValue, ShellError, ShellTypeName, Signature, SyntaxShape, UntaggedValue, Value, +use nu::{did_you_mean, serve_plugin, value, Plugin, ValueExt}; +use nu_errors::ShellError; +use nu_protocol::{ + CallInfo, ColumnPath, Primitive, ReturnSuccess, ReturnValue, ShellTypeName, Signature, + SyntaxShape, UntaggedValue, Value, }; use nu_source::{span_for_spanned_list, Tagged}; @@ -39,15 +41,15 @@ impl Str { fn apply(&self, input: &str) -> Result { let applied = match self.action.as_ref() { - Some(Action::Downcase) => UntaggedValue::string(input.to_ascii_lowercase()), - Some(Action::Upcase) => UntaggedValue::string(input.to_ascii_uppercase()), + Some(Action::Downcase) => value::string(input.to_ascii_lowercase()), + Some(Action::Upcase) => value::string(input.to_ascii_uppercase()), Some(Action::Substring(s, e)) => { let end: usize = cmp::min(*e, input.len()); let start: usize = *s; if start > input.len() - 1 { - UntaggedValue::string("") + value::string("") } else { - UntaggedValue::string( + value::string( &input .chars() .skip(start) @@ -57,25 +59,23 @@ impl Str { } } Some(Action::Replace(mode)) => match mode { - ReplaceAction::Direct(replacement) => UntaggedValue::string(replacement.as_str()), + ReplaceAction::Direct(replacement) => value::string(replacement.as_str()), ReplaceAction::FindAndReplace(find, replacement) => { let regex = Regex::new(find.as_str()); match regex { - Ok(re) => UntaggedValue::string( - re.replace(input, replacement.as_str()).to_owned(), - ), - Err(_) => UntaggedValue::string(input), + Ok(re) => value::string(re.replace(input, replacement.as_str()).to_owned()), + Err(_) => value::string(input), } } }, Some(Action::ToInteger) => match input.trim() { other => match other.parse::() { - Ok(v) => UntaggedValue::int(v), - Err(_) => UntaggedValue::string(input), + Ok(v) => value::int(v), + Err(_) => value::string(input), }, }, - None => UntaggedValue::string(input), + None => value::string(input), }; Ok(applied) @@ -276,8 +276,8 @@ impl Plugin for Str { }) = args.get("find-replace") { self.for_replace(ReplaceAction::FindAndReplace( - arguments.get(0).unwrap().as_string()?, - arguments.get(1).unwrap().as_string()?, + arguments.get(0).unwrap().as_string()?.to_string(), + arguments.get(1).unwrap().as_string()?.to_string(), )); } } @@ -312,19 +312,17 @@ fn main() { mod tests { use super::{Action, ReplaceAction, Str}; use indexmap::IndexMap; - use nu::{ - CallInfo, EvaluatedArgs, Plugin, Primitive, ReturnSuccess, TaggedDictBuilder, - UntaggedValue, Value, - }; + use nu::{value, Plugin, TaggedDictBuilder, ValueExt}; + use nu_protocol::{CallInfo, EvaluatedArgs, Primitive, ReturnSuccess, UntaggedValue, Value}; use nu_source::Tag; use num_bigint::BigInt; fn string(input: impl Into) -> Value { - UntaggedValue::string(input.into()).into_untagged_value() + value::string(input.into()).into_untagged_value() } fn table(list: &Vec) -> Value { - UntaggedValue::table(list).into_untagged_value() + value::table(list).into_untagged_value() } fn column_path(paths: &Vec) -> Value { @@ -357,7 +355,7 @@ mod tests { fn with_long_flag(&mut self, name: &str) -> &mut Self { self.flags.insert( name.to_string(), - UntaggedValue::boolean(true).into_value(Tag::unknown()), + value::boolean(true).into_value(Tag::unknown()), ); self } @@ -365,7 +363,7 @@ mod tests { fn with_parameter(&mut self, name: &str) -> &mut Self { let fields: Vec = name .split(".") - .map(|s| UntaggedValue::string(s.to_string()).into_value(Tag::unknown())) + .map(|s| value::string(s.to_string()).into_value(Tag::unknown())) .collect(); self.positionals.push(column_path(&fields)); @@ -382,12 +380,12 @@ mod tests { fn structured_sample_record(key: &str, value: &str) -> Value { let mut record = TaggedDictBuilder::new(Tag::unknown()); - record.insert_untagged(key.clone(), UntaggedValue::string(value)); + record.insert_untagged(key.clone(), value::string(value)); record.into_value() } fn unstructured_sample_record(value: &str) -> Value { - UntaggedValue::string(value).into_value(Tag::unknown()) + value::string(value).into_value(Tag::unknown()) } #[test] @@ -529,30 +527,21 @@ mod tests { fn str_downcases() { let mut strutils = Str::new(); strutils.for_downcase(); - assert_eq!( - strutils.apply("ANDRES").unwrap(), - UntaggedValue::string("andres") - ); + assert_eq!(strutils.apply("ANDRES").unwrap(), value::string("andres")); } #[test] fn str_upcases() { let mut strutils = Str::new(); strutils.for_upcase(); - assert_eq!( - strutils.apply("andres").unwrap(), - UntaggedValue::string("ANDRES") - ); + assert_eq!(strutils.apply("andres").unwrap(), value::string("ANDRES")); } #[test] fn str_to_int() { let mut strutils = Str::new(); strutils.for_to_int(); - assert_eq!( - strutils.apply("9999").unwrap(), - UntaggedValue::int(9999 as i64) - ); + assert_eq!(strutils.apply("9999").unwrap(), value::int(9999 as i64)); } #[test] @@ -560,10 +549,7 @@ mod tests { let mut strutils = Str::new(); strutils.for_replace(ReplaceAction::Direct("robalino".to_string())); - assert_eq!( - strutils.apply("andres").unwrap(), - UntaggedValue::string("robalino") - ); + assert_eq!(strutils.apply("andres").unwrap(), value::string("robalino")); } #[test] @@ -575,7 +561,7 @@ mod tests { )); assert_eq!( strutils.apply("wykittens").unwrap(), - UntaggedValue::string("wyjotandrehuda") + value::string("wyjotandrehuda") ); } @@ -601,7 +587,7 @@ mod tests { .. }) => assert_eq!( *o.get_data(&String::from("name")).borrow(), - UntaggedValue::string(String::from("JOTANDREHUDA")).into_untagged_value() + value::string(String::from("JOTANDREHUDA")).into_untagged_value() ), _ => {} } @@ -649,7 +635,7 @@ mod tests { .. }) => assert_eq!( *o.get_data(&String::from("name")).borrow(), - UntaggedValue::string(String::from("jotandrehuda")).into_untagged_value() + value::string(String::from("jotandrehuda")).into_untagged_value() ), _ => {} } @@ -697,7 +683,7 @@ mod tests { .. }) => assert_eq!( *o.get_data(&String::from("Nu_birthday")).borrow(), - UntaggedValue::int(10).into_untagged_value() + value::int(10).into_untagged_value() ), _ => {} } @@ -883,7 +869,7 @@ mod tests { }) => assert_eq!( *o.get_data(&String::from("rustconf")).borrow(), Value { - value: UntaggedValue::string(String::from("22nd August 2019")), + value: value::string(String::from("22nd August 2019")), tag: Tag::unknown() } ), @@ -941,7 +927,7 @@ mod tests { }) => assert_eq!( *o.get_data(&String::from("staff")).borrow(), Value { - value: UntaggedValue::string(String::from("wyjotandrehuda")), + value: value::string(String::from("wyjotandrehuda")), tag: Tag::unknown() } ), diff --git a/src/plugins/sum.rs b/src/plugins/sum.rs index 733b86926e..32e9dff2e5 100644 --- a/src/plugins/sum.rs +++ b/src/plugins/sum.rs @@ -1,6 +1,7 @@ -use nu::{ - serve_plugin, CallInfo, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, Signature, - UntaggedValue, Value, +use nu::{serve_plugin, value, Plugin}; +use nu_errors::ShellError; +use nu_protocol::{ + CallInfo, Primitive, ReturnSuccess, ReturnValue, Signature, UntaggedValue, Value, }; struct Sum { @@ -21,7 +22,7 @@ impl Sum { tag, }) => { //TODO: handle overflow - self.total = Some(UntaggedValue::int(i + j).into_value(tag)); + self.total = Some(value::int(i + j).into_value(tag)); Ok(()) } None => { @@ -42,7 +43,7 @@ impl Sum { tag, }) => { //TODO: handle overflow - self.total = Some(UntaggedValue::bytes(b + j).into_value(tag)); + self.total = Some(value::bytes(b + j).into_value(tag)); Ok(()) } None => { diff --git a/src/plugins/sys.rs b/src/plugins/sys.rs index 3226916015..c4816e6adc 100644 --- a/src/plugins/sys.rs +++ b/src/plugins/sys.rs @@ -4,10 +4,9 @@ use futures::executor::block_on; use futures::stream::StreamExt; use heim::units::{frequency, information, thermodynamic_temperature, time}; use heim::{disk, host, memory, net, sensors}; -use nu::{ - serve_plugin, CallInfo, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, Signature, - TaggedDictBuilder, UntaggedValue, Value, -}; +use nu::{primitive, serve_plugin, value, Plugin, TaggedDictBuilder}; +use nu_errors::ShellError; +use nu_protocol::{CallInfo, ReturnSuccess, ReturnValue, Signature, UntaggedValue, Value}; use nu_source::Tag; struct Sys; @@ -21,26 +20,26 @@ async fn cpu(tag: Tag) -> Option { match futures::future::try_join(heim::cpu::logical_count(), heim::cpu::frequency()).await { Ok((num_cpu, cpu_speed)) => { let mut cpu_idx = TaggedDictBuilder::with_capacity(tag, 4); - cpu_idx.insert_untagged("cores", Primitive::number(num_cpu)); + cpu_idx.insert_untagged("cores", primitive::number(num_cpu)); let current_speed = (cpu_speed.current().get::() as f64 / 1_000_000_000.0 * 100.0) .round() / 100.0; - cpu_idx.insert_untagged("current ghz", Primitive::number(current_speed)); + cpu_idx.insert_untagged("current ghz", primitive::number(current_speed)); if let Some(min_speed) = cpu_speed.min() { let min_speed = (min_speed.get::() as f64 / 1_000_000_000.0 * 100.0).round() / 100.0; - cpu_idx.insert_untagged("min ghz", Primitive::number(min_speed)); + cpu_idx.insert_untagged("min ghz", primitive::number(min_speed)); } if let Some(max_speed) = cpu_speed.max() { let max_speed = (max_speed.get::() as f64 / 1_000_000_000.0 * 100.0).round() / 100.0; - cpu_idx.insert_untagged("max ghz", Primitive::number(max_speed)); + cpu_idx.insert_untagged("max ghz", primitive::number(max_speed)); } Some(cpu_idx.into_value()) @@ -58,22 +57,22 @@ async fn mem(tag: Tag) -> Value { if let Ok(memory) = memory_result { dict.insert_untagged( "total", - UntaggedValue::bytes(memory.total().get::()), + value::bytes(memory.total().get::()), ); dict.insert_untagged( "free", - UntaggedValue::bytes(memory.free().get::()), + value::bytes(memory.free().get::()), ); } if let Ok(swap) = swap_result { dict.insert_untagged( "swap total", - UntaggedValue::bytes(swap.total().get::()), + value::bytes(swap.total().get::()), ); dict.insert_untagged( "swap free", - UntaggedValue::bytes(swap.free().get::()), + value::bytes(swap.free().get::()), ); } @@ -88,13 +87,10 @@ async fn host(tag: Tag) -> Value { // OS if let Ok(platform) = platform_result { - dict.insert_untagged("name", UntaggedValue::string(platform.system())); - dict.insert_untagged("release", UntaggedValue::string(platform.release())); - dict.insert_untagged("hostname", UntaggedValue::string(platform.hostname())); - dict.insert_untagged( - "arch", - UntaggedValue::string(platform.architecture().as_str()), - ); + dict.insert_untagged("name", value::string(platform.system())); + dict.insert_untagged("release", value::string(platform.release())); + dict.insert_untagged("hostname", value::string(platform.hostname())); + dict.insert_untagged("arch", value::string(platform.architecture().as_str())); } // Uptime @@ -107,10 +103,10 @@ async fn host(tag: Tag) -> Value { let minutes = (uptime - days * 60 * 60 * 24 - hours * 60 * 60) / 60; let seconds = uptime % 60; - uptime_dict.insert_untagged("days", UntaggedValue::int(days)); - uptime_dict.insert_untagged("hours", UntaggedValue::int(hours)); - uptime_dict.insert_untagged("mins", UntaggedValue::int(minutes)); - uptime_dict.insert_untagged("secs", UntaggedValue::int(seconds)); + uptime_dict.insert_untagged("days", value::int(days)); + uptime_dict.insert_untagged("hours", value::int(hours)); + uptime_dict.insert_untagged("mins", value::int(minutes)); + uptime_dict.insert_untagged("secs", value::int(seconds)); dict.insert_value("uptime", uptime_dict); } @@ -121,7 +117,7 @@ async fn host(tag: Tag) -> Value { while let Some(user) = users.next().await { if let Ok(user) = user { user_vec.push(Value { - value: UntaggedValue::string(user.username()), + value: value::string(user.username()), tag: tag.clone(), }); } @@ -140,31 +136,28 @@ async fn disks(tag: Tag) -> Option { let mut dict = TaggedDictBuilder::with_capacity(&tag, 6); dict.insert_untagged( "device", - UntaggedValue::string( + value::string( part.device() .unwrap_or_else(|| OsStr::new("N/A")) .to_string_lossy(), ), ); - dict.insert_untagged("type", UntaggedValue::string(part.file_system().as_str())); - dict.insert_untagged( - "mount", - UntaggedValue::string(part.mount_point().to_string_lossy()), - ); + dict.insert_untagged("type", value::string(part.file_system().as_str())); + dict.insert_untagged("mount", value::string(part.mount_point().to_string_lossy())); if let Ok(usage) = disk::usage(part.mount_point().to_path_buf()).await { dict.insert_untagged( "total", - UntaggedValue::bytes(usage.total().get::()), + value::bytes(usage.total().get::()), ); dict.insert_untagged( "used", - UntaggedValue::bytes(usage.used().get::()), + value::bytes(usage.used().get::()), ); dict.insert_untagged( "free", - UntaggedValue::bytes(usage.free().get::()), + value::bytes(usage.free().get::()), ); } @@ -188,28 +181,24 @@ async fn battery(tag: Tag) -> Option { if let Ok(battery) = battery { let mut dict = TaggedDictBuilder::new(&tag); if let Some(vendor) = battery.vendor() { - dict.insert_untagged("vendor", UntaggedValue::string(vendor)); + dict.insert_untagged("vendor", value::string(vendor)); } if let Some(model) = battery.model() { - dict.insert_untagged("model", UntaggedValue::string(model)); + dict.insert_untagged("model", value::string(model)); } if let Some(cycles) = battery.cycle_count() { - dict.insert_untagged("cycles", UntaggedValue::int(cycles)); + dict.insert_untagged("cycles", value::int(cycles)); } if let Some(time_to_full) = battery.time_to_full() { dict.insert_untagged( "mins to full", - UntaggedValue::number( - time_to_full.get::(), - ), + value::number(time_to_full.get::()), ); } if let Some(time_to_empty) = battery.time_to_empty() { dict.insert_untagged( "mins to empty", - UntaggedValue::number( - time_to_empty.get::(), - ), + value::number(time_to_empty.get::()), ); } output.push(dict.into_value()); @@ -232,13 +221,13 @@ async fn temp(tag: Tag) -> Option { while let Some(sensor) = sensors.next().await { if let Ok(sensor) = sensor { let mut dict = TaggedDictBuilder::new(&tag); - dict.insert_untagged("unit", UntaggedValue::string(sensor.unit())); + dict.insert_untagged("unit", value::string(sensor.unit())); if let Some(label) = sensor.label() { - dict.insert_untagged("label", UntaggedValue::string(label)); + dict.insert_untagged("label", value::string(label)); } dict.insert_untagged( "temp", - UntaggedValue::number( + value::number( sensor .current() .get::(), @@ -247,15 +236,13 @@ async fn temp(tag: Tag) -> Option { if let Some(high) = sensor.high() { dict.insert_untagged( "high", - UntaggedValue::number(high.get::()), + value::number(high.get::()), ); } if let Some(critical) = sensor.critical() { dict.insert_untagged( "critical", - UntaggedValue::number( - critical.get::(), - ), + value::number(critical.get::()), ); } @@ -276,14 +263,14 @@ async fn net(tag: Tag) -> Option { while let Some(nic) = io_counters.next().await { if let Ok(nic) = nic { let mut network_idx = TaggedDictBuilder::with_capacity(&tag, 3); - network_idx.insert_untagged("name", UntaggedValue::string(nic.interface())); + network_idx.insert_untagged("name", value::string(nic.interface())); network_idx.insert_untagged( "sent", - UntaggedValue::bytes(nic.bytes_sent().get::()), + value::bytes(nic.bytes_sent().get::()), ); network_idx.insert_untagged( "recv", - UntaggedValue::bytes(nic.bytes_recv().get::()), + value::bytes(nic.bytes_recv().get::()), ); output.push(network_idx.into_value()); } diff --git a/src/prelude.rs b/src/prelude.rs index 3c94ba8cfc..35fa419c80 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -68,19 +68,6 @@ macro_rules! trace_out_stream { }}; } -// These macros exist to differentiate between intentional writing to stdout -// and stray printlns left by accident - -#[macro_export] -macro_rules! outln { - ($($tokens:tt)*) => { println!($($tokens)*) } -} - -#[macro_export] -macro_rules! errln { - ($($tokens:tt)*) => { eprintln!($($tokens)*) } -} - #[macro_export] macro_rules! dict { ($( $key:expr => $value:expr ),*) => { @@ -100,40 +87,34 @@ macro_rules! dict { } } -pub(crate) use crate::cli::MaybeOwned; +pub(crate) use nu_protocol::{errln, outln}; + pub(crate) use crate::commands::command::{ - CallInfo, CommandAction, CommandArgs, ReturnSuccess, ReturnValue, RunnableContext, + CallInfoExt, CommandArgs, PerItemCommand, RawCommandArgs, RunnableContext, }; -pub(crate) use crate::commands::PerItemCommand; -pub(crate) use crate::commands::RawCommandArgs; pub(crate) use crate::context::CommandRegistry; pub(crate) use crate::context::Context; -pub(crate) use crate::data::base::{UntaggedValue, Value}; +pub(crate) use crate::data::base::property_get::ValueExt; pub(crate) use crate::data::types::ExtractType; -pub(crate) use crate::data::Primitive; +pub(crate) use crate::data::value; pub(crate) use crate::env::host::handle_unexpected; pub(crate) use crate::env::Host; -pub(crate) use crate::errors::{CoerceInto, ParseError, ShellError}; -pub(crate) use crate::parser::hir::SyntaxShape; -pub(crate) use crate::parser::parse::parser::Number; -pub(crate) use crate::parser::registry::Signature; pub(crate) use crate::shell::filesystem_shell::FilesystemShell; pub(crate) use crate::shell::help_shell::HelpShell; pub(crate) use crate::shell::shell_manager::ShellManager; pub(crate) use crate::shell::value_shell::ValueShell; pub(crate) use crate::stream::{InputStream, OutputStream}; -pub(crate) use crate::traits::{ShellTypeName, SpannedTypeName}; pub(crate) use async_stream::stream as async_stream; pub(crate) use bigdecimal::BigDecimal; pub(crate) use futures::stream::BoxStream; pub(crate) use futures::{FutureExt, Stream, StreamExt}; +pub(crate) use nu_protocol::{EvaluateTrait, MaybeOwned}; pub(crate) use nu_source::{ - b, AnchorLocation, DebugDocBuilder, HasFallibleSpan, HasSpan, PrettyDebug, - PrettyDebugWithSource, Span, SpannedItem, Tag, TaggedItem, Text, + b, AnchorLocation, DebugDocBuilder, HasSpan, PrettyDebug, PrettyDebugWithSource, Span, + SpannedItem, Tag, TaggedItem, Text, }; pub(crate) use num_bigint::BigInt; -pub(crate) use num_traits::cast::{FromPrimitive, ToPrimitive}; -pub(crate) use num_traits::identities::Zero; +pub(crate) use num_traits::cast::ToPrimitive; pub(crate) use serde::Deserialize; pub(crate) use std::collections::VecDeque; pub(crate) use std::future::Future; @@ -147,11 +128,11 @@ pub trait FromInputStream { impl FromInputStream for T where - T: Stream + Send + 'static, + T: Stream + Send + 'static, { fn from_input_stream(self) -> OutputStream { OutputStream { - values: self.map(ReturnSuccess::value).boxed(), + values: self.map(nu_protocol::ReturnSuccess::value).boxed(), } } } @@ -163,7 +144,7 @@ pub trait ToInputStream { impl ToInputStream for T where T: Stream + Send + 'static, - U: Into>, + U: Into>, { fn to_input_stream(self) -> InputStream { InputStream { @@ -179,7 +160,7 @@ pub trait ToOutputStream { impl ToOutputStream for T where T: Stream + Send + 'static, - U: Into, + U: Into, { fn to_output_stream(self) -> OutputStream { OutputStream { diff --git a/src/shell/filesystem_shell.rs b/src/shell/filesystem_shell.rs index 287c8baa60..15aaaec83c 100644 --- a/src/shell/filesystem_shell.rs +++ b/src/shell/filesystem_shell.rs @@ -8,6 +8,8 @@ use crate::prelude::*; use crate::shell::completer::NuCompleter; use crate::shell::shell::Shell; use crate::utils::FileStructure; +use nu_errors::ShellError; +use nu_protocol::{Primitive, ReturnSuccess, UntaggedValue}; use nu_source::Tagged; use rustyline::completion::FilenameCompleter; use rustyline::hint::{Hinter, HistoryHinter}; diff --git a/src/shell/help_shell.rs b/src/shell/help_shell.rs index ec4156f4f0..2da32fa60c 100644 --- a/src/shell/help_shell.rs +++ b/src/shell/help_shell.rs @@ -6,6 +6,8 @@ use crate::commands::rm::RemoveArgs; use crate::data::{command_dict, TaggedDictBuilder}; use crate::prelude::*; use crate::shell::shell::Shell; +use nu_errors::ShellError; +use nu_protocol::{Primitive, ReturnSuccess, ShellTypeName, UntaggedValue, Value}; use nu_source::Tagged; use std::ffi::OsStr; use std::path::PathBuf; diff --git a/src/shell/helper.rs b/src/shell/helper.rs index 2d830f6ae4..3008d5514d 100644 --- a/src/shell/helper.rs +++ b/src/shell/helper.rs @@ -1,9 +1,9 @@ use crate::context::Context; -use crate::parser::hir::syntax_shape::{color_fallible_syntax, FlatShape, PipelineShape}; -use crate::parser::hir::TokensIterator; -use crate::parser::parse::token_tree::TokenNode; use ansi_term::Color; use log::{log_enabled, trace}; +use nu_parser::hir::syntax_shape::color_fallible_syntax; +use nu_parser::{FlatShape, PipelineShape, TokenNode, TokensIterator}; +use nu_protocol::outln; use nu_source::{nom_input, HasSpan, Spanned, Tag, Tagged, Text}; use rustyline::completion::Completer; use rustyline::error::ReadlineError; @@ -63,7 +63,7 @@ impl Highlighter for Helper { } fn highlight<'l>(&self, line: &'l str, _pos: usize) -> Cow<'l, str> { - let tokens = crate::parser::pipeline(nom_input(line)); + let tokens = nu_parser::pipeline(nom_input(line)); match tokens { Err(_) => Cow::Borrowed(line), diff --git a/src/shell/shell.rs b/src/shell/shell.rs index 41f5aa9a5c..e812e7b24e 100644 --- a/src/shell/shell.rs +++ b/src/shell/shell.rs @@ -3,9 +3,9 @@ use crate::commands::cp::CopyArgs; use crate::commands::mkdir::MkdirArgs; use crate::commands::mv::MoveArgs; use crate::commands::rm::RemoveArgs; -use crate::errors::ShellError; use crate::prelude::*; use crate::stream::OutputStream; +use nu_errors::ShellError; use nu_source::Tagged; use std::path::PathBuf; diff --git a/src/shell/shell_manager.rs b/src/shell/shell_manager.rs index fa49d0e4ed..6dd0a66a40 100644 --- a/src/shell/shell_manager.rs +++ b/src/shell/shell_manager.rs @@ -3,11 +3,11 @@ use crate::commands::cp::CopyArgs; use crate::commands::mkdir::MkdirArgs; use crate::commands::mv::MoveArgs; use crate::commands::rm::RemoveArgs; -use crate::errors::ShellError; use crate::prelude::*; use crate::shell::filesystem_shell::FilesystemShell; use crate::shell::shell::Shell; use crate::stream::OutputStream; +use nu_errors::ShellError; use nu_source::Tagged; use std::error::Error; use std::path::PathBuf; diff --git a/src/shell/value_shell.rs b/src/shell/value_shell.rs index f0021e68bb..b655d73443 100644 --- a/src/shell/value_shell.rs +++ b/src/shell/value_shell.rs @@ -6,6 +6,8 @@ use crate::commands::rm::RemoveArgs; use crate::prelude::*; use crate::shell::shell::Shell; use crate::utils::ValueStructure; +use nu_errors::ShellError; +use nu_protocol::{ReturnSuccess, ShellTypeName, UntaggedValue, Value}; use nu_source::Tagged; use std::ffi::OsStr; use std::path::{Path, PathBuf}; @@ -216,7 +218,7 @@ impl Shell for ValueShell { fn pwd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result { let mut stream = VecDeque::new(); stream.push_back(ReturnSuccess::value( - UntaggedValue::string(self.path()).into_value(&args.call_info.name_tag), + value::string(self.path()).into_value(&args.call_info.name_tag), )); Ok(stream.into()) } diff --git a/src/stream.rs b/src/stream.rs index bf362b8b12..fcc430d6c3 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -1,4 +1,5 @@ use crate::prelude::*; +use nu_protocol::{ReturnSuccess, ReturnValue, Value}; pub struct InputStream { pub(crate) values: BoxStream<'static, Value>, diff --git a/src/utils.rs b/src/utils.rs index 75004aa915..c57a4b861b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,6 +1,5 @@ -use crate::data::base::{UntaggedValue, Value}; -use crate::errors::ShellError; -use crate::{PathMember, UnspannedPathMember}; +use nu_errors::ShellError; +use nu_protocol::{PathMember, UnspannedPathMember, UntaggedValue, Value}; use nu_source::{b, DebugDocBuilder, PrettyDebug}; use std::ops::Div; use std::path::{Component, Path, PathBuf}; @@ -161,22 +160,20 @@ impl<'a> Iterator for TaggedValueIter<'a> { } } -impl Value { - fn is_tagged_dir(value: &Value) -> bool { - match &value.value { - UntaggedValue::Row(_) | UntaggedValue::Table(_) => true, - _ => false, - } +fn is_value_tagged_dir(value: &Value) -> bool { + match &value.value { + UntaggedValue::Row(_) | UntaggedValue::Table(_) => true, + _ => false, } +} - fn tagged_entries(value: &Value) -> TaggedValueIter<'_> { - match &value.value { - UntaggedValue::Row(o) => { - let iter = o.entries.iter(); - TaggedValueIter::List(iter) - } - _ => TaggedValueIter::Empty, +fn tagged_entries_for(value: &Value) -> TaggedValueIter<'_> { + match &value.value { + UntaggedValue::Row(o) => { + let iter = o.entries.iter(); + TaggedValueIter::List(iter) } + _ => TaggedValueIter::Empty, } } @@ -237,7 +234,7 @@ impl ValueStructure { } fn build(&mut self, src: &Value, lvl: usize) -> Result<(), ShellError> { - for entry in Value::tagged_entries(src) { + for entry in tagged_entries_for(src) { let value = entry.1; let path = entry.0; @@ -246,7 +243,7 @@ impl ValueStructure { loc: PathBuf::from(path), }); - if Value::is_tagged_dir(value) { + if is_value_tagged_dir(value) { self.build(value, lvl + 1)?; } } @@ -335,8 +332,8 @@ impl FileStructure { #[cfg(test)] mod tests { use super::{FileStructure, Res, ValueResource, ValueStructure}; - use crate::data::base::{UntaggedValue, Value}; - use crate::data::TaggedDictBuilder; + use crate::data::{value, TaggedDictBuilder}; + use nu_protocol::Value; use nu_source::Tag; use pretty_assertions::assert_eq; use std::path::PathBuf; @@ -355,7 +352,7 @@ mod tests { fn structured_sample_record(key: &str, value: &str) -> Value { let mut record = TaggedDictBuilder::new(Tag::unknown()); - record.insert_untagged(key.clone(), UntaggedValue::string(value)); + record.insert_untagged(key.clone(), value::string(value)); record.into_value() } diff --git a/tests/filter_str_tests.rs b/tests/filter_str_tests.rs index a58c5439b6..fde3c77ee0 100644 --- a/tests/filter_str_tests.rs +++ b/tests/filter_str_tests.rs @@ -131,7 +131,7 @@ fn find_and_replaces() { cwd: dirs.test(), h::pipeline( r#" open sample.toml - | str fortune.teller.phone --find-replace [KATZ 5289] + | str fortune.teller.phone --find-replace [KATZ "5289"] | get fortune.teller.phone | echo $it "# @@ -157,7 +157,7 @@ fn find_and_replaces_without_passing_field() { r#" open sample.toml | get fortune.teller.phone - | str --find-replace [KATZ 5289] + | str --find-replace [KATZ "5289"] | echo $it "# ));