Merge branch 'master' of github.com:nushell/nushell

This commit is contained in:
Sam Hedin 2020-06-10 08:36:16 +02:00
commit f6458b4322
43 changed files with 637 additions and 491 deletions

56
Cargo.lock generated
View File

@ -1357,9 +1357,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]]
name = "heim"
version = "0.1.0-beta.1"
version = "0.1.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c39a60e3aee8ada013ddfc5d8447d6f81011dac7ddef61a3f3d34b4be982aa79"
checksum = "ea9164f267a5f4325020b8a989c4b0ab06acc0685ccdb22551f59257fdf296ab"
dependencies = [
"heim-common",
"heim-cpu",
@ -1393,9 +1393,9 @@ dependencies = [
[[package]]
name = "heim-cpu"
version = "0.1.0-beta.1"
version = "0.1.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "020d170328cadc4d6adcf549c22983a19c35068414609c276c4db607ee295693"
checksum = "8b088c42ce30cf60b485df484e0aa19c31ad8663bb939180ef64ca340d15eca6"
dependencies = [
"cfg-if",
"futures 0.3.5",
@ -1462,9 +1462,9 @@ dependencies = [
[[package]]
name = "heim-net"
version = "0.1.0-beta.1"
version = "0.1.0-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3108a5d01cfe88042c349c93d760d2cb8d82c2131183ba6af5fc5b8a6c0a5b5"
checksum = "59da1108e732afcda77e1429b5d0ce648b9a31d1f8cf385108b83bea4cf91342"
dependencies = [
"bitflags",
"cfg-if",
@ -1477,9 +1477,9 @@ dependencies = [
[[package]]
name = "heim-process"
version = "0.1.1-beta.1"
version = "0.1.1-beta.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac9b230a6f7c9d746c12a300186d6e8cb31495cdbe3cefd7a15f969327b0d323"
checksum = "190f1085293c8d54060dd77c943da0d5bd1729aa00d2ac68188e26446dc0170d"
dependencies = [
"async-trait",
"cfg-if",
@ -2175,7 +2175,7 @@ dependencies = [
[[package]]
name = "nu"
version = "0.14.1"
version = "0.15.0"
dependencies = [
"clap",
"crossterm",
@ -2212,7 +2212,7 @@ dependencies = [
[[package]]
name = "nu-build"
version = "0.14.1"
version = "0.15.0"
dependencies = [
"lazy_static 1.4.0",
"serde 1.0.110",
@ -2222,7 +2222,7 @@ dependencies = [
[[package]]
name = "nu-cli"
version = "0.14.1"
version = "0.15.0"
dependencies = [
"ansi_term 0.12.1",
"app_dirs",
@ -2313,7 +2313,7 @@ dependencies = [
[[package]]
name = "nu-errors"
version = "0.14.1"
version = "0.15.0"
dependencies = [
"ansi_term 0.12.1",
"bigdecimal",
@ -2333,7 +2333,7 @@ dependencies = [
[[package]]
name = "nu-parser"
version = "0.14.1"
version = "0.15.0"
dependencies = [
"bigdecimal",
"codespan-reporting",
@ -2352,7 +2352,7 @@ dependencies = [
[[package]]
name = "nu-plugin"
version = "0.14.1"
version = "0.15.0"
dependencies = [
"bigdecimal",
"indexmap",
@ -2368,7 +2368,7 @@ dependencies = [
[[package]]
name = "nu-protocol"
version = "0.14.1"
version = "0.15.0"
dependencies = [
"ansi_term 0.12.1",
"bigdecimal",
@ -2397,7 +2397,7 @@ dependencies = [
[[package]]
name = "nu-source"
version = "0.14.1"
version = "0.15.0"
dependencies = [
"codespan-reporting",
"derive-new",
@ -2410,7 +2410,7 @@ dependencies = [
[[package]]
name = "nu-test-support"
version = "0.14.1"
version = "0.15.0"
dependencies = [
"directories 2.0.2",
"dunce",
@ -2426,7 +2426,7 @@ dependencies = [
[[package]]
name = "nu-value-ext"
version = "0.14.1"
version = "0.15.0"
dependencies = [
"indexmap",
"itertools",
@ -2440,7 +2440,7 @@ dependencies = [
[[package]]
name = "nu_plugin_binaryview"
version = "0.14.1"
version = "0.15.0"
dependencies = [
"ansi_term 0.12.1",
"crossterm",
@ -2457,7 +2457,7 @@ dependencies = [
[[package]]
name = "nu_plugin_fetch"
version = "0.14.1"
version = "0.15.0"
dependencies = [
"base64 0.12.1",
"futures 0.3.5",
@ -2472,7 +2472,7 @@ dependencies = [
[[package]]
name = "nu_plugin_inc"
version = "0.14.1"
version = "0.15.0"
dependencies = [
"nu-build",
"nu-errors",
@ -2485,7 +2485,7 @@ dependencies = [
[[package]]
name = "nu_plugin_match"
version = "0.14.1"
version = "0.15.0"
dependencies = [
"futures 0.3.5",
"nu-build",
@ -2498,7 +2498,7 @@ dependencies = [
[[package]]
name = "nu_plugin_post"
version = "0.14.1"
version = "0.15.0"
dependencies = [
"base64 0.12.1",
"futures 0.3.5",
@ -2515,7 +2515,7 @@ dependencies = [
[[package]]
name = "nu_plugin_ps"
version = "0.14.1"
version = "0.15.0"
dependencies = [
"futures 0.3.5",
"futures-timer 3.0.2",
@ -2529,7 +2529,7 @@ dependencies = [
[[package]]
name = "nu_plugin_start"
version = "0.1.0"
version = "0.15.0"
dependencies = [
"glob",
"nu-build",
@ -2543,7 +2543,7 @@ dependencies = [
[[package]]
name = "nu_plugin_sys"
version = "0.14.1"
version = "0.15.0"
dependencies = [
"battery",
"futures 0.3.5",
@ -2558,7 +2558,7 @@ dependencies = [
[[package]]
name = "nu_plugin_textview"
version = "0.14.1"
version = "0.15.0"
dependencies = [
"ansi_term 0.12.1",
"crossterm",
@ -2573,7 +2573,7 @@ dependencies = [
[[package]]
name = "nu_plugin_tree"
version = "0.14.1"
version = "0.15.0"
dependencies = [
"derive-new",
"nu-build",

View File

@ -1,6 +1,6 @@
[package]
name = "nu"
version = "0.14.1"
version = "0.15.0"
authors = ["The Nu Project Contributors"]
description = "A new type of shell"
license = "MIT"
@ -18,23 +18,23 @@ members = ["crates/*/"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
nu-cli = { version = "0.14.1", path = "./crates/nu-cli" }
nu-source = { version = "0.14.1", path = "./crates/nu-source" }
nu-plugin = { version = "0.14.1", path = "./crates/nu-plugin" }
nu-protocol = { version = "0.14.1", path = "./crates/nu-protocol" }
nu-errors = { version = "0.14.1", path = "./crates/nu-errors" }
nu-parser = { version = "0.14.1", path = "./crates/nu-parser" }
nu-value-ext = { version = "0.14.1", path = "./crates/nu-value-ext" }
nu_plugin_binaryview = { version = "0.14.1", path = "./crates/nu_plugin_binaryview", optional=true }
nu_plugin_fetch = { version = "0.14.1", path = "./crates/nu_plugin_fetch", optional=true }
nu_plugin_inc = { version = "0.14.1", path = "./crates/nu_plugin_inc", optional=true }
nu_plugin_match = { version = "0.14.1", path = "./crates/nu_plugin_match", optional=true }
nu_plugin_post = { version = "0.14.1", path = "./crates/nu_plugin_post", optional=true }
nu_plugin_ps = { version = "0.14.1", path = "./crates/nu_plugin_ps", optional=true }
nu_plugin_start = { version = "0.1.0", path = "./crates/nu_plugin_start", optional=true }
nu_plugin_sys = { version = "0.14.1", path = "./crates/nu_plugin_sys", optional=true }
nu_plugin_textview = { version = "0.14.1", path = "./crates/nu_plugin_textview", optional=true }
nu_plugin_tree = { version = "0.14.1", path = "./crates/nu_plugin_tree", optional=true }
nu-cli = { version = "0.15.0", path = "./crates/nu-cli" }
nu-source = { version = "0.15.0", path = "./crates/nu-source" }
nu-plugin = { version = "0.15.0", path = "./crates/nu-plugin" }
nu-protocol = { version = "0.15.0", path = "./crates/nu-protocol" }
nu-errors = { version = "0.15.0", path = "./crates/nu-errors" }
nu-parser = { version = "0.15.0", path = "./crates/nu-parser" }
nu-value-ext = { version = "0.15.0", path = "./crates/nu-value-ext" }
nu_plugin_binaryview = { version = "0.15.0", path = "./crates/nu_plugin_binaryview", optional=true }
nu_plugin_fetch = { version = "0.15.0", path = "./crates/nu_plugin_fetch", optional=true }
nu_plugin_inc = { version = "0.15.0", path = "./crates/nu_plugin_inc", optional=true }
nu_plugin_match = { version = "0.15.0", path = "./crates/nu_plugin_match", optional=true }
nu_plugin_post = { version = "0.15.0", path = "./crates/nu_plugin_post", optional=true }
nu_plugin_ps = { version = "0.15.0", path = "./crates/nu_plugin_ps", optional=true }
nu_plugin_start = { version = "0.15.0", path = "./crates/nu_plugin_start", optional=true }
nu_plugin_sys = { version = "0.15.0", path = "./crates/nu_plugin_sys", optional=true }
nu_plugin_textview = { version = "0.15.0", path = "./crates/nu_plugin_textview", optional=true }
nu_plugin_tree = { version = "0.15.0", path = "./crates/nu_plugin_tree", optional=true }
crossterm = { version = "0.17.5", optional = true }
semver = { version = "0.10.0", optional = true }
@ -49,12 +49,12 @@ log = "0.4.8"
pretty_env_logger = "0.4.0"
[dev-dependencies]
nu-test-support = { version = "0.14.1", path = "./crates/nu-test-support" }
nu-test-support = { version = "0.15.0", path = "./crates/nu-test-support" }
[build-dependencies]
toml = "0.5.6"
serde = { version = "1.0.110", features = ["derive"] }
nu-build = { version = "0.14.1", path = "./crates/nu-build" }
nu-build = { version = "0.15.0", path = "./crates/nu-build" }
[features]
default = ["sys", "ps", "textview", "inc"]

View File

@ -1,6 +1,6 @@
[package]
name = "nu-build"
version = "0.14.1"
version = "0.15.0"
authors = ["The Nu Project Contributors"]
edition = "2018"
description = "Core build system for nushell"

View File

@ -1,6 +1,6 @@
[package]
name = "nu-cli"
version = "0.14.1"
version = "0.15.0"
authors = ["The Nu Project Contributors"]
description = "CLI for nushell"
edition = "2018"
@ -10,13 +10,13 @@ license = "MIT"
doctest = false
[dependencies]
nu-source = { version = "0.14.1", path = "../nu-source" }
nu-plugin = { version = "0.14.1", path = "../nu-plugin" }
nu-protocol = { version = "0.14.1", path = "../nu-protocol" }
nu-errors = { version = "0.14.1", path = "../nu-errors" }
nu-parser = { version = "0.14.1", path = "../nu-parser" }
nu-value-ext = { version = "0.14.1", path = "../nu-value-ext" }
nu-test-support = { version = "0.14.1", path = "../nu-test-support" }
nu-source = { version = "0.15.0", path = "../nu-source" }
nu-plugin = { version = "0.15.0", path = "../nu-plugin" }
nu-protocol = { version = "0.15.0", path = "../nu-protocol" }
nu-errors = { version = "0.15.0", path = "../nu-errors" }
nu-parser = { version = "0.15.0", path = "../nu-parser" }
nu-value-ext = { version = "0.15.0", path = "../nu-value-ext" }
nu-test-support = { version = "0.15.0", path = "../nu-test-support" }
ansi_term = "0.12.1"
app_dirs = "1.2.1"
@ -101,7 +101,7 @@ version = "0.23.1"
features = ["bundled", "blob"]
[build-dependencies]
nu-build = { version = "0.14.1", path = "../nu-build" }
nu-build = { version = "0.15.0", path = "../nu-build" }
[dev-dependencies]
quickcheck = "0.9"

View File

@ -1,11 +1,9 @@
use crate::commands::{command::EvaluatedWholeStreamCommandArgs, WholeStreamCommand};
use crate::prelude::*;
use chrono::{Datelike, Local, NaiveDate};
use nu_errors::ShellError;
use nu_protocol::Dictionary;
use crate::commands::{command::EvaluatedWholeStreamCommandArgs, WholeStreamCommand};
use indexmap::IndexMap;
use nu_protocol::{Signature, SyntaxShape, UntaggedValue, Value};
use nu_errors::ShellError;
use nu_protocol::{Dictionary, Signature, SyntaxShape, UntaggedValue, Value};
pub struct Cal;
@ -250,7 +248,7 @@ fn add_month_to_table(
tag: &Tag,
selected_year: i32,
current_month: u32,
_current_day_option: Option<u32>, // Can be used in the future to display current day
current_day_option: Option<u32>,
) -> Result<(), ShellError> {
let month_helper_result = MonthHelper::new(selected_year, current_month);
@ -316,14 +314,23 @@ fn add_month_to_table(
}
for day in &days_of_the_week {
let value = if (day_count <= day_limit)
&& (day_count > month_helper.day_number_month_starts_on)
{
UntaggedValue::int(day_count - month_helper.day_number_month_starts_on)
.into_value(tag)
} else {
UntaggedValue::nothing().into_value(tag)
};
let should_add_day_number_to_table =
(day_count <= day_limit) && (day_count > month_helper.day_number_month_starts_on);
let mut value = UntaggedValue::nothing().into_value(tag);
if should_add_day_number_to_table {
let day_count_with_offset = day_count - month_helper.day_number_month_starts_on;
value = UntaggedValue::int(day_count_with_offset).into_value(tag);
if let Some(current_day) = current_day_option {
if current_day == day_count_with_offset {
// TODO: Update the value here with a color when color support is added
// This colors the current day
}
}
}
indexmap.insert((*day).to_string(), value);

View File

@ -384,18 +384,16 @@ impl WholeStreamCommand for FnFilterCommand {
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let CommandArgs {
CommandArgs {
host,
ctrl_c,
shell_manager,
call_info,
mut input,
..
} = args;
}: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let host: Arc<parking_lot::Mutex<dyn Host>> = host.clone();
let registry: CommandRegistry = registry.clone();
let func = self.func;

View File

@ -37,42 +37,37 @@ impl WholeStreamCommand for EvaluateBy {
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
evaluate_by(args, registry)
evaluate_by(args, registry).await
}
}
pub fn evaluate_by(
pub async fn evaluate_by(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let registry = registry.clone();
let stream = async_stream! {
let name = args.call_info.name_tag.clone();
let (EvaluateByArgs { evaluate_with }, mut input) = args.process(&registry).await?;
let values: Vec<Value> = input.collect().await;
let name = args.call_info.name_tag.clone();
let (EvaluateByArgs { evaluate_with }, mut input) = args.process(&registry).await?;
let values: Vec<Value> = input.collect().await;
if values.is_empty() {
yield Err(ShellError::labeled_error(
"Expected table from pipeline",
"requires a table input",
name
))
if values.is_empty() {
Err(ShellError::labeled_error(
"Expected table from pipeline",
"requires a table input",
name,
))
} else {
let evaluate_with = if let Some(evaluator) = evaluate_with {
Some(evaluator.item().clone())
} else {
None
};
let evaluate_with = if let Some(evaluator) = evaluate_with {
Some(evaluator.item().clone())
} else {
None
};
match evaluate(&values[0], evaluate_with, name) {
Ok(evaluated) => yield ReturnSuccess::value(evaluated),
Err(err) => yield Err(err)
}
match evaluate(&values[0], evaluate_with, name) {
Ok(evaluated) => Ok(OutputStream::one(ReturnSuccess::value(evaluated))),
Err(err) => Err(err),
}
};
Ok(stream.to_output_stream())
}
}
#[cfg(test)]

View File

@ -25,7 +25,7 @@ impl WholeStreamCommand for Exit {
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
exit(args, registry)
exit(args, registry).await
}
fn examples(&self) -> Vec<Example> {
@ -44,19 +44,20 @@ impl WholeStreamCommand for Exit {
}
}
pub fn exit(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
pub async fn exit(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let registry = registry.clone();
let stream = async_stream! {
let args = args.evaluate_once(&registry).await?;
let args = args.evaluate_once(&registry).await?;
if args.call_info.args.has("now") {
yield Ok(ReturnSuccess::Action(CommandAction::Exit));
} else {
yield Ok(ReturnSuccess::Action(CommandAction::LeaveShell));
}
let command_action = if args.call_info.args.has("now") {
CommandAction::Exit
} else {
CommandAction::LeaveShell
};
Ok(stream.to_output_stream())
Ok(OutputStream::one(ReturnSuccess::action(command_action)))
}
#[cfg(test)]

View File

@ -40,7 +40,7 @@ impl WholeStreamCommand for FromEML {
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
from_eml(args, registry)
from_eml(args, registry).await
}
}
@ -77,46 +77,54 @@ fn headerfieldvalue_to_value(tag: &Tag, value: &HeaderFieldValue) -> UntaggedVal
}
}
fn from_eml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
async fn from_eml(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let tag = args.call_info.name_tag.clone();
let registry = registry.clone();
let stream = async_stream! {
let (eml_args, mut input): (FromEMLArgs, _) = args.process(&registry).await?;
let value = input.collect_string(tag.clone()).await?;
let (eml_args, input): (FromEMLArgs, _) = args.process(&registry).await?;
let value = input.collect_string(tag.clone()).await?;
let body_preview = eml_args.preview_body.map(|b| b.item).unwrap_or(DEFAULT_BODY_PREVIEW);
let body_preview = eml_args
.preview_body
.map(|b| b.item)
.unwrap_or(DEFAULT_BODY_PREVIEW);
let eml = EmlParser::from_string(value.item)
let eml = EmlParser::from_string(value.item)
.with_body_preview(body_preview)
.parse()
.map_err(|_| ShellError::labeled_error("Could not parse .eml file", "could not parse .eml file", &tag))?;
.map_err(|_| {
ShellError::labeled_error(
"Could not parse .eml file",
"could not parse .eml file",
&tag,
)
})?;
let mut dict = TaggedDictBuilder::new(&tag);
let mut dict = TaggedDictBuilder::new(&tag);
if let Some(subj) = eml.subject {
dict.insert_untagged("Subject", UntaggedValue::string(subj));
}
if let Some(subj) = eml.subject {
dict.insert_untagged("Subject", UntaggedValue::string(subj));
}
if let Some(from) = eml.from {
dict.insert_untagged("From", headerfieldvalue_to_value(&tag, &from));
}
if let Some(from) = eml.from {
dict.insert_untagged("From", headerfieldvalue_to_value(&tag, &from));
}
if let Some(to) = eml.to {
dict.insert_untagged("To", headerfieldvalue_to_value(&tag, &to));
}
if let Some(to) = eml.to {
dict.insert_untagged("To", headerfieldvalue_to_value(&tag, &to));
}
for HeaderField{ name, value } in eml.headers.iter() {
dict.insert_untagged(name, headerfieldvalue_to_value(&tag, &value));
}
for HeaderField { name, value } in eml.headers.iter() {
dict.insert_untagged(name, headerfieldvalue_to_value(&tag, &value));
}
if let Some(body) = eml.body {
dict.insert_untagged("Body", UntaggedValue::string(body));
}
if let Some(body) = eml.body {
dict.insert_untagged("Body", UntaggedValue::string(body));
}
yield ReturnSuccess::value(dict.into_value());
};
Ok(stream.to_output_stream())
Ok(OutputStream::one(ReturnSuccess::value(dict.into_value())))
}
#[cfg(test)]

View File

@ -35,7 +35,7 @@ impl WholeStreamCommand for GroupBy {
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
group_by(args, registry)
group_by(args, registry).await
}
fn examples(&self) -> Vec<Example> {
@ -71,30 +71,27 @@ impl WholeStreamCommand for GroupBy {
}
}
pub fn group_by(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
pub async fn group_by(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let registry = registry.clone();
let name = args.call_info.name_tag.clone();
let stream = async_stream! {
let (GroupByArgs { column_name }, mut input) = args.process(&registry).await?;
let values: Vec<Value> = input.collect().await;
if values.is_empty() {
yield Err(ShellError::labeled_error(
"Expected table from pipeline",
"requires a table input",
name
))
} else {
match crate::utils::data::group(column_name, &values, None, &name) {
Ok(grouped) => yield ReturnSuccess::value(grouped),
Err(err) => yield Err(err),
}
let (GroupByArgs { column_name }, input) = args.process(&registry).await?;
let values: Vec<Value> = input.collect().await;
if values.is_empty() {
Err(ShellError::labeled_error(
"Expected table from pipeline",
"requires a table input",
name,
))
} else {
match crate::utils::data::group(column_name, &values, None, &name) {
Ok(grouped) => Ok(OutputStream::one(ReturnSuccess::value(grouped))),
Err(err) => Err(err),
}
};
Ok(stream.to_output_stream())
}
}
pub fn group(

View File

@ -42,7 +42,7 @@ impl WholeStreamCommand for GroupByDate {
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
group_by_date(args, registry)
group_by_date(args, registry).await
}
fn examples(&self) -> Vec<Example> {
@ -58,50 +58,59 @@ enum Grouper {
ByDate(Option<String>),
}
pub fn group_by_date(
pub async fn group_by_date(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let registry = registry.clone();
let name = args.call_info.name_tag.clone();
let stream = async_stream! {
let (GroupByDateArgs { column_name, format }, mut input) = args.process(&registry).await?;
let values: Vec<Value> = input.collect().await;
let (
GroupByDateArgs {
column_name,
format,
},
input,
) = args.process(&registry).await?;
let values: Vec<Value> = input.collect().await;
if values.is_empty() {
yield Err(ShellError::labeled_error(
"Expected table from pipeline",
"requires a table input",
name
))
if values.is_empty() {
Err(ShellError::labeled_error(
"Expected table from pipeline",
"requires a table input",
name,
))
} else {
let grouper = if let Some(Tagged { item: fmt, tag: _ }) = format {
Grouper::ByDate(Some(fmt))
} else {
Grouper::ByDate(None)
};
let grouper = if let Some(Tagged { item: fmt, tag }) = format {
Grouper::ByDate(Some(fmt))
} else {
Grouper::ByDate(None)
};
match grouper {
Grouper::ByDate(None) => {
match crate::utils::data::group(column_name, &values, Some(Box::new(|row: &Value| row.format("%Y-%b-%d"))), &name) {
Ok(grouped) => yield ReturnSuccess::value(grouped),
Err(err) => yield Err(err),
}
match grouper {
Grouper::ByDate(None) => {
match crate::utils::data::group(
column_name,
&values,
Some(Box::new(|row: &Value| row.format("%Y-%b-%d"))),
&name,
) {
Ok(grouped) => Ok(OutputStream::one(ReturnSuccess::value(grouped))),
Err(err) => Err(err),
}
Grouper::ByDate(Some(fmt)) => {
match crate::utils::data::group(column_name, &values, Some(Box::new(move |row: &Value| {
row.format(&fmt)
})), &name) {
Ok(grouped) => yield ReturnSuccess::value(grouped),
Err(err) => yield Err(err),
}
}
Grouper::ByDate(Some(fmt)) => {
match crate::utils::data::group(
column_name,
&values,
Some(Box::new(move |row: &Value| row.format(&fmt))),
&name,
) {
Ok(grouped) => Ok(OutputStream::one(ReturnSuccess::value(grouped))),
Err(err) => Err(err),
}
}
}
};
Ok(stream.to_output_stream())
}
}
#[cfg(test)]

View File

@ -38,42 +38,37 @@ impl WholeStreamCommand for MapMaxBy {
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
map_max_by(args, registry)
map_max_by(args, registry).await
}
}
pub fn map_max_by(
pub async fn map_max_by(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let registry = registry.clone();
let name = args.call_info.name_tag.clone();
let stream = async_stream! {
let (MapMaxByArgs { column_name }, mut input) = args.process(&registry).await?;
let values: Vec<Value> = input.collect().await;
let (MapMaxByArgs { column_name }, mut input) = args.process(&registry).await?;
let values: Vec<Value> = input.collect().await;
if values.is_empty() {
yield Err(ShellError::labeled_error(
"Expected table from pipeline",
"requires a table input",
name
))
if values.is_empty() {
Err(ShellError::labeled_error(
"Expected table from pipeline",
"requires a table input",
name,
))
} else {
let map_by_column = if let Some(column_to_map) = column_name {
Some(column_to_map.item().clone())
} else {
None
};
let map_by_column = if let Some(column_to_map) = column_name {
Some(column_to_map.item().clone())
} else {
None
};
match map_max(&values[0], map_by_column, name) {
Ok(table_maxed) => yield ReturnSuccess::value(table_maxed),
Err(err) => yield Err(err)
}
match map_max(&values[0], map_by_column, name) {
Ok(table_maxed) => Ok(OutputStream::one(ReturnSuccess::value(table_maxed))),
Err(err) => Err(err),
}
};
Ok(stream.to_output_stream())
}
}
#[cfg(test)]

View File

@ -11,6 +11,8 @@ pub struct Mkdir;
#[derive(Deserialize)]
pub struct MkdirArgs {
pub rest: Vec<Tagged<PathBuf>>,
#[serde(rename = "show-created-paths")]
pub show_created_paths: bool,
}
#[async_trait]
@ -20,7 +22,9 @@ impl WholeStreamCommand for Mkdir {
}
fn signature(&self) -> Signature {
Signature::build("mkdir").rest(SyntaxShape::Path, "the name(s) of the path(s) to create")
Signature::build("mkdir")
.rest(SyntaxShape::Path, "the name(s) of the path(s) to create")
.switch("show-created-paths", "show the path(s) created.", Some('s'))
}
fn usage(&self) -> &str {

View File

@ -42,7 +42,7 @@ impl WholeStreamCommand for Open {
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
open(args, registry)
open(args, registry).await
}
fn examples(&self) -> Vec<Example> {
@ -54,39 +54,33 @@ impl WholeStreamCommand for Open {
}
}
fn open(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
async fn open(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let cwd = PathBuf::from(args.shell_manager.path());
let full_path = cwd;
let registry = registry.clone();
let stream = async_stream! {
let (OpenArgs { path, raw }, _) = args.process(&registry).await?;
let result = fetch(&full_path, &path.item, path.tag.span).await;
let (OpenArgs { path, raw }, _) = args.process(&registry).await?;
let result = fetch(&full_path, &path.item, path.tag.span).await;
if let Err(e) = result {
yield Err(e);
return;
}
let (file_extension, contents, contents_tag) = result?;
let (file_extension, contents, contents_tag) = result?;
let file_extension = if raw.item {
None
} else {
// If the extension could not be determined via mimetype, try to use the path
// extension. Some file types do not declare their mimetypes (such as bson files).
file_extension.or(path.extension().map(|x| x.to_string_lossy().to_string()))
};
let tagged_contents = contents.into_value(&contents_tag);
if let Some(extension) = file_extension {
yield Ok(ReturnSuccess::Action(CommandAction::AutoConvert(tagged_contents, extension)))
} else {
yield ReturnSuccess::value(tagged_contents);
}
let file_extension = if raw.item {
None
} else {
// If the extension could not be determined via mimetype, try to use the path
// extension. Some file types do not declare their mimetypes (such as bson files).
file_extension.or_else(|| path.extension().map(|x| x.to_string_lossy().to_string()))
};
Ok(stream.to_output_stream())
let tagged_contents = contents.into_value(&contents_tag);
if let Some(extension) = file_extension {
Ok(OutputStream::one(ReturnSuccess::action(
CommandAction::AutoConvert(tagged_contents, extension),
)))
} else {
Ok(OutputStream::one(ReturnSuccess::value(tagged_contents)))
}
}
pub async fn fetch(

View File

@ -27,98 +27,106 @@ impl WholeStreamCommand for ToHTML {
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
to_html(args, registry)
to_html(args, registry).await
}
}
fn to_html(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
async fn to_html(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let registry = registry.clone();
let stream = async_stream! {
let args = args.evaluate_once(&registry).await?;
let name_tag = args.name_tag();
let input: Vec<Value> = args.input.collect().await;
let headers = nu_protocol::merge_descriptors(&input);
let mut output_string = "<html><body>".to_string();
let args = args.evaluate_once(&registry).await?;
let name_tag = args.name_tag();
let input: Vec<Value> = args.input.collect().await;
let headers = nu_protocol::merge_descriptors(&input);
let mut output_string = "<html><body>".to_string();
if !headers.is_empty() && (headers.len() > 1 || headers[0] != "") {
output_string.push_str("<table>");
if !headers.is_empty() && (headers.len() > 1 || headers[0] != "") {
output_string.push_str("<table>");
output_string.push_str("<tr>");
for header in &headers {
output_string.push_str("<th>");
output_string.push_str(&htmlescape::encode_minimal(&header));
output_string.push_str("</th>");
}
output_string.push_str("</tr>");
output_string.push_str("<tr>");
for header in &headers {
output_string.push_str("<th>");
output_string.push_str(&htmlescape::encode_minimal(&header));
output_string.push_str("</th>");
}
output_string.push_str("</tr>");
}
for row in input {
match row.value {
UntaggedValue::Primitive(Primitive::Binary(b)) => {
// This might be a bit much, but it's fun :)
match row.tag.anchor {
Some(AnchorLocation::Url(f)) |
Some(AnchorLocation::File(f)) => {
let extension = f.split('.').last().map(String::from);
match extension {
Some(s) if ["png", "jpg", "bmp", "gif", "tiff", "jpeg"].contains(&s.to_lowercase().as_str()) => {
output_string.push_str("<img src=\"data:image/");
output_string.push_str(&s);
output_string.push_str(";base64,");
output_string.push_str(&base64::encode(&b));
output_string.push_str("\">");
}
_ => {}
for row in input {
match row.value {
UntaggedValue::Primitive(Primitive::Binary(b)) => {
// This might be a bit much, but it's fun :)
match row.tag.anchor {
Some(AnchorLocation::Url(f)) | Some(AnchorLocation::File(f)) => {
let extension = f.split('.').last().map(String::from);
match extension {
Some(s)
if ["png", "jpg", "bmp", "gif", "tiff", "jpeg"]
.contains(&s.to_lowercase().as_str()) =>
{
output_string.push_str("<img src=\"data:image/");
output_string.push_str(&s);
output_string.push_str(";base64,");
output_string.push_str(&base64::encode(&b));
output_string.push_str("\">");
}
_ => {}
}
_ => {}
}
}
UntaggedValue::Primitive(Primitive::String(ref b)) => {
// This might be a bit much, but it's fun :)
match row.tag.anchor {
Some(AnchorLocation::Url(f)) |
Some(AnchorLocation::File(f)) => {
let extension = f.split('.').last().map(String::from);
match extension {
Some(s) if s.to_lowercase() == "svg" => {
output_string.push_str("<img src=\"data:image/svg+xml;base64,");
output_string.push_str(&base64::encode(&b.as_bytes()));
output_string.push_str("\">");
continue;
}
_ => {}
}
}
_ => {}
}
output_string.push_str(&(htmlescape::encode_minimal(&format_leaf(&row.value).plain_string(100_000)).replace("\n", "<br>")));
}
UntaggedValue::Row(row) => {
output_string.push_str("<tr>");
for header in &headers {
let data = row.get_data(header);
output_string.push_str("<td>");
output_string.push_str(&format_leaf(data.borrow()).plain_string(100_000));
output_string.push_str("</td>");
}
output_string.push_str("</tr>");
}
p => {
output_string.push_str(&(htmlescape::encode_minimal(&format_leaf(&p).plain_string(100_000)).replace("\n", "<br>")));
_ => {}
}
}
UntaggedValue::Primitive(Primitive::String(ref b)) => {
// This might be a bit much, but it's fun :)
match row.tag.anchor {
Some(AnchorLocation::Url(f)) | Some(AnchorLocation::File(f)) => {
let extension = f.split('.').last().map(String::from);
match extension {
Some(s) if s.to_lowercase() == "svg" => {
output_string.push_str("<img src=\"data:image/svg+xml;base64,");
output_string.push_str(&base64::encode(&b.as_bytes()));
output_string.push_str("\">");
continue;
}
_ => {}
}
}
_ => {}
}
output_string.push_str(
&(htmlescape::encode_minimal(&format_leaf(&row.value).plain_string(100_000))
.replace("\n", "<br>")),
);
}
UntaggedValue::Row(row) => {
output_string.push_str("<tr>");
for header in &headers {
let data = row.get_data(header);
output_string.push_str("<td>");
output_string.push_str(&format_leaf(data.borrow()).plain_string(100_000));
output_string.push_str("</td>");
}
output_string.push_str("</tr>");
}
p => {
output_string.push_str(
&(htmlescape::encode_minimal(&format_leaf(&p).plain_string(100_000))
.replace("\n", "<br>")),
);
}
}
}
if !headers.is_empty() && (headers.len() > 1 || headers[0] != "") {
output_string.push_str("</table>");
}
output_string.push_str("</body></html>");
if !headers.is_empty() && (headers.len() > 1 || headers[0] != "") {
output_string.push_str("</table>");
}
output_string.push_str("</body></html>");
yield ReturnSuccess::value(UntaggedValue::string(output_string).into_value(name_tag));
};
Ok(stream.to_output_stream())
Ok(OutputStream::one(ReturnSuccess::value(
UntaggedValue::string(output_string).into_value(name_tag),
)))
}
#[cfg(test)]

View File

@ -26,55 +26,58 @@ impl WholeStreamCommand for ToMarkdown {
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
to_html(args, registry)
to_html(args, registry).await
}
}
fn to_html(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
async fn to_html(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let registry = registry.clone();
let stream = async_stream! {
let args = args.evaluate_once(&registry).await?;
let name_tag = args.name_tag();
let input: Vec<Value> = args.input.collect().await;
let headers = nu_protocol::merge_descriptors(&input);
let mut output_string = String::new();
let args = args.evaluate_once(&registry).await?;
let name_tag = args.name_tag();
let input: Vec<Value> = args.input.collect().await;
let headers = nu_protocol::merge_descriptors(&input);
let mut output_string = String::new();
if !headers.is_empty() && (headers.len() > 1 || headers[0] != "") {
if !headers.is_empty() && (headers.len() > 1 || headers[0] != "") {
output_string.push_str("|");
for header in &headers {
output_string.push_str(&htmlescape::encode_minimal(&header));
output_string.push_str("|");
for header in &headers {
output_string.push_str(&htmlescape::encode_minimal(&header));
output_string.push_str("|");
}
output_string.push_str("\n|");
for _ in &headers {
output_string.push_str("-");
output_string.push_str("|");
}
output_string.push_str("\n");
}
output_string.push_str("\n|");
for _ in &headers {
output_string.push_str("-");
output_string.push_str("|");
}
output_string.push_str("\n");
}
for row in input {
match row.value {
UntaggedValue::Row(row) => {
for row in input {
match row.value {
UntaggedValue::Row(row) => {
output_string.push_str("|");
for header in &headers {
let data = row.get_data(header);
output_string.push_str(&format_leaf(data.borrow()).plain_string(100_000));
output_string.push_str("|");
for header in &headers {
let data = row.get_data(header);
output_string.push_str(&format_leaf(data.borrow()).plain_string(100_000));
output_string.push_str("|");
}
output_string.push_str("\n");
}
p => {
output_string.push_str(&(htmlescape::encode_minimal(&format_leaf(&p).plain_string(100_000))));
output_string.push_str("\n");
}
output_string.push_str("\n");
}
p => {
output_string.push_str(
&(htmlescape::encode_minimal(&format_leaf(&p).plain_string(100_000))),
);
output_string.push_str("\n");
}
}
}
yield ReturnSuccess::value(UntaggedValue::string(output_string).into_value(name_tag));
};
Ok(stream.to_output_stream())
Ok(OutputStream::one(ReturnSuccess::value(
UntaggedValue::string(output_string).into_value(name_tag),
)))
}
#[cfg(test)]

View File

@ -27,7 +27,7 @@ impl WholeStreamCommand for ToSQLite {
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
to_sqlite(args, registry)
to_sqlite(args, registry).await
}
fn is_binary(&self) -> bool {
@ -56,7 +56,7 @@ impl WholeStreamCommand for ToDB {
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
to_sqlite(args, registry)
to_sqlite(args, registry).await
}
fn is_binary(&self) -> bool {
@ -203,26 +203,23 @@ fn sqlite_input_stream_to_bytes(values: Vec<Value>) -> Result<Value, std::io::Er
Ok(UntaggedValue::binary(out).into_value(tag))
}
fn to_sqlite(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
async fn to_sqlite(
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let registry = registry.clone();
let stream = async_stream! {
let args = args.evaluate_once(&registry).await?;
let name_tag = args.name_tag();
let input: Vec<Value> = args.input.collect().await;
let args = args.evaluate_once(&registry).await?;
let name_tag = args.name_tag();
let input: Vec<Value> = args.input.collect().await;
match sqlite_input_stream_to_bytes(input) {
Ok(out) => yield ReturnSuccess::value(out),
_ => {
yield Err(ShellError::labeled_error(
"Expected a table with SQLite-compatible structure from pipeline",
"requires SQLite-compatible input",
name_tag,
))
},
}
};
Ok(stream.to_output_stream())
match sqlite_input_stream_to_bytes(input) {
Ok(out) => Ok(OutputStream::one(ReturnSuccess::value(out))),
_ => Err(ShellError::labeled_error(
"Expected a table with SQLite-compatible structure from pipeline",
"requires SQLite-compatible input",
name_tag,
)),
}
}
#[cfg(test)]

View File

@ -26,9 +26,22 @@ impl WholeStreamCommand for ToTOML {
) -> Result<OutputStream, ShellError> {
to_toml(args, registry)
}
// TODO: add an example here. What commands to run to get a Row(Dictionary)?
// fn examples(&self) -> Vec<Example> {
// vec![
// Example {
// description:
// "Outputs an TOML string representing TOML document",
// example: "echo [1 2 3] | to json",
// result: Some(vec![Value::from("[1,2,3]")]),
// },
// ]
// }
}
pub fn value_to_toml_value(v: &Value) -> Result<toml::Value, ShellError> {
// Helper method to recursively convert nu_protocol::Value -> toml::Value
// This shouldn't be called at the top-level
fn helper(v: &Value) -> Result<toml::Value, ShellError> {
Ok(match &v.value {
UntaggedValue::Primitive(Primitive::Boolean(b)) => toml::Value::Boolean(*b),
UntaggedValue::Primitive(Primitive::Bytes(b)) => toml::Value::Integer(*b as i64),
@ -66,7 +79,6 @@ pub fn value_to_toml_value(v: &Value) -> Result<toml::Value, ShellError> {
})
.collect::<Result<Vec<toml::Value>, ShellError>>()?,
),
UntaggedValue::Table(l) => toml::Value::Array(collect_values(l)?),
UntaggedValue::Error(e) => return Err(e.clone()),
UntaggedValue::Block(_) => toml::Value::String("<Block>".to_string()),
@ -77,18 +89,47 @@ pub fn value_to_toml_value(v: &Value) -> Result<toml::Value, ShellError> {
UntaggedValue::Row(o) => {
let mut m = toml::map::Map::new();
for (k, v) in o.entries.iter() {
m.insert(k.clone(), value_to_toml_value(v)?);
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<toml::Value, ShellError> {
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(),
)),
}
}
fn collect_values(input: &[Value]) -> Result<Vec<toml::Value>, ShellError> {
let mut out = vec![];
for value in input {
out.push(value_to_toml_value(value)?);
out.push(helper(value)?);
}
Ok(out)
@ -141,7 +182,8 @@ fn to_toml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream
#[cfg(test)]
mod tests {
use super::ToTOML;
use super::*;
use nu_protocol::Dictionary;
#[test]
fn examples_work_as_expected() {
@ -149,4 +191,60 @@ mod tests {
test_examples(ToTOML {})
}
#[test]
fn test_value_to_toml_value() {
//
// Positive Tests
//
// Dictionary -> What we do in "crates/nu-cli/src/data/config.rs" to write the config file
let mut m = indexmap::IndexMap::new();
m.insert("rust".to_owned(), Value::from("editor"));
m.insert("is".to_owned(), Value::nothing());
m.insert(
"features".to_owned(),
UntaggedValue::Table(vec![
UntaggedValue::string("hello").into_untagged_value(),
UntaggedValue::string("array").into_untagged_value(),
])
.into_untagged_value(),
);
let tv = value_to_toml_value(&UntaggedValue::Row(Dictionary::new(m)).into_untagged_value())
.expect("Expected Ok from valid TOML dictionary");
assert_eq!(
tv.get("features"),
Some(&toml::Value::Array(vec![
toml::Value::String("hello".to_owned()),
toml::Value::String("array".to_owned())
]))
);
// TOML string
let tv = value_to_toml_value(&Value::from(
r#"
title = "TOML Example"
[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00 # First class dates
[dependencies]
rustyline = "4.1.0"
sysinfo = "0.8.4"
chrono = { version = "0.4.6", features = ["serde"] }
"#,
))
.expect("Expected Ok from valid TOML string");
assert_eq!(
tv.get("title").unwrap(),
&toml::Value::String("TOML Example".to_owned())
);
//
// Negative Tests
//
value_to_toml_value(&Value::from("not_valid"))
.expect_err("Expected non-valid toml (String) to cause error!");
value_to_toml_value(&UntaggedValue::Table(vec![Value::from("1")]).into_untagged_value())
.expect_err("Expected non-valid toml (Table) to cause error!");
}
}

View File

@ -51,10 +51,10 @@ impl DirectorySpecificEnvironment {
let current_dir = std::env::current_dir()?;
let working_dir = Some(current_dir.as_path());
let keyvals_to_restore = self
self
.overwritten_env_values
.iter()
.filter_map(|(directory, keyvals)| {
.filter(|(directory, keyvals)| {
while let Some(wdir) = working_dir {
if &wdir == directory {
return false;
@ -66,6 +66,8 @@ impl DirectorySpecificEnvironment {
})
.collect();
let mut keyvals_to_restore = IndexMap::new();
Ok(keyvals_to_restore)
}

View File

@ -44,7 +44,7 @@ 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::stream::OutputStream;
pub use crate::stream::{InputStream, InterruptibleStream, OutputStream};
pub use nu_value_ext::ValueExt;
pub use num_traits::cast::ToPrimitive;

View File

@ -396,11 +396,15 @@ impl Shell for FilesystemShell {
fn mkdir(
&self,
MkdirArgs { rest: directories }: MkdirArgs,
MkdirArgs {
rest: directories,
show_created_paths,
}: MkdirArgs,
name: Tag,
path: &str,
) -> Result<OutputStream, ShellError> {
let path = Path::new(path);
let mut stream = VecDeque::new();
if directories.is_empty() {
return Err(ShellError::labeled_error(
@ -413,7 +417,7 @@ impl Shell for FilesystemShell {
for dir in directories.iter() {
let create_at = path.join(&dir.item);
let dir_res = std::fs::create_dir_all(create_at);
let dir_res = std::fs::create_dir_all(&create_at);
if let Err(reason) = dir_res {
return Err(ShellError::labeled_error(
reason.to_string(),
@ -421,9 +425,13 @@ impl Shell for FilesystemShell {
dir.tag(),
));
}
if show_created_paths {
let val = format!("{:}", create_at.to_string_lossy()).into();
stream.push_back(Ok(ReturnSuccess::Value(val)));
}
}
Ok(OutputStream::empty())
Ok(stream.into())
}
fn mv(

View File

@ -24,7 +24,7 @@ fn filesystem_change_from_current_directory_using_absolute_path() {
let actual = nu!(
cwd: dirs.test(),
r#"
cd {}
cd "{}"
pwd | echo $it
"#,
dirs.formats()
@ -113,9 +113,9 @@ fn filesystem_change_current_directory_to_parent_directory_after_delete_cwd() {
let actual = nu!(
cwd: dirs.test().join("foo/bar"),
r#"
rm {}/foo/bar
rm {}/foo/bar
echo ","
cd ..
cd ..
pwd | echo $it
"#,
dirs.test()

View File

@ -8,7 +8,7 @@ fn copies_a_file() {
Playground::setup("cp_test_1", |dirs, _| {
nu!(
cwd: dirs.root(),
"cp {} cp_test_1/sample.ini",
"cp \"{}\" cp_test_1/sample.ini",
dirs.formats().join("sample.ini")
);

View File

@ -1,6 +1,6 @@
use nu_test_support::fs::files_exist_at;
use nu_test_support::nu;
use nu_test_support::playground::Playground;
use nu_test_support::{nu, pipeline};
use std::path::Path;
#[test]
@ -61,3 +61,25 @@ fn create_directory_two_parents_up_using_multiple_dots() {
assert!(expected.exists());
})
}
#[test]
fn show_created_paths() {
Playground::setup("mkdir_test_2", |dirs, _| {
let actual = nu!(
cwd: dirs.test(),
pipeline(
r#"
mkdir -s dir_1 dir_2 dir_3
| count
| echo $it
"#
));
assert!(files_exist_at(
vec![Path::new("dir_1"), Path::new("dir_2"), Path::new("dir_3")],
dirs.test()
));
assert_eq!(actual.out, "3");
})
}

View File

@ -37,7 +37,7 @@ fn writes_out_csv() {
nu!(
cwd: dirs.root(),
"open {}/cargo_sample.toml | get package | save save_test_2/cargo_sample.csv",
"open \"{}/cargo_sample.toml\" | get package | save save_test_2/cargo_sample.csv",
dirs.formats()
);

View File

@ -1,6 +1,6 @@
[package]
name = "nu-errors"
version = "0.14.1"
version = "0.15.0"
authors = ["The Nu Project Contributors"]
edition = "2018"
description = "Core error subsystem for Nushell"
@ -10,7 +10,7 @@ license = "MIT"
doctest = false
[dependencies]
nu-source = { path = "../nu-source", version = "0.14.1" }
nu-source = { path = "../nu-source", version = "0.15.0" }
ansi_term = "0.12.1"
bigdecimal = { version = "0.1.2", features = ["serde"] }
@ -28,4 +28,4 @@ serde_json = "1.0.53"
glob = "0.3.0"
[build-dependencies]
nu-build = { version = "0.14.1", path = "../nu-build" }
nu-build = { version = "0.15.0", path = "../nu-build" }

View File

@ -1,6 +1,6 @@
[package]
name = "nu-parser"
version = "0.14.1"
version = "0.15.0"
authors = ["The Nu Project Contributors"]
edition = "2018"
description = "Nushell parser"
@ -20,9 +20,9 @@ codespan-reporting = "0.9.4"
log = "0.4.8"
shellexpand = "2.0.0"
nu-source = { version = "0.14.1", path = "../nu-source" }
nu-protocol = { version = "0.14.1", path = "../nu-protocol" }
nu-errors = { version = "0.14.1", path = "../nu-errors" }
nu-source = { version = "0.15.0", path = "../nu-source" }
nu-protocol = { version = "0.15.0", path = "../nu-protocol" }
nu-errors = { version = "0.15.0", path = "../nu-errors" }
[features]
stable = []

View File

@ -1,6 +1,6 @@
[package]
name = "nu-plugin"
version = "0.14.1"
version = "0.15.0"
authors = ["The Nu Project Contributors"]
edition = "2018"
description = "Nushell Plugin"
@ -10,10 +10,10 @@ license = "MIT"
doctest = false
[dependencies]
nu-protocol = { path = "../nu-protocol", version = "0.14.1" }
nu-source = { path = "../nu-source", version = "0.14.1" }
nu-errors = { path = "../nu-errors", version = "0.14.1" }
nu-value-ext = { path = "../nu-value-ext", version = "0.14.1" }
nu-protocol = { path = "../nu-protocol", version = "0.15.0" }
nu-source = { path = "../nu-source", version = "0.15.0" }
nu-errors = { path = "../nu-errors", version = "0.15.0" }
nu-value-ext = { path = "../nu-value-ext", version = "0.15.0" }
indexmap = { version = "1.3.2", features = ["serde-1"] }
serde = { version = "1.0.110", features = ["derive"] }
@ -22,4 +22,4 @@ serde_json = "1.0.53"
bigdecimal = { version = "0.1.2", features = ["serde"] }
[build-dependencies]
nu-build = { version = "0.14.1", path = "../nu-build" }
nu-build = { version = "0.15.0", path = "../nu-build" }

View File

@ -1,6 +1,6 @@
[package]
name = "nu-protocol"
version = "0.14.1"
version = "0.15.0"
authors = ["The Nu Project Contributors"]
edition = "2018"
description = "Core values and protocols for Nushell"
@ -10,8 +10,8 @@ license = "MIT"
doctest = false
[dependencies]
nu-source = { path = "../nu-source", version = "0.14.1" }
nu-errors = { path = "../nu-errors", version = "0.14.1" }
nu-source = { path = "../nu-source", version = "0.15.0" }
nu-errors = { path = "../nu-errors", version = "0.15.0" }
serde = { version = "1.0.110", features = ["derive"] }
indexmap = { version = "1.3.2", features = ["serde-1"] }
@ -37,4 +37,4 @@ toml = "0.5.6"
serde_json = "1.0.53"
[build-dependencies]
nu-build = { version = "0.14.1", path = "../nu-build" }
nu-build = { version = "0.15.0", path = "../nu-build" }

View File

@ -1,6 +1,6 @@
[package]
name = "nu-source"
version = "0.14.1"
version = "0.15.0"
authors = ["The Nu Project Contributors"]
edition = "2018"
description = "A source string characterizer for Nushell"
@ -18,4 +18,4 @@ termcolor = "1.1.0"
pretty = "0.5.2"
[build-dependencies]
nu-build = { version = "0.14.1", path = "../nu-build" }
nu-build = { version = "0.15.0", path = "../nu-build" }

View File

@ -1,6 +1,6 @@
[package]
name = "nu-test-support"
version = "0.14.1"
version = "0.15.0"
authors = ["The Nu Project Contributors"]
edition = "2018"
description = "A source string characterizer for Nushell"
@ -10,9 +10,9 @@ license = "MIT"
doctest = false
[dependencies]
nu-parser = { path = "../nu-parser", version = "0.14.1" }
nu-source = { path = "../nu-source", version = "0.14.1" }
nu-protocol = { path = "../nu-protocol", version = "0.14.1" }
nu-parser = { path = "../nu-parser", version = "0.15.0" }
nu-source = { path = "../nu-source", version = "0.15.0" }
nu-protocol = { path = "../nu-protocol", version = "0.15.0" }
directories = "2.0.2"
dunce = "1.0.0"
@ -22,4 +22,4 @@ tempfile = "3.1.0"
indexmap = { version = "1.3.2", features = ["serde-1"] }
[build-dependencies]
nu-build = { version = "0.14.1", path = "../nu-build" }
nu-build = { version = "0.15.0", path = "../nu-build" }

View File

@ -1,6 +1,6 @@
[package]
name = "nu-value-ext"
version = "0.14.1"
version = "0.15.0"
authors = ["The Nu Project Contributors"]
edition = "2018"
description = "Extension traits for values in Nushell"
@ -10,14 +10,14 @@ license = "MIT"
doctest = false
[dependencies]
nu-source = { path = "../nu-source", version = "0.14.1" }
nu-errors = { path = "../nu-errors", version = "0.14.1" }
nu-parser = { path = "../nu-parser", version = "0.14.1" }
nu-protocol = { path = "../nu-protocol", version = "0.14.1" }
nu-source = { path = "../nu-source", version = "0.15.0" }
nu-errors = { path = "../nu-errors", version = "0.15.0" }
nu-parser = { path = "../nu-parser", version = "0.15.0" }
nu-protocol = { path = "../nu-protocol", version = "0.15.0" }
num-traits = "0.2.11"
itertools = "0.9.0"
indexmap = { version = "1.3.2", features = ["serde-1"] }
[build-dependencies]
nu-build = { version = "0.14.1", path = "../nu-build" }
nu-build = { version = "0.15.0", path = "../nu-build" }

View File

@ -1,6 +1,6 @@
[package]
name = "nu_plugin_binaryview"
version = "0.14.1"
version = "0.15.0"
authors = ["The Nu Project Contributors"]
edition = "2018"
description = "A binary viewer plugin for Nushell"
@ -12,14 +12,14 @@ doctest = false
[dependencies]
ansi_term = "0.12.1"
crossterm = { version = "0.17.5" }
nu-plugin = { path = "../nu-plugin", version = "0.14.1" }
nu-protocol = { path = "../nu-protocol", version = "0.14.1" }
nu-source = { path = "../nu-source", version = "0.14.1" }
nu-errors = { path = "../nu-errors", version = "0.14.1" }
nu-plugin = { path = "../nu-plugin", version = "0.15.0" }
nu-protocol = { path = "../nu-protocol", version = "0.15.0" }
nu-source = { path = "../nu-source", version = "0.15.0" }
nu-errors = { path = "../nu-errors", version = "0.15.0" }
pretty-hex = "0.1.1"
image = { version = "0.22.4", default_features = false, features = ["png_codec", "jpeg"] }
rawkey = "0.1.2"
neso = "0.5.0"
[build-dependencies]
nu-build = { version = "0.14.1", path = "../nu-build" }
nu-build = { version = "0.15.0", path = "../nu-build" }

View File

@ -1,6 +1,6 @@
[package]
name = "nu_plugin_fetch"
version = "0.14.1"
version = "0.15.0"
authors = ["The Nu Project Contributors"]
edition = "2018"
description = "A URL fetch plugin for Nushell"
@ -10,14 +10,14 @@ license = "MIT"
doctest = false
[dependencies]
nu-plugin = { path = "../nu-plugin", version = "0.14.1" }
nu-protocol = { path = "../nu-protocol", version = "0.14.1" }
nu-source = { path = "../nu-source", version = "0.14.1" }
nu-errors = { path = "../nu-errors", version = "0.14.1" }
nu-plugin = { path = "../nu-plugin", version = "0.15.0" }
nu-protocol = { path = "../nu-protocol", version = "0.15.0" }
nu-source = { path = "../nu-source", version = "0.15.0" }
nu-errors = { path = "../nu-errors", version = "0.15.0" }
futures = { version = "0.3", features = ["compat", "io-compat"] }
surf = "1.0.3"
url = "2.1.1"
base64 = "0.12.1"
[build-dependencies]
nu-build = { version = "0.14.1", path = "../nu-build" }
nu-build = { version = "0.15.0", path = "../nu-build" }

View File

@ -1,6 +1,6 @@
[package]
name = "nu_plugin_inc"
version = "0.14.1"
version = "0.15.0"
authors = ["The Nu Project Contributors"]
edition = "2018"
description = "A version incrementer plugin for Nushell"
@ -10,13 +10,13 @@ license = "MIT"
doctest = false
[dependencies]
nu-plugin = { path = "../nu-plugin", version = "0.14.1" }
nu-protocol = { path = "../nu-protocol", version = "0.14.1" }
nu-source = { path = "../nu-source", version = "0.14.1" }
nu-errors = { path = "../nu-errors", version = "0.14.1" }
nu-value-ext = { path = "../nu-value-ext", version = "0.14.1" }
nu-plugin = { path = "../nu-plugin", version = "0.15.0" }
nu-protocol = { path = "../nu-protocol", version = "0.15.0" }
nu-source = { path = "../nu-source", version = "0.15.0" }
nu-errors = { path = "../nu-errors", version = "0.15.0" }
nu-value-ext = { path = "../nu-value-ext", version = "0.15.0" }
semver = "0.10.0"
[build-dependencies]
nu-build = { version = "0.14.1", path = "../nu-build" }
nu-build = { version = "0.15.0", path = "../nu-build" }

View File

@ -1,6 +1,6 @@
[package]
name = "nu_plugin_match"
version = "0.14.1"
version = "0.15.0"
authors = ["The Nu Project Contributors"]
edition = "2018"
description = "A regex match plugin for Nushell"
@ -10,12 +10,12 @@ license = "MIT"
doctest = false
[dependencies]
nu-plugin = { path = "../nu-plugin", version = "0.14.1" }
nu-protocol = { path = "../nu-protocol", version = "0.14.1" }
nu-source = { path = "../nu-source", version = "0.14.1" }
nu-errors = { path = "../nu-errors", version = "0.14.1" }
nu-plugin = { path = "../nu-plugin", version = "0.15.0" }
nu-protocol = { path = "../nu-protocol", version = "0.15.0" }
nu-source = { path = "../nu-source", version = "0.15.0" }
nu-errors = { path = "../nu-errors", version = "0.15.0" }
futures = { version = "0.3", features = ["compat", "io-compat"] }
regex = "1"
[build-dependencies]
nu-build = { version = "0.14.1", path = "../nu-build" }
nu-build = { version = "0.15.0", path = "../nu-build" }

View File

@ -1,6 +1,6 @@
[package]
name = "nu_plugin_post"
version = "0.14.1"
version = "0.15.0"
authors = ["The Nu Project Contributors"]
edition = "2018"
description = "An HTTP post plugin for Nushell"
@ -10,10 +10,10 @@ license = "MIT"
doctest = false
[dependencies]
nu-plugin = { path = "../nu-plugin", version = "0.14.1" }
nu-protocol = { path = "../nu-protocol", version = "0.14.1" }
nu-source = { path = "../nu-source", version = "0.14.1" }
nu-errors = { path = "../nu-errors", version = "0.14.1" }
nu-plugin = { path = "../nu-plugin", version = "0.15.0" }
nu-protocol = { path = "../nu-protocol", version = "0.15.0" }
nu-source = { path = "../nu-source", version = "0.15.0" }
nu-errors = { path = "../nu-errors", version = "0.15.0" }
futures = { version = "0.3", features = ["compat", "io-compat"] }
surf = "1.0.3"
url = "2.1.1"
@ -22,4 +22,4 @@ base64 = "0.12.1"
num-traits = "0.2.11"
[build-dependencies]
nu-build = { version = "0.14.1", path = "../nu-build" }
nu-build = { version = "0.15.0", path = "../nu-build" }

View File

@ -1,6 +1,6 @@
[package]
name = "nu_plugin_ps"
version = "0.14.1"
version = "0.15.0"
authors = ["The Nu Project Contributors"]
edition = "2018"
description = "A process list plugin for Nushell"
@ -10,18 +10,18 @@ license = "MIT"
doctest = false
[dependencies]
nu-plugin = { path = "../nu-plugin", version = "0.14.1" }
nu-protocol = { path = "../nu-protocol", version = "0.14.1" }
nu-source = { path = "../nu-source", version = "0.14.1" }
nu-errors = { path = "../nu-errors", version = "0.14.1" }
nu-plugin = { path = "../nu-plugin", version = "0.15.0" }
nu-protocol = { path = "../nu-protocol", version = "0.15.0" }
nu-source = { path = "../nu-source", version = "0.15.0" }
nu-errors = { path = "../nu-errors", version = "0.15.0" }
futures = { version = "0.3", features = ["compat", "io-compat"] }
futures-timer = "3.0.2"
[dependencies.heim]
version = "0.1.0-beta.1"
version = "0.1.0-beta.2"
default-features = false
features = ["process"]
[build-dependencies]
nu-build = { version = "0.14.1", path = "../nu-build" }
nu-build = { version = "0.15.0", path = "../nu-build" }

View File

@ -1,6 +1,6 @@
[package]
name = "nu_plugin_start"
version = "0.1.0"
version = "0.15.0"
authors = ["The Nu Project Contributors"]
edition = "2018"
description = "A plugin to open files/URLs directly from Nushell"
@ -10,15 +10,15 @@ license = "MIT"
doctest = false
[dependencies]
nu-plugin = { path = "../nu-plugin", version = "0.14.1" }
nu-protocol = { path = "../nu-protocol", version = "0.14.1" }
nu-source = { path = "../nu-source", version = "0.14.1" }
nu-errors = { path = "../nu-errors", version = "0.14.1" }
nu-plugin = { path = "../nu-plugin", version = "0.15.0" }
nu-protocol = { path = "../nu-protocol", version = "0.15.0" }
nu-source = { path = "../nu-source", version = "0.15.0" }
nu-errors = { path = "../nu-errors", version = "0.15.0" }
url = "2.1.1"
open = "1.4.0"
glob = "0.3.0"
[build-dependencies]
nu-build = { version = "0.14.1", path = "../nu-build" }
nu-errors = { version = "0.14.1", path = "../nu-errors" }
nu-source = { version = "0.14.1", path = "../nu-source" }
nu-build = { version = "0.15.0", path = "../nu-build" }
nu-errors = { version = "0.15.0", path = "../nu-errors" }
nu-source = { version = "0.15.0", path = "../nu-source" }

View File

@ -1,6 +1,6 @@
[package]
name = "nu_plugin_sys"
version = "0.14.1"
version = "0.15.0"
authors = ["The Nu Project Contributors"]
edition = "2018"
description = "A system info plugin for Nushell"
@ -10,20 +10,20 @@ license = "MIT"
doctest = false
[dependencies]
nu-plugin = { path = "../nu-plugin", version = "0.14.1" }
nu-protocol = { path = "../nu-protocol", version = "0.14.1" }
nu-source = { path = "../nu-source", version = "0.14.1" }
nu-errors = { path = "../nu-errors", version = "0.14.1" }
nu-plugin = { path = "../nu-plugin", version = "0.15.0" }
nu-protocol = { path = "../nu-protocol", version = "0.15.0" }
nu-source = { path = "../nu-source", version = "0.15.0" }
nu-errors = { path = "../nu-errors", version = "0.15.0" }
futures = { version = "0.3", features = ["compat", "io-compat"] }
battery = "0.7.5"
futures-util = "0.3.5"
[dependencies.heim]
version = "0.1.0-beta.1"
version = "0.1.0-beta.2"
default-features = false
features = ["host", "cpu", "memory", "disk", "net", "sensors"]
[build-dependencies]
nu-build = { version = "0.14.1", path = "../nu-build" }
nu-build = { version = "0.15.0", path = "../nu-build" }

View File

@ -1,6 +1,6 @@
[package]
name = "nu_plugin_textview"
version = "0.14.1"
version = "0.15.0"
authors = ["The Nu Project Contributors"]
edition = "2018"
description = "Text viewer plugin for Nushell"
@ -10,10 +10,10 @@ license = "MIT"
doctest = false
[dependencies]
nu-plugin = { path = "../nu-plugin", version = "0.14.1" }
nu-protocol = { path = "../nu-protocol", version = "0.14.1" }
nu-source = { path = "../nu-source", version = "0.14.1" }
nu-errors = { path = "../nu-errors", version = "0.14.1" }
nu-plugin = { path = "../nu-plugin", version = "0.15.0" }
nu-protocol = { path = "../nu-protocol", version = "0.15.0" }
nu-source = { path = "../nu-source", version = "0.15.0" }
nu-errors = { path = "../nu-errors", version = "0.15.0" }
crossterm = "0.17.5"
syntect = { version = "4.2", default-features = false, features = ["default-fancy"]}
@ -21,4 +21,4 @@ ansi_term = "0.12.1"
url = "2.1.1"
[build-dependencies]
nu-build = { version = "0.14.1", path = "../nu-build" }
nu-build = { version = "0.15.0", path = "../nu-build" }

View File

@ -1,6 +1,6 @@
[package]
name = "nu_plugin_tree"
version = "0.14.1"
version = "0.15.0"
authors = ["The Nu Project Contributors"]
edition = "2018"
description = "Tree viewer plugin for Nushell"
@ -10,12 +10,12 @@ license = "MIT"
doctest = false
[dependencies]
nu-plugin = { path = "../nu-plugin", version = "0.14.1" }
nu-protocol = { path = "../nu-protocol", version = "0.14.1" }
nu-source = { path = "../nu-source", version = "0.14.1" }
nu-errors = { path = "../nu-errors", version = "0.14.1" }
nu-plugin = { path = "../nu-plugin", version = "0.15.0" }
nu-protocol = { path = "../nu-protocol", version = "0.15.0" }
nu-source = { path = "../nu-source", version = "0.15.0" }
nu-errors = { path = "../nu-errors", version = "0.15.0" }
ptree = {version = "0.2" }
derive-new = "0.5.8"
[build-dependencies]
nu-build = { version = "0.14.1", path = "../nu-build" }
nu-build = { version = "0.15.0", path = "../nu-build" }

View File

@ -83,7 +83,7 @@ version = "0.4.6"
[dependencies.cursive]
default-features = false
features = ["pancurses-backend"]
version = "0.14.1"
version = "0.15.0"
[dependencies.futures-preview]
features = ["compat", "io-compat"]