diff --git a/Cargo.lock b/Cargo.lock index c7898fe83..1e501dc4b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -593,9 +593,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "chrono" -version = "0.4.13" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c74d84029116787153e02106bf53e66828452a4b325cc8652b788b5967c0a0b6" +checksum = "942f72db697d8767c22d46a598e01f2d3b475501ea43d0db4f16d90259182d0b" dependencies = [ "num-integer", "num-traits 0.2.12", @@ -2932,6 +2932,7 @@ dependencies = [ "futures 0.3.5", "log 0.4.11", "nu-cli", + "nu-data", "nu-errors", "nu-parser", "nu-plugin", @@ -3005,6 +3006,7 @@ dependencies = [ "log 0.4.11", "meval", "natural", + "nu-data", "nu-errors", "nu-parser", "nu-plugin", @@ -3058,6 +3060,36 @@ dependencies = [ "zip", ] +[[package]] +name = "nu-data" +version = "0.18.2" +dependencies = [ + "ansi_term 0.12.1", + "bigdecimal", + "byte-unit", + "chrono", + "derive-new", + "directories 2.0.2", + "dirs 2.0.2", + "getset", + "indexmap", + "log 0.4.11", + "nu-errors", + "nu-protocol", + "nu-source", + "nu-table", + "nu-value-ext", + "num-bigint", + "num-format", + "num-traits 0.2.12", + "parking_lot 0.11.0", + "query_interface", + "serde 1.0.115", + "toml 0.5.6", + "umask", + "users", +] + [[package]] name = "nu-errors" version = "0.18.2" @@ -3346,7 +3378,7 @@ version = "0.18.2" dependencies = [ "ansi_term 0.12.1", "bat", - "nu-cli", + "nu-data", "nu-errors", "nu-plugin", "nu-protocol", diff --git a/Cargo.toml b/Cargo.toml index 04dc57a94..94fe65af8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ members = ["crates/*/"] [dependencies] nu-cli = {version = "0.18.2", path = "./crates/nu-cli"} +nu-data = {version = "0.18.2", path = "./crates/nu-data"} nu-errors = {version = "0.18.2", path = "./crates/nu-errors"} nu-parser = {version = "0.18.2", path = "./crates/nu-parser"} nu-plugin = {version = "0.18.2", path = "./crates/nu-plugin"} @@ -101,7 +102,7 @@ s3 = ["nu_plugin_s3"] clipboard-cli = ["nu-cli/clipboard-cli"] ctrlc-support = ["nu-cli/ctrlc"] -directories-support = ["nu-cli/directories", "nu-cli/dirs"] +directories-support = ["nu-cli/directories", "nu-cli/dirs", "nu-data/directories", "nu-data/dirs"] git-support = ["nu-cli/git2"] ptree-support = ["nu-cli/ptree"] term-support = ["nu-cli/term"] diff --git a/crates/nu-cli/Cargo.toml b/crates/nu-cli/Cargo.toml index d669f5392..f21a6ede5 100644 --- a/crates/nu-cli/Cargo.toml +++ b/crates/nu-cli/Cargo.toml @@ -10,6 +10,7 @@ version = "0.18.2" doctest = false [dependencies] +nu-data = {version = "0.18.2", path = "../nu-data"} nu-errors = {version = "0.18.2", path = "../nu-errors"} nu-parser = {version = "0.18.2", path = "../nu-parser"} nu-plugin = {version = "0.18.2", path = "../nu-plugin"} diff --git a/crates/nu-cli/src/cli.rs b/crates/nu-cli/src/cli.rs index f5a22278d..8513ae7fb 100644 --- a/crates/nu-cli/src/cli.rs +++ b/crates/nu-cli/src/cli.rs @@ -111,7 +111,7 @@ fn search_paths() -> Vec { } } - if let Ok(config) = crate::data::config::config(Tag::unknown()) { + if let Ok(config) = nu_data::config::config(Tag::unknown()) { if let Some(plugin_dirs) = config.get("plugin_dirs") { if let Value { value: UntaggedValue::Table(pipelines), @@ -210,7 +210,7 @@ impl History { }) .unwrap_or_else(|_| PathBuf::from(FNAME)); - let cfg = crate::data::config::config(Tag::unknown()); + let cfg = nu_data::config::config(Tag::unknown()); if let Ok(c) = cfg { match &c.get("history-path") { Some(Value { @@ -471,7 +471,7 @@ pub async fn run_vec_of_pipelines( } // before we start up, let's run our startup commands - if let Ok(config) = crate::data::config::config(Tag::unknown()) { + if let Ok(config) = nu_data::config::config(Tag::unknown()) { if let Some(commands) = config.get("startup") { match commands { Value { @@ -752,7 +752,7 @@ pub async fn cli( let mut ctrlcbreak = false; // before we start up, let's run our startup commands - if let Ok(config) = crate::data::config::config(Tag::unknown()) { + if let Ok(config) = nu_data::config::config(Tag::unknown()) { if let Some(commands) = config.get("startup") { match commands { Value { diff --git a/crates/nu-cli/src/commands/alias.rs b/crates/nu-cli/src/commands/alias.rs index 81ee024a3..501844f38 100644 --- a/crates/nu-cli/src/commands/alias.rs +++ b/crates/nu-cli/src/commands/alias.rs @@ -1,7 +1,7 @@ use crate::commands::WholeStreamCommand; use crate::context::CommandRegistry; -use crate::data::config; use crate::prelude::*; +use nu_data::config; use nu_errors::ShellError; use nu_protocol::{ hir::Block, CommandAction, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value, @@ -82,7 +82,7 @@ pub async fn alias( let mut processed_args: Vec = vec![]; if let Some(true) = save { - let mut result = crate::data::config::read(name.clone().tag, &None)?; + let mut result = nu_data::config::read(name.clone().tag, &None)?; // process the alias to remove the --save flag let left_brace = raw_input.find('{').unwrap_or(0); diff --git a/crates/nu-cli/src/commands/autoview.rs b/crates/nu-cli/src/commands/autoview.rs index 1c49c4be6..c222c981c 100644 --- a/crates/nu-cli/src/commands/autoview.rs +++ b/crates/nu-cli/src/commands/autoview.rs @@ -1,10 +1,10 @@ use crate::commands::UnevaluatedCallInfo; use crate::commands::WholeStreamCommand; -use crate::data::config::table::AutoPivotMode; -use crate::data::config::table::HasTableProperties; -use crate::data::config::NuConfig as Configuration; -use crate::data::value::format_leaf; use crate::prelude::*; +use nu_data::config::table::AutoPivotMode; +use nu_data::config::table::HasTableProperties; +use nu_data::config::NuConfig as Configuration; +use nu_data::value::format_leaf; use nu_errors::ShellError; use nu_protocol::hir::{self, Expression, ExternalRedirection, Literal, SpannedExpression}; use nu_protocol::{Primitive, Scope, Signature, UntaggedValue, Value}; diff --git a/crates/nu-cli/src/commands/build_string.rs b/crates/nu-cli/src/commands/build_string.rs index 3420bb7ce..1ce63bf04 100644 --- a/crates/nu-cli/src/commands/build_string.rs +++ b/crates/nu-cli/src/commands/build_string.rs @@ -2,7 +2,7 @@ use crate::prelude::*; use nu_errors::ShellError; use crate::commands::WholeStreamCommand; -use crate::data::value::format_leaf; +use nu_data::value::format_leaf; use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; #[derive(Deserialize)] diff --git a/crates/nu-cli/src/commands/classified/external.rs b/crates/nu-cli/src/commands/classified/external.rs index a9589c959..f7bc01971 100644 --- a/crates/nu-cli/src/commands/classified/external.rs +++ b/crates/nu-cli/src/commands/classified/external.rs @@ -425,7 +425,7 @@ fn spawn( }; if external_failed { - let cfg = crate::data::config::config(Tag::unknown()); + let cfg = nu_data::config::config(Tag::unknown()); if let Ok(cfg) = cfg { if cfg.contains_key("nonzero_exit_errors") { let _ = stdout_read_tx.send(Ok(Value { diff --git a/crates/nu-cli/src/commands/config/clear.rs b/crates/nu-cli/src/commands/config/clear.rs index 53501255d..b37523602 100644 --- a/crates/nu-cli/src/commands/config/clear.rs +++ b/crates/nu-cli/src/commands/config/clear.rs @@ -45,7 +45,7 @@ pub async fn clear( // NOTE: None because we are not loading a new config file, we just want to read from the // existing config - let mut result = crate::data::config::read(name_span, &None)?; + let mut result = nu_data::config::read(name_span, &None)?; result.clear(); diff --git a/crates/nu-cli/src/commands/config/command.rs b/crates/nu-cli/src/commands/config/command.rs index 854f3cd0a..c014da064 100644 --- a/crates/nu-cli/src/commands/config/command.rs +++ b/crates/nu-cli/src/commands/config/command.rs @@ -27,7 +27,7 @@ impl WholeStreamCommand for Command { ) -> Result { let name_span = args.call_info.name_tag.clone(); let name = args.call_info.name_tag; - let result = crate::data::config::read(name_span, &None)?; + let result = nu_data::config::read(name_span, &None)?; Ok(futures::stream::iter(vec![ReturnSuccess::value( UntaggedValue::Row(result.into()).into_value(name), diff --git a/crates/nu-cli/src/commands/config/get.rs b/crates/nu-cli/src/commands/config/get.rs index d947a2d20..8c8202621 100644 --- a/crates/nu-cli/src/commands/config/get.rs +++ b/crates/nu-cli/src/commands/config/get.rs @@ -56,7 +56,7 @@ pub async fn get( // NOTE: None because we are not loading a new config file, we just want to read from the // existing config - let result = crate::data::config::read(name_span, &None)?; + let result = nu_data::config::read(name_span, &None)?; let key = get.to_string(); let value = result diff --git a/crates/nu-cli/src/commands/config/load.rs b/crates/nu-cli/src/commands/config/load.rs index 2c49fc777..d09acec30 100644 --- a/crates/nu-cli/src/commands/config/load.rs +++ b/crates/nu-cli/src/commands/config/load.rs @@ -50,7 +50,7 @@ pub async fn set( let configuration = load.item().clone(); - let result = crate::data::config::read(name_span, &Some(configuration))?; + let result = nu_data::config::read(name_span, &Some(configuration))?; Ok(futures::stream::iter(vec![ReturnSuccess::value( UntaggedValue::Row(result.into()).into_value(name), diff --git a/crates/nu-cli/src/commands/config/remove.rs b/crates/nu-cli/src/commands/config/remove.rs index 9fd33f93a..602580d78 100644 --- a/crates/nu-cli/src/commands/config/remove.rs +++ b/crates/nu-cli/src/commands/config/remove.rs @@ -54,7 +54,7 @@ pub async fn remove( let name_span = args.call_info.name_tag.clone(); let (RemoveArgs { remove }, _) = args.process(®istry).await?; - let mut result = crate::data::config::read(name_span, &None)?; + let mut result = nu_data::config::read(name_span, &None)?; let key = remove.to_string(); diff --git a/crates/nu-cli/src/commands/config/set.rs b/crates/nu-cli/src/commands/config/set.rs index 7eda77b64..76bcd2dc6 100644 --- a/crates/nu-cli/src/commands/config/set.rs +++ b/crates/nu-cli/src/commands/config/set.rs @@ -55,7 +55,7 @@ pub async fn set( // NOTE: None because we are not loading a new config file, we just want to read from the // existing config - let mut result = crate::data::config::read(name_span, &None)?; + let mut result = nu_data::config::read(name_span, &None)?; result.insert(key.to_string(), value.clone()); diff --git a/crates/nu-cli/src/commands/config/set_into.rs b/crates/nu-cli/src/commands/config/set_into.rs index 6210cc095..da8fe4f3e 100644 --- a/crates/nu-cli/src/commands/config/set_into.rs +++ b/crates/nu-cli/src/commands/config/set_into.rs @@ -58,7 +58,7 @@ pub async fn set_into( // NOTE: None because we are not loading a new config file, we just want to read from the // existing config - let mut result = crate::data::config::read(name_span, &None)?; + let mut result = nu_data::config::read(name_span, &None)?; // In the original code, this is set to `Some` if the `load flag is set` let configuration = None; diff --git a/crates/nu-cli/src/commands/echo.rs b/crates/nu-cli/src/commands/echo.rs index 1073d883f..af05c9567 100644 --- a/crates/nu-cli/src/commands/echo.rs +++ b/crates/nu-cli/src/commands/echo.rs @@ -102,7 +102,7 @@ impl Iterator for RangeIterator { if self.curr != self.end { let output = UntaggedValue::Primitive(self.curr.clone()).into_value(self.tag.clone()); - self.curr = match crate::data::value::compute_values( + self.curr = match nu_data::value::compute_values( Operator::Plus, &UntaggedValue::Primitive(self.curr.clone()), &UntaggedValue::int(1), diff --git a/crates/nu-cli/src/commands/from_ods.rs b/crates/nu-cli/src/commands/from_ods.rs index 94c42f010..138eed4b6 100644 --- a/crates/nu-cli/src/commands/from_ods.rs +++ b/crates/nu-cli/src/commands/from_ods.rs @@ -1,7 +1,7 @@ use crate::commands::WholeStreamCommand; use crate::prelude::*; -use crate::TaggedListBuilder; use calamine::*; +use nu_data::TaggedListBuilder; use nu_errors::ShellError; use nu_protocol::{ReturnSuccess, Signature, TaggedDictBuilder, UntaggedValue}; use std::io::Cursor; diff --git a/crates/nu-cli/src/commands/from_xlsx.rs b/crates/nu-cli/src/commands/from_xlsx.rs index c518837ef..f23c773bd 100644 --- a/crates/nu-cli/src/commands/from_xlsx.rs +++ b/crates/nu-cli/src/commands/from_xlsx.rs @@ -1,7 +1,7 @@ use crate::commands::WholeStreamCommand; use crate::prelude::*; -use crate::TaggedListBuilder; use calamine::*; +use nu_data::TaggedListBuilder; use nu_errors::ShellError; use nu_protocol::{ReturnSuccess, Signature, TaggedDictBuilder, UntaggedValue}; use std::io::Cursor; diff --git a/crates/nu-cli/src/commands/group_by.rs b/crates/nu-cli/src/commands/group_by.rs index 9544e165a..d5449f04d 100644 --- a/crates/nu-cli/src/commands/group_by.rs +++ b/crates/nu-cli/src/commands/group_by.rs @@ -179,7 +179,7 @@ pub async fn group_by( None => as_string(row), }); - crate::utils::data::group(&values, &Some(block), &name) + nu_data::utils::group(&values, &Some(block), &name) } Grouper::ByColumn(column_name) => group(&column_name, &values, name), }; @@ -234,12 +234,12 @@ pub fn group( } }); - crate::utils::data::group(&values, &Some(block), &name) + nu_data::utils::group(&values, &Some(block), &name) } Grouper::ByColumn(None) => { let block = Box::new(move |_, row: &Value| as_string(row)); - crate::utils::data::group(&values, &Some(block), &name) + nu_data::utils::group(&values, &Some(block), &name) } Grouper::ByBlock => Err(ShellError::unimplemented( "Block not implemented: This should never happen.", @@ -250,7 +250,7 @@ pub fn group( #[cfg(test)] mod tests { use super::group; - use crate::utils::data::helpers::{committers, date, int, row, string, table}; + use nu_data::utils::helpers::{committers, date, int, row, string, table}; use nu_errors::ShellError; use nu_source::*; diff --git a/crates/nu-cli/src/commands/group_by_date.rs b/crates/nu-cli/src/commands/group_by_date.rs index f69965182..834443dff 100644 --- a/crates/nu-cli/src/commands/group_by_date.rs +++ b/crates/nu-cli/src/commands/group_by_date.rs @@ -102,7 +102,7 @@ pub async fn group_by_date( (Grouper::ByDate(None), GroupByColumn::Name(None)) => { let block = Box::new(move |_, row: &Value| row.format("%Y-%m-%d")); - crate::utils::data::group(&values, &Some(block), &name) + nu_data::utils::group(&values, &Some(block), &name) } (Grouper::ByDate(None), GroupByColumn::Name(Some(column_name))) => { let block = Box::new(move |_, row: &Value| { @@ -113,12 +113,12 @@ pub async fn group_by_date( group_key?.format("%Y-%m-%d") }); - crate::utils::data::group(&values, &Some(block), &name) + nu_data::utils::group(&values, &Some(block), &name) } (Grouper::ByDate(Some(fmt)), GroupByColumn::Name(None)) => { let block = Box::new(move |_, row: &Value| row.format(&fmt)); - crate::utils::data::group(&values, &Some(block), &name) + nu_data::utils::group(&values, &Some(block), &name) } (Grouper::ByDate(Some(fmt)), GroupByColumn::Name(Some(column_name))) => { let block = Box::new(move |_, row: &Value| { @@ -129,7 +129,7 @@ pub async fn group_by_date( group_key?.format(&fmt) }); - crate::utils::data::group(&values, &Some(block), &name) + nu_data::utils::group(&values, &Some(block), &name) } }; diff --git a/crates/nu-cli/src/commands/help.rs b/crates/nu-cli/src/commands/help.rs index 6c2f15434..dd9afe30e 100644 --- a/crates/nu-cli/src/commands/help.rs +++ b/crates/nu-cli/src/commands/help.rs @@ -1,10 +1,10 @@ +use crate::commands::command::Command; use crate::commands::WholeStreamCommand; -use crate::data::command_dict; use crate::documentation::{generate_docs, get_documentation, DocumentationConfig}; - use crate::prelude::*; +use nu_data::command::signature_dict; use nu_errors::ShellError; -use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, TaggedDictBuilder, UntaggedValue}; +use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, TaggedDictBuilder, UntaggedValue, Value}; use nu_source::{SpannedItem, Tagged}; use nu_value_ext::get_data_by_key; @@ -38,6 +38,21 @@ impl WholeStreamCommand for Help { } } +pub(crate) fn command_dict(command: Command, tag: impl Into) -> Value { + let tag = tag.into(); + + let mut cmd_dict = TaggedDictBuilder::new(&tag); + + cmd_dict.insert_untagged("name", UntaggedValue::string(command.name())); + + cmd_dict.insert_untagged("type", UntaggedValue::string("Command")); + + cmd_dict.insert_value("signature", signature_dict(command.signature(), tag)); + cmd_dict.insert_untagged("usage", UntaggedValue::string(command.usage())); + + cmd_dict.into_value() +} + async fn help(args: CommandArgs, registry: &CommandRegistry) -> Result { let registry = registry.clone(); let name = args.call_info.name_tag.clone(); diff --git a/crates/nu-cli/src/commands/histogram.rs b/crates/nu-cli/src/commands/histogram.rs index fc67c1e2d..ae1d94457 100644 --- a/crates/nu-cli/src/commands/histogram.rs +++ b/crates/nu-cli/src/commands/histogram.rs @@ -107,9 +107,9 @@ pub async fn histogram( "value".to_string().tagged(&name) }; - let results = crate::utils::data::report( + let results = nu_data::utils::report( &UntaggedValue::table(&values).into_value(&name), - crate::utils::data::Operation { + nu_data::utils::Operation { grouper: Some(Box::new(move |_, _| Ok(String::from("frequencies")))), splitter: Some(splitter(column_grouper)), format: None, diff --git a/crates/nu-cli/src/commands/macros.rs b/crates/nu-cli/src/commands/macros.rs index c79d980b8..f61e3402b 100644 --- a/crates/nu-cli/src/commands/macros.rs +++ b/crates/nu-cli/src/commands/macros.rs @@ -266,7 +266,7 @@ macro_rules! command { Extract { $($extract:tt)* { - use $crate::data::types::ExtractType; + use $nu_data::types::ExtractType; let value = $args.expect_nth($($positional_count)*)?; Block::extract(value)? } @@ -321,7 +321,7 @@ macro_rules! command { Extract { $($extract:tt)* { - use $crate::data::types::ExtractType; + use $nu_data::types::ExtractType; let value = $args.expect_nth($($positional_count)*)?; <$param_kind>::extract(&value)? } diff --git a/crates/nu-cli/src/commands/math/avg.rs b/crates/nu-cli/src/commands/math/avg.rs index ca23a06df..5f8962091 100644 --- a/crates/nu-cli/src/commands/math/avg.rs +++ b/crates/nu-cli/src/commands/math/avg.rs @@ -118,7 +118,7 @@ pub fn average(values: &[Value], name: &Tag) -> Result { .. } => { let left = UntaggedValue::from(Primitive::Int(num.into())); - let result = crate::data::value::compute_values(Operator::Divide, &left, &total_rows); + let result = nu_data::value::compute_values(Operator::Divide, &left, &total_rows); match result { Ok(UntaggedValue::Primitive(Primitive::Decimal(result))) => { @@ -142,7 +142,7 @@ pub fn average(values: &[Value], name: &Tag) -> Result { .. } => { let left = UntaggedValue::from(other); - let result = crate::data::value::compute_values(Operator::Divide, &left, &total_rows); + let result = nu_data::value::compute_values(Operator::Divide, &left, &total_rows); match result { Ok(value) => Ok(value.into_value(name)), diff --git a/crates/nu-cli/src/commands/math/median.rs b/crates/nu-cli/src/commands/math/median.rs index 477911769..d5f91b37f 100644 --- a/crates/nu-cli/src/commands/math/median.rs +++ b/crates/nu-cli/src/commands/math/median.rs @@ -138,7 +138,7 @@ fn compute_average(values: &[Value], name: impl Into) -> Result { let left = UntaggedValue::from(Primitive::Int(num.into())); - let result = crate::data::value::compute_values(Operator::Divide, &left, &total_rows); + let result = nu_data::value::compute_values(Operator::Divide, &left, &total_rows); match result { Ok(UntaggedValue::Primitive(Primitive::Decimal(result))) => { @@ -162,7 +162,7 @@ fn compute_average(values: &[Value], name: impl Into) -> Result { let left = UntaggedValue::from(other); - let result = crate::data::value::compute_values(Operator::Divide, &left, &total_rows); + let result = nu_data::value::compute_values(Operator::Divide, &left, &total_rows); match result { Ok(value) => Ok(value.into_value(name)), diff --git a/crates/nu-cli/src/commands/math/reducers.rs b/crates/nu-cli/src/commands/math/reducers.rs index 1170bda85..faa5d6ba7 100644 --- a/crates/nu-cli/src/commands/math/reducers.rs +++ b/crates/nu-cli/src/commands/math/reducers.rs @@ -1,4 +1,4 @@ -use crate::data::value::{compare_values, compute_values}; +use nu_data::value::{compare_values, compute_values}; use nu_errors::ShellError; use nu_protocol::hir::Operator; use nu_protocol::{UntaggedValue, Value}; diff --git a/crates/nu-cli/src/commands/math/variance.rs b/crates/nu-cli/src/commands/math/variance.rs index 59dda37ec..b081b8050 100644 --- a/crates/nu-cli/src/commands/math/variance.rs +++ b/crates/nu-cli/src/commands/math/variance.rs @@ -1,7 +1,7 @@ use crate::commands::WholeStreamCommand; -use crate::data::value::compute_values; use crate::prelude::*; use bigdecimal::FromPrimitive; +use nu_data::value::compute_values; use nu_errors::ShellError; use nu_protocol::{ hir::Operator, Dictionary, Primitive, ReturnSuccess, Signature, UntaggedValue, Value, diff --git a/crates/nu-cli/src/commands/merge.rs b/crates/nu-cli/src/commands/merge.rs index 6cf6178d7..97db41301 100644 --- a/crates/nu-cli/src/commands/merge.rs +++ b/crates/nu-cli/src/commands/merge.rs @@ -1,8 +1,8 @@ use crate::commands::classified::block::run_block; use crate::commands::WholeStreamCommand; use crate::context::CommandRegistry; -use crate::data::value::merge_values; use crate::prelude::*; +use nu_data::value::merge_values; use indexmap::IndexMap; use nu_errors::ShellError; diff --git a/crates/nu-cli/src/commands/move_/column.rs b/crates/nu-cli/src/commands/move_/column.rs index 563be0a55..32fcf0129 100644 --- a/crates/nu-cli/src/commands/move_/column.rs +++ b/crates/nu-cli/src/commands/move_/column.rs @@ -1,7 +1,7 @@ use crate::commands::WholeStreamCommand; use crate::context::CommandRegistry; -use crate::data::base::select_fields; use crate::prelude::*; +use nu_data::base::select_fields; use nu_errors::ShellError; use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, Value}; use nu_source::span_for_spanned_list; diff --git a/crates/nu-cli/src/commands/path/type.rs b/crates/nu-cli/src/commands/path/type.rs index 9b1b019a4..d044af22b 100644 --- a/crates/nu-cli/src/commands/path/type.rs +++ b/crates/nu-cli/src/commands/path/type.rs @@ -1,7 +1,7 @@ use super::{operate, DefaultArguments}; use crate::commands::WholeStreamCommand; -use crate::data::files::get_file_type; use crate::prelude::*; +use crate::shell::filesystem_shell::get_file_type; use nu_errors::ShellError; use nu_protocol::{Signature, SyntaxShape, UntaggedValue, Value}; use std::path::Path; diff --git a/crates/nu-cli/src/commands/reject.rs b/crates/nu-cli/src/commands/reject.rs index a3ff4899b..1498b382f 100644 --- a/crates/nu-cli/src/commands/reject.rs +++ b/crates/nu-cli/src/commands/reject.rs @@ -1,6 +1,6 @@ use crate::commands::WholeStreamCommand; -use crate::data::base::reject_fields; use crate::prelude::*; +use nu_data::base::reject_fields; use nu_errors::ShellError; use nu_protocol::{ReturnSuccess, Signature, SyntaxShape}; use nu_source::Tagged; diff --git a/crates/nu-cli/src/commands/sort_by.rs b/crates/nu-cli/src/commands/sort_by.rs index 671e7b778..af096cce0 100644 --- a/crates/nu-cli/src/commands/sort_by.rs +++ b/crates/nu-cli/src/commands/sort_by.rs @@ -1,6 +1,6 @@ use crate::commands::WholeStreamCommand; -use crate::data::base::coerce_compare; use crate::prelude::*; +use nu_data::base::coerce_compare; use nu_errors::ShellError; use nu_protocol::{Signature, SyntaxShape, UntaggedValue, Value}; use nu_source::Tagged; diff --git a/crates/nu-cli/src/commands/split_by.rs b/crates/nu-cli/src/commands/split_by.rs index c0239a2f1..5ce75be9f 100644 --- a/crates/nu-cli/src/commands/split_by.rs +++ b/crates/nu-cli/src/commands/split_by.rs @@ -86,12 +86,12 @@ pub fn split( } }); - crate::utils::data::split(&values, &Some(block), &name) + nu_data::utils::split(&values, &Some(block), &name) } Grouper::ByColumn(None) => { let block = Box::new(move |_, row: &Value| as_string(row)); - crate::utils::data::split(&values, &Some(block), &name) + nu_data::utils::split(&values, &Some(block), &name) } } } @@ -124,7 +124,7 @@ pub fn suggestions(tried: Tagged<&str>, for_value: &Value) -> ShellError { #[cfg(test)] mod tests { use super::split; - use crate::utils::data::helpers::{committers_grouped_by_date, date, int, row, string, table}; + use nu_data::utils::helpers::{committers_grouped_by_date, date, int, row, string, table}; use nu_protocol::UntaggedValue; use nu_source::*; diff --git a/crates/nu-cli/src/commands/table.rs b/crates/nu-cli/src/commands/table.rs index ba6e2e66a..a57e56b72 100644 --- a/crates/nu-cli/src/commands/table.rs +++ b/crates/nu-cli/src/commands/table.rs @@ -1,8 +1,8 @@ use crate::commands::WholeStreamCommand; -use crate::data::config::table::HasTableProperties; -use crate::data::config::NuConfig as TableConfiguration; -use crate::data::value::{format_leaf, style_leaf}; use crate::prelude::*; +use nu_data::config::table::HasTableProperties; +use nu_data::config::NuConfig as TableConfiguration; +use nu_data::value::{format_leaf, style_leaf}; use nu_errors::ShellError; use nu_protocol::{Primitive, Signature, SyntaxShape, UntaggedValue, Value}; use nu_table::{draw_table, Alignment, StyledString, TextStyle}; diff --git a/crates/nu-cli/src/commands/to_html.rs b/crates/nu-cli/src/commands/to_html.rs index 3ac3b034f..74715af5b 100644 --- a/crates/nu-cli/src/commands/to_html.rs +++ b/crates/nu-cli/src/commands/to_html.rs @@ -1,7 +1,7 @@ use crate::commands::WholeStreamCommand; -use crate::data::value::format_leaf; use crate::prelude::*; use futures::StreamExt; +use nu_data::value::format_leaf; use nu_errors::ShellError; use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value}; use nu_source::{AnchorLocation, Tagged}; diff --git a/crates/nu-cli/src/commands/to_md.rs b/crates/nu-cli/src/commands/to_md.rs index 587390abc..1cf8d200a 100644 --- a/crates/nu-cli/src/commands/to_md.rs +++ b/crates/nu-cli/src/commands/to_md.rs @@ -1,7 +1,7 @@ use crate::commands::WholeStreamCommand; -use crate::data::value::format_leaf; use crate::prelude::*; use futures::StreamExt; +use nu_data::value::format_leaf; use nu_errors::ShellError; use nu_protocol::{ReturnSuccess, Signature, UntaggedValue, Value}; diff --git a/crates/nu-cli/src/commands/version.rs b/crates/nu-cli/src/commands/version.rs index 47bd73c98..5d3eaa5de 100644 --- a/crates/nu-cli/src/commands/version.rs +++ b/crates/nu-cli/src/commands/version.rs @@ -1,7 +1,7 @@ use crate::commands::WholeStreamCommand; use crate::prelude::*; -use crate::TaggedListBuilder; use indexmap::IndexMap; +use nu_data::TaggedListBuilder; use nu_errors::ShellError; use nu_protocol::{Dictionary, Signature, UntaggedValue}; diff --git a/crates/nu-cli/src/data.rs b/crates/nu-cli/src/data.rs deleted file mode 100644 index 4269aef91..000000000 --- a/crates/nu-cli/src/data.rs +++ /dev/null @@ -1,12 +0,0 @@ -pub(crate) mod base; -pub(crate) mod command; -pub mod config; -pub(crate) mod dict; -pub(crate) mod files; -pub mod primitive; -pub(crate) mod types; -pub mod value; - -pub(crate) use command::command_dict; -pub(crate) use dict::TaggedListBuilder; -pub(crate) use files::dir_entry_dict; diff --git a/crates/nu-cli/src/data/config.rs b/crates/nu-cli/src/data/config.rs deleted file mode 100644 index d9de93372..000000000 --- a/crates/nu-cli/src/data/config.rs +++ /dev/null @@ -1,164 +0,0 @@ -mod conf; -mod nuconfig; -pub mod table; - -#[cfg(test)] -pub mod tests; - -pub(crate) use conf::Conf; -pub(crate) use nuconfig::NuConfig; - -use crate::commands::from_toml::convert_toml_value_to_nu_value; -use crate::commands::to_toml::value_to_toml_value; -use crate::prelude::*; -use indexmap::IndexMap; -use log::trace; -use nu_errors::ShellError; -use nu_protocol::{Dictionary, ShellTypeName, UntaggedValue, Value}; -use nu_source::Tag; -use std::fs::{self, OpenOptions}; -use std::io; -use std::path::{Path, PathBuf}; - -#[cfg(feature = "directories")] -pub fn config_path() -> Result { - use directories::ProjectDirs; - - let dir = ProjectDirs::from("org", "nushell", "nu") - .ok_or_else(|| ShellError::untagged_runtime_error("Couldn't find project directory"))?; - let path = ProjectDirs::config_dir(&dir).to_owned(); - std::fs::create_dir_all(&path).map_err(|err| { - ShellError::untagged_runtime_error(&format!("Couldn't create {} path:\n{}", "config", err)) - })?; - - Ok(path) -} - -#[cfg(not(feature = "directories"))] -pub fn config_path() -> Result { - // FIXME: unsure if this should be error or a simple default - - Ok(std::path::PathBuf::from("/")) -} - -pub fn default_path() -> Result { - default_path_for(&None) -} - -pub fn default_path_for(file: &Option) -> Result { - let mut filename = config_path()?; - let file: &Path = file - .as_ref() - .map(AsRef::as_ref) - .unwrap_or_else(|| "config.toml".as_ref()); - filename.push(file); - - Ok(filename) -} - -#[cfg(feature = "directories")] -pub fn user_data() -> Result { - use directories::ProjectDirs; - - let dir = ProjectDirs::from("org", "nushell", "nu") - .ok_or_else(|| ShellError::untagged_runtime_error("Couldn't find project directory"))?; - let path = ProjectDirs::data_local_dir(&dir).to_owned(); - std::fs::create_dir_all(&path).map_err(|err| { - ShellError::untagged_runtime_error(&format!( - "Couldn't create {} path:\n{}", - "user data", err - )) - })?; - - Ok(path) -} - -#[cfg(not(feature = "directories"))] -pub fn user_data() -> Result { - // FIXME: unsure if this should be error or a simple default - - Ok(std::path::PathBuf::from("/")) -} - -pub fn read( - tag: impl Into, - at: &Option, -) -> Result, ShellError> { - let filename = default_path()?; - - let filename = match at { - None => filename, - Some(ref file) => file.clone(), - }; - - if !filename.exists() && touch(&filename).is_err() { - // If we can't create configs, let's just return an empty indexmap instead as we may be in - // a readonly environment - return Ok(IndexMap::new()); - } - - trace!("config file = {}", filename.display()); - - let tag = tag.into(); - let contents = fs::read_to_string(filename) - .map(|v| v.tagged(&tag)) - .map_err(|err| { - ShellError::labeled_error( - &format!("Couldn't read config file:\n{}", err), - "file name", - &tag, - ) - })?; - - let parsed: toml::Value = toml::from_str(&contents).map_err(|err| { - ShellError::labeled_error( - &format!("Couldn't parse config file:\n{}", err), - "file name", - &tag, - ) - })?; - - let value = convert_toml_value_to_nu_value(&parsed, tag); - let tag = value.tag(); - match value.value { - UntaggedValue::Row(Dictionary { entries }) => Ok(entries), - other => Err(ShellError::type_error( - "Dictionary", - other.type_name().spanned(tag.span), - )), - } -} - -pub fn config(tag: impl Into) -> Result, ShellError> { - read(tag, &None) -} - -pub fn write(config: &IndexMap, at: &Option) -> Result<(), ShellError> { - let filename = &mut default_path()?; - let filename = match at { - None => filename, - Some(file) => { - filename.pop(); - filename.push(file); - filename - } - }; - - let contents = value_to_toml_value( - &UntaggedValue::Row(Dictionary::new(config.clone())).into_untagged_value(), - )?; - - let contents = toml::to_string(&contents)?; - - fs::write(&filename, &contents)?; - - Ok(()) -} - -// A simple implementation of `% touch path` (ignores existing files) -fn touch(path: &Path) -> io::Result<()> { - match OpenOptions::new().create(true).write(true).open(path) { - Ok(_) => Ok(()), - Err(e) => Err(e), - } -} diff --git a/crates/nu-cli/src/data/files.rs b/crates/nu-cli/src/data/files.rs deleted file mode 100644 index ce93f5577..000000000 --- a/crates/nu-cli/src/data/files.rs +++ /dev/null @@ -1,199 +0,0 @@ -use crate::commands::du::{DirBuilder, DirInfo}; -use crate::prelude::*; -use nu_errors::ShellError; -use nu_protocol::{TaggedDictBuilder, UntaggedValue, Value}; - -#[cfg(unix)] -use std::os::unix::fs::FileTypeExt; - -pub(crate) fn get_file_type(md: &std::fs::Metadata) -> &str { - let ft = md.file_type(); - let mut file_type = "Unknown"; - if ft.is_dir() { - file_type = "Dir"; - } else if ft.is_file() { - file_type = "File"; - } else if ft.is_symlink() { - file_type = "Symlink"; - } else { - #[cfg(unix)] - { - if ft.is_block_device() { - file_type = "Block device"; - } else if ft.is_char_device() { - file_type = "Char device"; - } else if ft.is_fifo() { - file_type = "Pipe"; - } else if ft.is_socket() { - file_type = "Socket"; - } - } - } - file_type -} - -#[allow(clippy::too_many_arguments)] -pub(crate) fn dir_entry_dict( - filename: &std::path::Path, - metadata: Option<&std::fs::Metadata>, - tag: impl Into, - long: bool, - short_name: bool, - du: bool, - ctrl_c: Arc, -) -> Result { - let tag = tag.into(); - let mut dict = TaggedDictBuilder::new(&tag); - // Insert all columns first to maintain proper table alignment if we can't find (or are not allowed to view) any information - if long { - #[cfg(windows)] - { - for column in [ - "name", "type", "target", "readonly", "size", "created", "accessed", "modified", - ] - .iter() - { - dict.insert_untagged(*column, UntaggedValue::nothing()); - } - } - - #[cfg(unix)] - { - for column in [ - "name", "type", "target", "readonly", "mode", "uid", "group", "size", "created", - "accessed", "modified", - ] - .iter() - { - dict.insert_untagged(&(*column.to_owned()), UntaggedValue::nothing()); - } - } - } else { - for column in ["name", "type", "target", "size", "modified"].iter() { - if *column == "target" { - continue; - } - dict.insert_untagged(*column, UntaggedValue::nothing()); - } - } - - let name = if short_name { - filename.file_name().and_then(|s| s.to_str()) - } else { - filename.to_str() - } - .ok_or_else(|| { - ShellError::labeled_error( - format!("Invalid file name: {:}", filename.to_string_lossy()), - "invalid file name", - tag, - ) - })?; - - dict.insert_untagged("name", UntaggedValue::string(name)); - - if let Some(md) = metadata { - dict.insert_untagged("type", get_file_type(md)); - } - - if long { - if let Some(md) = metadata { - if md.file_type().is_symlink() { - let symlink_target_untagged_value: UntaggedValue; - if let Ok(path_to_link) = filename.read_link() { - symlink_target_untagged_value = - UntaggedValue::string(path_to_link.to_string_lossy()); - } else { - symlink_target_untagged_value = - UntaggedValue::string("Could not obtain target file's path"); - } - dict.insert_untagged("target", symlink_target_untagged_value); - } - } - } - - if long { - if let Some(md) = metadata { - dict.insert_untagged( - "readonly", - UntaggedValue::boolean(md.permissions().readonly()), - ); - - #[cfg(unix)] - { - use std::os::unix::fs::MetadataExt; - use std::os::unix::fs::PermissionsExt; - let mode = md.permissions().mode(); - dict.insert_untagged( - "mode", - UntaggedValue::string(umask::Mode::from(mode).to_string()), - ); - - if let Some(user) = users::get_user_by_uid(md.uid()) { - dict.insert_untagged( - "uid", - UntaggedValue::string(user.name().to_string_lossy()), - ); - } - - if let Some(group) = users::get_group_by_gid(md.gid()) { - dict.insert_untagged( - "group", - UntaggedValue::string(group.name().to_string_lossy()), - ); - } - } - } - } - - if let Some(md) = metadata { - let mut size_untagged_value: UntaggedValue = UntaggedValue::nothing(); - - if md.is_dir() { - let dir_size: u64 = if du { - let params = DirBuilder::new( - Tag { - anchor: None, - span: Span::new(0, 2), - }, - None, - false, - None, - false, - ); - - DirInfo::new(filename, ¶ms, None, ctrl_c).get_size() - } else { - md.len() - }; - - size_untagged_value = UntaggedValue::filesize(dir_size); - } else if md.is_file() { - size_untagged_value = UntaggedValue::filesize(md.len()); - } else if md.file_type().is_symlink() { - if let Ok(symlink_md) = filename.symlink_metadata() { - size_untagged_value = UntaggedValue::filesize(symlink_md.len() as u64); - } - } - - dict.insert_untagged("size", size_untagged_value); - } - - if let Some(md) = metadata { - if long { - if let Ok(c) = md.created() { - dict.insert_untagged("created", UntaggedValue::system_date(c)); - } - - if let Ok(a) = md.accessed() { - dict.insert_untagged("accessed", UntaggedValue::system_date(a)); - } - } - - if let Ok(m) = md.modified() { - dict.insert_untagged("modified", UntaggedValue::system_date(m)); - } - } - - Ok(dict.into_value()) -} diff --git a/crates/nu-cli/src/env/environment.rs b/crates/nu-cli/src/env/environment.rs index 0993cdd92..3bdbbc7ea 100644 --- a/crates/nu-cli/src/env/environment.rs +++ b/crates/nu-cli/src/env/environment.rs @@ -1,6 +1,6 @@ -use crate::data::config::Conf; use crate::env::directory_specific_environment::*; use indexmap::{indexmap, IndexSet}; +use nu_data::config::Conf; use nu_errors::ShellError; use nu_protocol::{UntaggedValue, Value}; use std::env::*; @@ -154,7 +154,7 @@ impl Env for Environment { #[cfg(test)] mod tests { use super::{Env, Environment}; - use crate::data::config::{tests::FakeConfig, Conf}; + use nu_data::config::{tests::FakeConfig, Conf}; use nu_protocol::UntaggedValue; use nu_test_support::fs::Stub::FileWithContent; use nu_test_support::playground::Playground; diff --git a/crates/nu-cli/src/env/environment_syncer.rs b/crates/nu-cli/src/env/environment_syncer.rs index fc761e130..c7b847a30 100644 --- a/crates/nu-cli/src/env/environment_syncer.rs +++ b/crates/nu-cli/src/env/environment_syncer.rs @@ -1,5 +1,5 @@ use crate::context::Context; -use crate::data::config::{Conf, NuConfig}; +use nu_data::config::{Conf, NuConfig}; use crate::env::environment::{Env, Environment}; use nu_source::Text; @@ -128,9 +128,9 @@ impl EnvironmentSyncer { mod tests { use super::EnvironmentSyncer; use crate::context::Context; - use crate::data::config::tests::FakeConfig; use crate::env::environment::Env; use indexmap::IndexMap; + use nu_data::config::tests::FakeConfig; use nu_errors::ShellError; use nu_test_support::fs::Stub::FileWithContent; use nu_test_support::playground::Playground; diff --git a/crates/nu-cli/src/evaluate/operator.rs b/crates/nu-cli/src/evaluate/operator.rs index 9350172b5..c5bfee949 100644 --- a/crates/nu-cli/src/evaluate/operator.rs +++ b/crates/nu-cli/src/evaluate/operator.rs @@ -1,4 +1,4 @@ -use crate::data::value; +use nu_data::value; use nu_errors::ShellError; use nu_protocol::hir::Operator; use nu_protocol::{Primitive, ShellTypeName, UntaggedValue, Value}; diff --git a/crates/nu-cli/src/evaluate/variables.rs b/crates/nu-cli/src/evaluate/variables.rs index 33c7f51a1..94f77fcda 100644 --- a/crates/nu-cli/src/evaluate/variables.rs +++ b/crates/nu-cli/src/evaluate/variables.rs @@ -17,7 +17,7 @@ pub fn nu(env: &IndexMap, tag: impl Into) -> Result, tag: impl Into) -> Result; pub(crate) fn keybinding_path() -> Result { - crate::data::config::default_path_for(&Some(std::path::PathBuf::from("keybindings.yml"))) + nu_data::config::default_path_for(&Some(std::path::PathBuf::from("keybindings.yml"))) } pub(crate) fn load_keybindings( diff --git a/crates/nu-cli/src/lib.rs b/crates/nu-cli/src/lib.rs index 1d2690b54..2329597d8 100644 --- a/crates/nu-cli/src/lib.rs +++ b/crates/nu-cli/src/lib.rs @@ -17,7 +17,6 @@ mod cli; mod commands; mod completion; mod context; -pub mod data; mod deserializer; mod documentation; mod env; @@ -43,14 +42,14 @@ pub use crate::commands::command::{ }; pub use crate::commands::help::get_help; pub use crate::context::{CommandRegistry, Context}; -pub use crate::data::config; -pub use crate::data::dict::TaggedListBuilder; -pub use crate::data::primitive; -pub use crate::data::value; pub use crate::env::environment_syncer::EnvironmentSyncer; pub use crate::env::host::BasicHost; pub use crate::prelude::ToOutputStream; pub use crate::stream::{InputStream, InterruptibleStream, OutputStream}; +pub use nu_data::config; +pub use nu_data::dict::TaggedListBuilder; +pub use nu_data::primitive; +pub use nu_data::value; pub use nu_value_ext::ValueExt; pub use num_traits::cast::ToPrimitive; diff --git a/crates/nu-cli/src/prelude.rs b/crates/nu-cli/src/prelude.rs index ce58148b6..601e71f7d 100644 --- a/crates/nu-cli/src/prelude.rs +++ b/crates/nu-cli/src/prelude.rs @@ -75,8 +75,8 @@ pub(crate) use crate::commands::command::{CommandArgs, RawCommandArgs, RunnableC pub(crate) use crate::commands::Example; pub(crate) use crate::context::CommandRegistry; pub(crate) use crate::context::Context; -pub(crate) use crate::data::config; -pub(crate) use crate::data::value; +pub(crate) use nu_data::config; +pub(crate) use nu_data::value; // pub(crate) use crate::env::host::handle_unexpected; pub(crate) use crate::env::Host; pub(crate) use crate::shell::filesystem_shell::FilesystemShell; @@ -87,7 +87,6 @@ pub(crate) use crate::stream::{InputStream, InterruptibleStream, OutputStream}; pub(crate) use bigdecimal::BigDecimal; pub(crate) use futures::stream::BoxStream; pub(crate) use futures::{Stream, StreamExt}; -pub(crate) use nu_protocol::MaybeOwned; pub(crate) use nu_source::{ b, AnchorLocation, DebugDocBuilder, PrettyDebug, PrettyDebugWithSource, Span, SpannedItem, Tag, TaggedItem, Text, diff --git a/crates/nu-cli/src/shell/completer.rs b/crates/nu-cli/src/shell/completer.rs index 019dc6d0f..9e4d69c74 100644 --- a/crates/nu-cli/src/shell/completer.rs +++ b/crates/nu-cli/src/shell/completer.rs @@ -13,8 +13,8 @@ use ichwh::{IchwhError, IchwhResult}; use crate::completion::{self, Completer}; use crate::context; -use crate::data::config; use crate::prelude::*; +use nu_data::config; pub(crate) struct NuCompleter { file_completer: FilenameCompleter, diff --git a/crates/nu-cli/src/shell/filesystem_shell.rs b/crates/nu-cli/src/shell/filesystem_shell.rs index 49be6fe11..1f0d3fa69 100644 --- a/crates/nu-cli/src/shell/filesystem_shell.rs +++ b/crates/nu-cli/src/shell/filesystem_shell.rs @@ -1,15 +1,16 @@ use crate::commands::cd::CdArgs; use crate::commands::command::EvaluatedWholeStreamCommandArgs; use crate::commands::cp::CopyArgs; +use crate::commands::du::{DirBuilder, DirInfo}; use crate::commands::ls::LsArgs; use crate::commands::mkdir::MkdirArgs; use crate::commands::move_::mv::Arguments as MvArgs; use crate::commands::rm::RemoveArgs; -use crate::data::dir_entry_dict; use crate::path::canonicalize; use crate::prelude::*; use crate::shell::shell::Shell; use crate::utils::FileStructure; +use nu_protocol::{TaggedDictBuilder, Value}; use std::collections::HashMap; use std::io::{Error, ErrorKind}; @@ -790,3 +791,197 @@ fn is_hidden_dir(dir: impl AsRef) -> bool { .unwrap_or(false) } } + +#[cfg(unix)] +use std::os::unix::fs::FileTypeExt; + +pub(crate) fn get_file_type(md: &std::fs::Metadata) -> &str { + let ft = md.file_type(); + let mut file_type = "Unknown"; + if ft.is_dir() { + file_type = "Dir"; + } else if ft.is_file() { + file_type = "File"; + } else if ft.is_symlink() { + file_type = "Symlink"; + } else { + #[cfg(unix)] + { + if ft.is_block_device() { + file_type = "Block device"; + } else if ft.is_char_device() { + file_type = "Char device"; + } else if ft.is_fifo() { + file_type = "Pipe"; + } else if ft.is_socket() { + file_type = "Socket"; + } + } + } + file_type +} + +#[allow(clippy::too_many_arguments)] +pub(crate) fn dir_entry_dict( + filename: &std::path::Path, + metadata: Option<&std::fs::Metadata>, + tag: impl Into, + long: bool, + short_name: bool, + du: bool, + ctrl_c: Arc, +) -> Result { + let tag = tag.into(); + let mut dict = TaggedDictBuilder::new(&tag); + // Insert all columns first to maintain proper table alignment if we can't find (or are not allowed to view) any information + if long { + #[cfg(windows)] + { + for column in [ + "name", "type", "target", "readonly", "size", "created", "accessed", "modified", + ] + .iter() + { + dict.insert_untagged(*column, UntaggedValue::nothing()); + } + } + + #[cfg(unix)] + { + for column in [ + "name", "type", "target", "readonly", "mode", "uid", "group", "size", "created", + "accessed", "modified", + ] + .iter() + { + dict.insert_untagged(&(*column.to_owned()), UntaggedValue::nothing()); + } + } + } else { + for column in ["name", "type", "target", "size", "modified"].iter() { + if *column == "target" { + continue; + } + dict.insert_untagged(*column, UntaggedValue::nothing()); + } + } + + let name = if short_name { + filename.file_name().and_then(|s| s.to_str()) + } else { + filename.to_str() + } + .ok_or_else(|| { + ShellError::labeled_error( + format!("Invalid file name: {:}", filename.to_string_lossy()), + "invalid file name", + tag, + ) + })?; + + dict.insert_untagged("name", UntaggedValue::string(name)); + + if let Some(md) = metadata { + dict.insert_untagged("type", get_file_type(md)); + } + + if long { + if let Some(md) = metadata { + if md.file_type().is_symlink() { + let symlink_target_untagged_value: UntaggedValue; + if let Ok(path_to_link) = filename.read_link() { + symlink_target_untagged_value = + UntaggedValue::string(path_to_link.to_string_lossy()); + } else { + symlink_target_untagged_value = + UntaggedValue::string("Could not obtain target file's path"); + } + dict.insert_untagged("target", symlink_target_untagged_value); + } + } + } + + if long { + if let Some(md) = metadata { + dict.insert_untagged( + "readonly", + UntaggedValue::boolean(md.permissions().readonly()), + ); + + #[cfg(unix)] + { + use std::os::unix::fs::MetadataExt; + let mode = md.permissions().mode(); + dict.insert_untagged( + "mode", + UntaggedValue::string(umask::Mode::from(mode).to_string()), + ); + + if let Some(user) = users::get_user_by_uid(md.uid()) { + dict.insert_untagged( + "uid", + UntaggedValue::string(user.name().to_string_lossy()), + ); + } + + if let Some(group) = users::get_group_by_gid(md.gid()) { + dict.insert_untagged( + "group", + UntaggedValue::string(group.name().to_string_lossy()), + ); + } + } + } + } + + if let Some(md) = metadata { + let mut size_untagged_value: UntaggedValue = UntaggedValue::nothing(); + + if md.is_dir() { + let dir_size: u64 = if du { + let params = DirBuilder::new( + Tag { + anchor: None, + span: Span::new(0, 2), + }, + None, + false, + None, + false, + ); + + DirInfo::new(filename, ¶ms, None, ctrl_c).get_size() + } else { + md.len() + }; + + size_untagged_value = UntaggedValue::filesize(dir_size); + } else if md.is_file() { + size_untagged_value = UntaggedValue::filesize(md.len()); + } else if md.file_type().is_symlink() { + if let Ok(symlink_md) = filename.symlink_metadata() { + size_untagged_value = UntaggedValue::filesize(symlink_md.len() as u64); + } + } + + dict.insert_untagged("size", size_untagged_value); + } + + if let Some(md) = metadata { + if long { + if let Ok(c) = md.created() { + dict.insert_untagged("created", UntaggedValue::system_date(c)); + } + + if let Ok(a) = md.accessed() { + dict.insert_untagged("accessed", UntaggedValue::system_date(a)); + } + } + + if let Ok(m) = md.modified() { + dict.insert_untagged("modified", UntaggedValue::system_date(m)); + } + } + + Ok(dict.into_value()) +} diff --git a/crates/nu-cli/src/shell/help_shell.rs b/crates/nu-cli/src/shell/help_shell.rs index 5ed55220b..0450b2995 100644 --- a/crates/nu-cli/src/shell/help_shell.rs +++ b/crates/nu-cli/src/shell/help_shell.rs @@ -1,12 +1,12 @@ use crate::commands::cd::CdArgs; use crate::commands::command::EvaluatedWholeStreamCommandArgs; use crate::commands::cp::CopyArgs; +use crate::commands::help::command_dict; use crate::commands::ls::LsArgs; use crate::commands::mkdir::MkdirArgs; use crate::commands::move_::mv::Arguments as MvArgs; use crate::commands::rm::RemoveArgs; use crate::completion; -use crate::data::command_dict; use crate::prelude::*; use crate::shell::shell::Shell; diff --git a/crates/nu-cli/src/utils.rs b/crates/nu-cli/src/utils.rs index baf42c8e4..31f21ca91 100644 --- a/crates/nu-cli/src/utils.rs +++ b/crates/nu-cli/src/utils.rs @@ -1,4 +1,3 @@ -pub mod data; pub mod test_bins; use crate::path::canonicalize; diff --git a/crates/nu-data/Cargo.toml b/crates/nu-data/Cargo.toml new file mode 100644 index 000000000..a42d5c94f --- /dev/null +++ b/crates/nu-data/Cargo.toml @@ -0,0 +1,40 @@ +[package] +authors = ["The Nu Project Contributors"] +description = "CLI for nushell" +edition = "2018" +license = "MIT" +name = "nu-data" +version = "0.18.2" + +[lib] +doctest = false + +[dependencies] +ansi_term = "0.12.1" +bigdecimal = "0.1.2" +byte-unit = "3.1.3" + +chrono = "0.4.15" +derive-new = "0.5.8" +directories = {version = "2.0.2", optional = true} +dirs = {version = "2.0.2", optional = true} +getset = "0.1.1" +indexmap = {version = "1.4.0", features = ["serde-1"]} +log = "0.4.8" +num-bigint = {version = "0.2.6", features = ["serde"]} +num-format = {version = "0.4", features = ["with-num-bigint"]} +num-traits = "0.2.11" +parking_lot = "0.11.0" +query_interface = "0.3.5" +serde = {version = "1.0.114", features = ["derive"]} +toml = "0.5.6" +umask = "1.0.0" + +nu-errors = {version = "0.18.2", path = "../nu-errors"} +nu-protocol = {version = "0.18.2", path = "../nu-protocol"} +nu-source = {version = "0.18.2", path = "../nu-source"} +nu-table = {version = "0.18.2", path = "../nu-table"} +nu-value-ext = {version = "0.18.2", path = "../nu-value-ext"} + +[target.'cfg(unix)'.dependencies] +users = "0.10.0" diff --git a/crates/nu-cli/src/data/base.rs b/crates/nu-data/src/base.rs similarity index 97% rename from crates/nu-cli/src/data/base.rs rename to crates/nu-data/src/base.rs index 9fb980f23..7e825c016 100644 --- a/crates/nu-cli/src/data/base.rs +++ b/crates/nu-data/src/base.rs @@ -49,7 +49,7 @@ impl std::convert::TryFrom> for Switch { } } -pub(crate) fn select_fields(obj: &Value, fields: &[String], tag: impl Into) -> Value { +pub fn select_fields(obj: &Value, fields: &[String], tag: impl Into) -> Value { let mut out = TaggedDictBuilder::new(tag); let descs = obj.data_descriptors(); @@ -64,7 +64,7 @@ pub(crate) fn select_fields(obj: &Value, fields: &[String], tag: impl Into) out.into_value() } -pub(crate) fn reject_fields(obj: &Value, fields: &[String], tag: impl Into) -> Value { +pub fn reject_fields(obj: &Value, fields: &[String], tag: impl Into) -> Value { let mut out = TaggedDictBuilder::new(tag); let descs = obj.data_descriptors(); @@ -80,7 +80,7 @@ pub(crate) fn reject_fields(obj: &Value, fields: &[String], tag: impl Into) out.into_value() } -pub(crate) enum CompareValues { +pub enum CompareValues { Ints(BigInt, BigInt), Decimals(BigDecimal, BigDecimal), String(String, String), @@ -113,7 +113,7 @@ impl CompareValues { } } -pub(crate) fn coerce_compare( +pub fn coerce_compare( left: &UntaggedValue, right: &UntaggedValue, ) -> Result { @@ -165,7 +165,7 @@ fn coerce_compare_primitive( } #[cfg(test)] mod tests { - use indexmap::IndexMap; + use indexmap::{indexmap, IndexMap}; use nu_errors::ShellError; use nu_protocol::{ColumnPath as ColumnPathValue, PathMember, UntaggedValue, Value}; use nu_source::*; @@ -173,19 +173,19 @@ mod tests { use num_bigint::BigInt; fn string(input: impl Into) -> Value { - crate::utils::data::helpers::string(input) + crate::utils::helpers::string(input) } fn int(input: impl Into) -> Value { - crate::utils::data::helpers::int(input) + crate::utils::helpers::int(input) } fn row(entries: IndexMap) -> Value { - crate::utils::data::helpers::row(entries) + crate::utils::helpers::row(entries) } fn table(list: &[Value]) -> Value { - crate::utils::data::helpers::table(list) + crate::utils::helpers::table(list) } fn error_callback( diff --git a/crates/nu-cli/src/data/base/shape.rs b/crates/nu-data/src/base/shape.rs similarity index 98% rename from crates/nu-cli/src/data/base/shape.rs rename to crates/nu-data/src/base/shape.rs index 621ae1d67..bf6cd8f3d 100644 --- a/crates/nu-cli/src/data/base/shape.rs +++ b/crates/nu-data/src/base/shape.rs @@ -1,8 +1,9 @@ -use crate::prelude::*; +use bigdecimal::BigDecimal; use chrono::{DateTime, Utc}; use nu_protocol::RangeInclusion; use nu_protocol::{format_primitive, ColumnPath, Dictionary, Primitive, UntaggedValue, Value}; -use nu_source::{b, PrettyDebug}; +use nu_source::{b, DebugDocBuilder, PrettyDebug}; +use num_bigint::BigInt; use std::collections::BTreeMap; use std::fmt::Debug; use std::hash::Hash; diff --git a/crates/nu-cli/src/data/command.rs b/crates/nu-data/src/command.rs similarity index 66% rename from crates/nu-cli/src/data/command.rs rename to crates/nu-data/src/command.rs index c470dfc40..259dcb026 100644 --- a/crates/nu-cli/src/data/command.rs +++ b/crates/nu-data/src/command.rs @@ -1,23 +1,8 @@ -use crate::commands::command::Command; -use crate::data::TaggedListBuilder; -use crate::prelude::*; +use crate::TaggedListBuilder; +use nu_source::Tag; + use nu_protocol::{NamedType, PositionalType, Signature, TaggedDictBuilder, UntaggedValue, Value}; -pub(crate) fn command_dict(command: Command, tag: impl Into) -> Value { - let tag = tag.into(); - - let mut cmd_dict = TaggedDictBuilder::new(&tag); - - cmd_dict.insert_untagged("name", UntaggedValue::string(command.name())); - - cmd_dict.insert_untagged("type", UntaggedValue::string("Command")); - - cmd_dict.insert_value("signature", signature_dict(command.signature(), tag)); - cmd_dict.insert_untagged("usage", UntaggedValue::string(command.usage())); - - cmd_dict.into_value() -} - fn for_spec(name: &str, ty: &str, required: bool, tag: impl Into) -> Value { let tag = tag.into(); @@ -33,7 +18,7 @@ fn for_spec(name: &str, ty: &str, required: bool, tag: impl Into) -> Value spec.into_value() } -fn signature_dict(signature: Signature, tag: impl Into) -> Value { +pub fn signature_dict(signature: Signature, tag: impl Into) -> Value { let tag = tag.into(); let mut sig = TaggedListBuilder::new(&tag); diff --git a/crates/nu-data/src/config.rs b/crates/nu-data/src/config.rs new file mode 100644 index 000000000..4dfd95d25 --- /dev/null +++ b/crates/nu-data/src/config.rs @@ -0,0 +1,289 @@ +mod conf; +mod nuconfig; +pub mod table; + +pub mod tests; + +pub use conf::Conf; +pub use nuconfig::NuConfig; + +use indexmap::IndexMap; +use log::trace; +use nu_errors::{CoerceInto, ShellError}; +use nu_protocol::{ + Dictionary, Primitive, ShellTypeName, TaggedDictBuilder, UnspannedPathMember, UntaggedValue, + Value, +}; +use nu_source::{SpannedItem, Tag, TaggedItem}; +use std::fs::{self, OpenOptions}; +use std::io; +use std::path::{Path, PathBuf}; + +pub fn convert_toml_value_to_nu_value(v: &toml::Value, tag: impl Into) -> Value { + let tag = tag.into(); + + match v { + toml::Value::Boolean(b) => UntaggedValue::boolean(*b).into_value(tag), + toml::Value::Integer(n) => UntaggedValue::int(*n).into_value(tag), + toml::Value::Float(n) => UntaggedValue::decimal(*n).into_value(tag), + toml::Value::String(s) => { + UntaggedValue::Primitive(Primitive::String(String::from(s))).into_value(tag) + } + toml::Value::Array(a) => UntaggedValue::Table( + a.iter() + .map(|x| convert_toml_value_to_nu_value(x, &tag)) + .collect(), + ) + .into_value(tag), + toml::Value::Datetime(dt) => { + UntaggedValue::Primitive(Primitive::String(dt.to_string())).into_value(tag) + } + toml::Value::Table(t) => { + let mut collected = TaggedDictBuilder::new(&tag); + + for (k, v) in t.iter() { + collected.insert_value(k.clone(), convert_toml_value_to_nu_value(v, &tag)); + } + + collected.into_value() + } + } +} + +fn collect_values(input: &[Value]) -> Result, ShellError> { + let mut out = vec![]; + + for value in input { + out.push(helper(value)?); + } + + Ok(out) +} +// Helper method to recursively convert nu_protocol::Value -> toml::Value +// This shouldn't be called at the top-level +fn helper(v: &Value) -> Result { + Ok(match &v.value { + UntaggedValue::Primitive(Primitive::Boolean(b)) => toml::Value::Boolean(*b), + UntaggedValue::Primitive(Primitive::Filesize(b)) => toml::Value::Integer(*b as i64), + UntaggedValue::Primitive(Primitive::Duration(i)) => toml::Value::String(i.to_string()), + UntaggedValue::Primitive(Primitive::Date(d)) => toml::Value::String(d.to_string()), + UntaggedValue::Primitive(Primitive::EndOfStream) => { + toml::Value::String("".to_string()) + } + UntaggedValue::Primitive(Primitive::BeginningOfStream) => { + toml::Value::String("".to_string()) + } + UntaggedValue::Primitive(Primitive::Decimal(f)) => { + toml::Value::Float(f.tagged(&v.tag).coerce_into("converting to TOML float")?) + } + UntaggedValue::Primitive(Primitive::Int(i)) => { + toml::Value::Integer(i.tagged(&v.tag).coerce_into("converting to TOML integer")?) + } + UntaggedValue::Primitive(Primitive::Nothing) => { + toml::Value::String("".to_string()) + } + UntaggedValue::Primitive(Primitive::Pattern(s)) => toml::Value::String(s.clone()), + UntaggedValue::Primitive(Primitive::String(s)) => toml::Value::String(s.clone()), + UntaggedValue::Primitive(Primitive::Line(s)) => toml::Value::String(s.clone()), + UntaggedValue::Primitive(Primitive::Path(s)) => { + toml::Value::String(s.display().to_string()) + } + UntaggedValue::Primitive(Primitive::ColumnPath(path)) => toml::Value::Array( + path.iter() + .map(|x| match &x.unspanned { + UnspannedPathMember::String(string) => Ok(toml::Value::String(string.clone())), + UnspannedPathMember::Int(int) => Ok(toml::Value::Integer( + int.tagged(&v.tag) + .coerce_into("converting to TOML integer")?, + )), + }) + .collect::, ShellError>>()?, + ), + UntaggedValue::Table(l) => toml::Value::Array(collect_values(l)?), + UntaggedValue::Error(e) => return Err(e.clone()), + UntaggedValue::Block(_) => toml::Value::String("".to_string()), + UntaggedValue::Primitive(Primitive::Range(_)) => toml::Value::String("".to_string()), + UntaggedValue::Primitive(Primitive::Binary(b)) => { + toml::Value::Array(b.iter().map(|x| toml::Value::Integer(*x as i64)).collect()) + } + UntaggedValue::Row(o) => { + let mut m = toml::map::Map::new(); + for (k, v) in o.entries.iter() { + m.insert(k.clone(), helper(v)?); + } + toml::Value::Table(m) + } + }) +} + +/// Converts a nu_protocol::Value into a toml::Value +/// Will return a Shell Error, if the Nu Value is not a valid top-level TOML Value +pub fn value_to_toml_value(v: &Value) -> Result { + match &v.value { + UntaggedValue::Row(o) => { + let mut m = toml::map::Map::new(); + for (k, v) in o.entries.iter() { + m.insert(k.clone(), helper(v)?); + } + Ok(toml::Value::Table(m)) + } + UntaggedValue::Primitive(Primitive::String(s)) => { + // Attempt to de-serialize the String + toml::de::from_str(s).map_err(|_| { + ShellError::labeled_error( + format!("{:?} unable to de-serialize string to TOML", s), + "invalid TOML", + v.tag(), + ) + }) + } + _ => Err(ShellError::labeled_error( + format!("{:?} is not a valid top-level TOML", v.value), + "invalid TOML", + v.tag(), + )), + } +} + +#[cfg(feature = "directories")] +pub fn config_path() -> Result { + use directories::ProjectDirs; + + let dir = ProjectDirs::from("org", "nushell", "nu") + .ok_or_else(|| ShellError::untagged_runtime_error("Couldn't find project directory"))?; + let path = ProjectDirs::config_dir(&dir).to_owned(); + std::fs::create_dir_all(&path).map_err(|err| { + ShellError::untagged_runtime_error(&format!("Couldn't create {} path:\n{}", "config", err)) + })?; + + Ok(path) +} + +#[cfg(not(feature = "directories"))] +pub fn config_path() -> Result { + // FIXME: unsure if this should be error or a simple default + + Ok(std::path::PathBuf::from("/")) +} + +pub fn default_path() -> Result { + default_path_for(&None) +} + +pub fn default_path_for(file: &Option) -> Result { + let mut filename = config_path()?; + let file: &Path = file + .as_ref() + .map(AsRef::as_ref) + .unwrap_or_else(|| "config.toml".as_ref()); + filename.push(file); + + Ok(filename) +} + +#[cfg(feature = "directories")] +pub fn user_data() -> Result { + use directories::ProjectDirs; + + let dir = ProjectDirs::from("org", "nushell", "nu") + .ok_or_else(|| ShellError::untagged_runtime_error("Couldn't find project directory"))?; + let path = ProjectDirs::data_local_dir(&dir).to_owned(); + std::fs::create_dir_all(&path).map_err(|err| { + ShellError::untagged_runtime_error(&format!( + "Couldn't create {} path:\n{}", + "user data", err + )) + })?; + + Ok(path) +} + +#[cfg(not(feature = "directories"))] +pub fn user_data() -> Result { + // FIXME: unsure if this should be error or a simple default + + Ok(std::path::PathBuf::from("/")) +} + +pub fn read( + tag: impl Into, + at: &Option, +) -> Result, ShellError> { + let filename = default_path()?; + + let filename = match at { + None => filename, + Some(ref file) => file.clone(), + }; + + if !filename.exists() && touch(&filename).is_err() { + // If we can't create configs, let's just return an empty indexmap instead as we may be in + // a readonly environment + return Ok(IndexMap::new()); + } + + trace!("config file = {}", filename.display()); + + let tag = tag.into(); + let contents = fs::read_to_string(filename) + .map(|v| v.tagged(&tag)) + .map_err(|err| { + ShellError::labeled_error( + &format!("Couldn't read config file:\n{}", err), + "file name", + &tag, + ) + })?; + + let parsed: toml::Value = toml::from_str(&contents).map_err(|err| { + ShellError::labeled_error( + &format!("Couldn't parse config file:\n{}", err), + "file name", + &tag, + ) + })?; + + let value = convert_toml_value_to_nu_value(&parsed, tag); + let tag = value.tag(); + match value.value { + UntaggedValue::Row(Dictionary { entries }) => Ok(entries), + other => Err(ShellError::type_error( + "Dictionary", + other.type_name().spanned(tag.span), + )), + } +} + +pub fn config(tag: impl Into) -> Result, ShellError> { + read(tag, &None) +} + +pub fn write(config: &IndexMap, at: &Option) -> Result<(), ShellError> { + let filename = &mut default_path()?; + let filename = match at { + None => filename, + Some(file) => { + filename.pop(); + filename.push(file); + filename + } + }; + + let contents = value_to_toml_value( + &UntaggedValue::Row(Dictionary::new(config.clone())).into_untagged_value(), + )?; + + let contents = toml::to_string(&contents)?; + + fs::write(&filename, &contents)?; + + Ok(()) +} + +// A simple implementation of `% touch path` (ignores existing files) +fn touch(path: &Path) -> io::Result<()> { + match OpenOptions::new().create(true).write(true).open(path) { + Ok(_) => Ok(()), + Err(e) => Err(e), + } +} diff --git a/crates/nu-cli/src/data/config/conf.rs b/crates/nu-data/src/config/conf.rs similarity index 100% rename from crates/nu-cli/src/data/config/conf.rs rename to crates/nu-data/src/config/conf.rs diff --git a/crates/nu-cli/src/data/config/nuconfig.rs b/crates/nu-data/src/config/nuconfig.rs similarity index 97% rename from crates/nu-cli/src/data/config/nuconfig.rs rename to crates/nu-data/src/config/nuconfig.rs index 88c7d424f..76e08a9a8 100644 --- a/crates/nu-cli/src/data/config/nuconfig.rs +++ b/crates/nu-data/src/config/nuconfig.rs @@ -1,4 +1,4 @@ -use crate::data::config::{read, Conf}; +use crate::config::{read, Conf}; use indexmap::IndexMap; use nu_protocol::Value; use nu_source::Tag; diff --git a/crates/nu-cli/src/data/config/table.rs b/crates/nu-data/src/config/table.rs similarity index 98% rename from crates/nu-cli/src/data/config/table.rs rename to crates/nu-data/src/config/table.rs index 40f3dec20..ffe761a22 100644 --- a/crates/nu-cli/src/data/config/table.rs +++ b/crates/nu-data/src/config/table.rs @@ -1,4 +1,4 @@ -use crate::data::config::nuconfig::NuConfig; +use crate::config::nuconfig::NuConfig; use std::fmt::Debug; #[derive(PartialEq, Debug)] diff --git a/crates/nu-cli/src/data/config/tests.rs b/crates/nu-data/src/config/tests.rs similarity index 94% rename from crates/nu-cli/src/data/config/tests.rs rename to crates/nu-data/src/config/tests.rs index ecbe0cb7f..9039707b7 100644 --- a/crates/nu-cli/src/data/config/tests.rs +++ b/crates/nu-data/src/config/tests.rs @@ -1,4 +1,4 @@ -use crate::data::config::{read, Conf, NuConfig}; +use crate::config::{read, Conf, NuConfig}; use indexmap::IndexMap; use nu_protocol::Value; use nu_source::Tag; diff --git a/crates/nu-cli/src/data/dict.rs b/crates/nu-data/src/dict.rs similarity index 95% rename from crates/nu-cli/src/data/dict.rs rename to crates/nu-data/src/dict.rs index 5be5c0904..b615ffa23 100644 --- a/crates/nu-cli/src/data/dict.rs +++ b/crates/nu-data/src/dict.rs @@ -1,7 +1,6 @@ -use crate::prelude::*; use derive_new::new; -use nu_protocol::{Dictionary, Primitive, UntaggedValue, Value}; -use nu_source::{b, PrettyDebug, Spanned}; +use nu_protocol::{Dictionary, MaybeOwned, Primitive, UntaggedValue, Value}; +use nu_source::{b, DebugDocBuilder, PrettyDebug, Spanned, Tag}; #[derive(Debug, new)] struct DebugEntry<'a> { diff --git a/crates/nu-data/src/lib.rs b/crates/nu-data/src/lib.rs new file mode 100644 index 000000000..809d499a6 --- /dev/null +++ b/crates/nu-data/src/lib.rs @@ -0,0 +1,10 @@ +pub mod base; +pub mod command; +pub mod config; +pub mod dict; +pub mod primitive; +pub mod types; +pub mod utils; +pub mod value; + +pub use dict::TaggedListBuilder; diff --git a/crates/nu-cli/src/data/operators.rs b/crates/nu-data/src/operators.rs similarity index 100% rename from crates/nu-cli/src/data/operators.rs rename to crates/nu-data/src/operators.rs diff --git a/crates/nu-cli/src/data/primitive.rs b/crates/nu-data/src/primitive.rs similarity index 100% rename from crates/nu-cli/src/data/primitive.rs rename to crates/nu-data/src/primitive.rs diff --git a/crates/nu-cli/src/data/process.rs b/crates/nu-data/src/process.rs similarity index 94% rename from crates/nu-cli/src/data/process.rs rename to crates/nu-data/src/process.rs index 8772beba4..e87c26f3b 100644 --- a/crates/nu-cli/src/data/process.rs +++ b/crates/nu-data/src/process.rs @@ -1,4 +1,4 @@ -use crate::data::{TaggedDictBuilder, Value}; +use nu_data::{TaggedDictBuilder, Value}; use crate::prelude::*; use itertools::join; use sysinfo::ProcessExt; diff --git a/crates/nu-cli/src/data/types.rs b/crates/nu-data/src/types.rs similarity index 98% rename from crates/nu-cli/src/data/types.rs rename to crates/nu-data/src/types.rs index 4407c588a..2667ec8ef 100644 --- a/crates/nu-cli/src/data/types.rs +++ b/crates/nu-data/src/types.rs @@ -1,8 +1,7 @@ -use crate::prelude::*; use log::trace; use nu_errors::{CoerceInto, ShellError}; use nu_protocol::{Primitive, SpannedTypeName, UntaggedValue, Value}; -use nu_source::Tagged; +use nu_source::{Tagged, TaggedItem}; pub trait ExtractType: Sized { fn extract(value: &Value) -> Result; diff --git a/crates/nu-cli/src/utils/data/group.rs b/crates/nu-data/src/utils/group.rs similarity index 100% rename from crates/nu-cli/src/utils/data/group.rs rename to crates/nu-data/src/utils/group.rs diff --git a/crates/nu-cli/src/utils/data/internal.rs b/crates/nu-data/src/utils/internal.rs similarity index 98% rename from crates/nu-cli/src/utils/data/internal.rs rename to crates/nu-data/src/utils/internal.rs index 19d10a2bf..fda8ddc9d 100644 --- a/crates/nu-cli/src/utils/data/internal.rs +++ b/crates/nu-data/src/utils/internal.rs @@ -1,6 +1,6 @@ #![allow(clippy::type_complexity)] -use crate::data::value::compute_values; +use crate::value::compute_values; use derive_new::new; use nu_errors::ShellError; use nu_protocol::hir::Operator; @@ -138,8 +138,7 @@ pub fn sort_columns( if let Some(fmt) = format { for k in values.iter() { let k = k.clone().tagged_unknown(); - let v = - crate::data::value::Date::naive_from_str(k.borrow_tagged())?.into_untagged_value(); + let v = crate::value::Date::naive_from_str(k.borrow_tagged())?.into_untagged_value(); keys.push(fmt(&v, k.to_string())?); } } else { diff --git a/crates/nu-cli/src/utils/data/mod.rs b/crates/nu-data/src/utils/mod.rs similarity index 91% rename from crates/nu-cli/src/utils/data/mod.rs rename to crates/nu-data/src/utils/mod.rs index 84ebc7724..9ff2ab0ae 100644 --- a/crates/nu-cli/src/utils/data/mod.rs +++ b/crates/nu-data/src/utils/mod.rs @@ -3,10 +3,10 @@ pub mod split; mod internal; -pub use crate::utils::data::group::group; -pub use crate::utils::data::split::split; +pub use crate::utils::group::group; +pub use crate::utils::split::split; -use crate::utils::data::internal::*; +use crate::utils::internal::*; use derive_new::new; use getset::Getters; @@ -97,9 +97,8 @@ pub fn report( }) } -#[cfg(test)] pub mod helpers { - use super::{report, Labels, Model, Operation, Range}; + use super::Model; use bigdecimal::BigDecimal; use indexmap::indexmap; use nu_errors::ShellError; @@ -132,8 +131,8 @@ pub mod helpers { pub fn date(input: impl Into) -> Value { let key = input.into().tagged_unknown(); - crate::data::value::Date::naive_from_str(key.borrow_tagged()) - .unwrap() + crate::value::Date::naive_from_str(key.borrow_tagged()) + .expect("date from string failed") .into_untagged_value() } @@ -201,12 +200,15 @@ pub mod helpers { let grouper = Box::new(move |_, row: &Value| { let key = String::from("date").tagged_unknown(); - let group_key = row.get_data_by_key(key.borrow_spanned()).unwrap(); + let group_key = row + .get_data_by_key(key.borrow_spanned()) + .expect("get key failed"); group_key.format("%Y-%m-%d") }); - crate::utils::data::group(&sample, &Some(grouper), Tag::unknown()).unwrap() + crate::utils::group(&sample, &Some(grouper), Tag::unknown()) + .expect("failed to create group") } pub fn date_formatter( @@ -215,13 +217,24 @@ pub mod helpers { Box::new(move |date: &Value, _: String| date.format(&fmt)) } - fn assert_without_checking_percentages(report_a: Model, report_b: Model) { + pub fn assert_without_checking_percentages(report_a: Model, report_b: Model) { assert_eq!(report_a.labels.x, report_b.labels.x); assert_eq!(report_a.labels.y, report_b.labels.y); assert_eq!(report_a.ranges, report_b.ranges); assert_eq!(report_a.data, report_b.data); } +} +#[cfg(test)] +mod tests { + use super::helpers::{ + assert_without_checking_percentages, committers, date_formatter, decimal, int, table, + }; + use super::{report, Labels, Model, Operation, Range}; + use nu_errors::ShellError; + use nu_protocol::Value; + use nu_source::{Tag, TaggedItem}; + use nu_value_ext::ValueExt; #[test] fn prepares_report_using_accumulating_value() { let committers = table(&committers()); diff --git a/crates/nu-cli/src/utils/data/split.rs b/crates/nu-data/src/utils/split.rs similarity index 98% rename from crates/nu-cli/src/utils/data/split.rs rename to crates/nu-data/src/utils/split.rs index 514b2c832..7cdadef7d 100644 --- a/crates/nu-cli/src/utils/data/split.rs +++ b/crates/nu-data/src/utils/split.rs @@ -2,7 +2,7 @@ use nu_errors::ShellError; use nu_protocol::{SpannedTypeName, TaggedDictBuilder, UntaggedValue, Value}; use nu_source::Tag; -use crate::utils::data::group; +use crate::utils::group; #[allow(clippy::type_complexity)] pub fn split( diff --git a/crates/nu-cli/src/data/value.rs b/crates/nu-data/src/value.rs similarity index 98% rename from crates/nu-cli/src/data/value.rs rename to crates/nu-data/src/value.rs index 42e9e8214..80fce4797 100644 --- a/crates/nu-cli/src/data/value.rs +++ b/crates/nu-data/src/value.rs @@ -1,6 +1,6 @@ -use crate::data::base::coerce_compare; -use crate::data::base::shape::{Column, InlineShape}; -use crate::data::primitive::style_primitive; +use crate::base::coerce_compare; +use crate::base::shape::{Column, InlineShape}; +use crate::primitive::style_primitive; use chrono::{DateTime, NaiveDate, Utc}; use nu_errors::ShellError; use nu_protocol::hir::Operator; diff --git a/crates/nu_plugin_textview/Cargo.toml b/crates/nu_plugin_textview/Cargo.toml index 48e78f3b2..a0fcebc5f 100644 --- a/crates/nu_plugin_textview/Cargo.toml +++ b/crates/nu_plugin_textview/Cargo.toml @@ -10,7 +10,7 @@ version = "0.18.2" doctest = false [dependencies] -nu-cli = {path = "../nu-cli", version = "0.18.2"} +nu-data = {path = "../nu-data", version = "0.18.2"} nu-errors = {path = "../nu-errors", version = "0.18.2"} nu-plugin = {path = "../nu-plugin", version = "0.18.2"} nu-protocol = {path = "../nu-protocol", version = "0.18.2"} diff --git a/crates/nu_plugin_textview/src/textview.rs b/crates/nu_plugin_textview/src/textview.rs index b62f823f7..e99adf146 100644 --- a/crates/nu_plugin_textview/src/textview.rs +++ b/crates/nu_plugin_textview/src/textview.rs @@ -32,7 +32,7 @@ pub fn view_text_value(value: &Value) { let highlight_range_to: u64 = 0; let mut theme = "OneHalfDark".to_string(); - if let Ok(config) = nu_cli::data::config::config(Tag::unknown()) { + if let Ok(config) = nu_data::config::config(Tag::unknown()) { if let Some(batvars) = config.get("textview") { for (idx, value) in batvars.row_entries() { match idx.as_ref() {