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

This commit is contained in:
Yehuda Katz 2019-09-02 21:53:26 -07:00
commit fa859f1461
13 changed files with 221 additions and 203 deletions

View File

@ -4,6 +4,6 @@ root = true
indent_style = space indent_style = space
indent_size = 4 indent_size = 4
charset = utf-8 charset = utf-8
trim_trailing_whitespace = false trim_trailing_whitespace = true
insert_final_newline = false insert_final_newline = false
end_of_line = lf end_of_line = lf

View File

@ -1,5 +1,4 @@
#![feature(generators)] #![feature(generators)]
#![feature(specialization)]
#![feature(proc_macro_hygiene)] #![feature(proc_macro_hygiene)]
#[macro_use] #[macro_use]

View File

@ -146,7 +146,7 @@ impl TaggedDictBuilder {
dict: IndexMap::default(), dict: IndexMap::default(),
} }
} }
pub fn with_capacity(tag: impl Into<Tag>, n: usize) -> TaggedDictBuilder { pub fn with_capacity(tag: impl Into<Tag>, n: usize) -> TaggedDictBuilder {
TaggedDictBuilder { TaggedDictBuilder {
tag: tag.into(), tag: tag.into(),

View File

@ -1,4 +1,3 @@
use crate::object::base as value;
use crate::prelude::*; use crate::prelude::*;
use log::trace; use log::trace;
@ -6,29 +5,6 @@ pub trait ExtractType: Sized {
fn extract(value: &Tagged<Value>) -> Result<Self, ShellError>; fn extract(value: &Tagged<Value>) -> Result<Self, ShellError>;
} }
impl<T> ExtractType for T {
default fn extract(_value: &Tagged<Value>) -> Result<T, ShellError> {
let name = std::any::type_name::<T>();
Err(ShellError::unimplemented(format!(
"<T> ExtractType for {}",
name
)))
}
}
impl<T: ExtractType> ExtractType for Option<T> {
fn extract(value: &Tagged<Value>) -> Result<Option<T>, ShellError> {
let name = std::any::type_name::<T>();
trace!("<Option> Extracting {:?} for Option<{}>", value, name);
let result = match value.item() {
Value::Primitive(Primitive::Nothing) => None,
_ => Some(T::extract(value)?),
};
Ok(result)
}
}
impl<T: ExtractType> ExtractType for Tagged<T> { impl<T: ExtractType> ExtractType for Tagged<T> {
fn extract(value: &Tagged<Value>) -> Result<Tagged<T>, ShellError> { fn extract(value: &Tagged<Value>) -> Result<Tagged<T>, ShellError> {
let name = std::any::type_name::<T>(); let name = std::any::type_name::<T>();
@ -38,14 +14,6 @@ impl<T: ExtractType> ExtractType for Tagged<T> {
} }
} }
impl ExtractType for Value {
fn extract(value: &Tagged<Value>) -> Result<Value, ShellError> {
trace!("<Tagged> Extracting {:?} for Value", value);
Ok(value.item().clone())
}
}
impl ExtractType for bool { impl ExtractType for bool {
fn extract(value: &Tagged<Value>) -> Result<bool, ShellError> { fn extract(value: &Tagged<Value>) -> Result<bool, ShellError> {
trace!("Extracting {:?} for bool", value); trace!("Extracting {:?} for bool", value);
@ -119,15 +87,3 @@ impl ExtractType for String {
} }
} }
} }
impl ExtractType for value::Block {
fn extract(value: &Tagged<Value>) -> Result<value::Block, ShellError> {
match value {
Tagged {
item: Value::Block(block),
..
} => Ok(block.clone()),
other => Err(ShellError::type_error("Block", other.tagged_type_name())),
}
}
}

View File

@ -1,6 +1,7 @@
use crate::prelude::*; use crate::prelude::*;
use log::trace; use log::trace;
use serde::de; use serde::de;
use std::path::PathBuf;
#[derive(Debug)] #[derive(Debug)]
pub struct DeserializerItem<'de> { pub struct DeserializerItem<'de> {
@ -58,7 +59,7 @@ impl<'de> ConfigDeserializer<'de> {
Ok(()) Ok(())
} }
pub fn top(&mut self) -> &DeserializerItem { pub fn top(&mut self) -> &DeserializerItem {
let value = self.stack.last(); let value = self.stack.last();
trace!("inspecting top value :: {:?}", value); trace!("inspecting top value :: {:?}", value);
@ -191,7 +192,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut ConfigDeserializer<'de> {
{ {
unimplemented!("deserialize_byte_buf") unimplemented!("deserialize_byte_buf")
} }
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where where
V: Visitor<'de>, V: Visitor<'de>,
@ -293,6 +294,22 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut ConfigDeserializer<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
fn visit<'de, T, V>(
val: T,
name: &'static str,
fields: &'static [&'static str],
visitor: V
) -> Result<V::Value, ShellError>
where
T: serde::Serialize,
V: Visitor<'de>,
{
let json = serde_json::to_string(&val)?;
let json_cursor = std::io::Cursor::new(json.into_bytes());
let mut json_de = serde_json::Deserializer::from_reader(json_cursor);
let r = json_de.deserialize_struct(name, fields, visitor)?;
return Ok(r);
}
trace!( trace!(
"deserializing struct {:?} {:?} (stack={:?})", "deserializing struct {:?} {:?} (stack={:?})",
name, name,
@ -300,14 +317,60 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut ConfigDeserializer<'de> {
self.stack self.stack
); );
if self.saw_root { if !self.saw_root {
let value = self.pop();
let name = std::any::type_name::<V::Value>();
trace!("Extracting {:?} for {:?}", value.val, name);
V::Value::extract(&value.val)
} else {
self.saw_root = true; self.saw_root = true;
visitor.visit_seq(StructDeserializer::new(&mut self, fields)) return visitor.visit_seq(StructDeserializer::new(&mut self, fields));
}
let value = self.pop();
let type_name = std::any::type_name::<V::Value>();
let tagged_val_name = std::any::type_name::<Tagged<Value>>();
if name == tagged_val_name {
return visit::<Tagged<Value>, _>(value.val, name, fields, visitor);
}
if name == "Block" {
let block = match value.val {
Tagged {
item: Value::Block(block),
..
} => block,
other => return Err(ShellError::type_error("Block", other.tagged_type_name())),
};
return visit::<value::Block, _>(block, name, fields, visitor);
}
trace!("Extracting {:?} for {:?}", value.val, type_name);
let tag = value.val.tag();
match value.val {
Tagged {
item: Value::Primitive(Primitive::Boolean(b)),
..
} => visit::<Tagged<bool>, _>(b.tagged(tag), name, fields, visitor),
Tagged {
item: Value::Primitive(Primitive::Nothing),
..
} => visit::<Tagged<bool>, _>(false.tagged(tag), name, fields, visitor),
Tagged {
item: Value::Primitive(Primitive::Path(p)),
..
} => visit::<Tagged<PathBuf>, _>(p.clone().tagged(tag), name, fields, visitor),
Tagged {
item: Value::Primitive(Primitive::Int(int)),
..
} => {
let i: i64 = int.tagged(value.val.tag).coerce_into("converting to i64")?;
visit::<Tagged<i64>, _>(i.tagged(tag), name, fields, visitor)
},
Tagged {
item: Value::Primitive(Primitive::String(string)),
..
} => visit::<Tagged<String>, _>(string.tagged(tag), name, fields, visitor),
other => return Err(ShellError::type_error(name, other.tagged_type_name())),
} }
} }
fn deserialize_enum<V>( fn deserialize_enum<V>(

View File

@ -37,8 +37,8 @@ impl NuCompleter {
} }
} }
let line_chars: Vec<_> = line.chars().collect(); let line_chars: Vec<_> = line[..pos].chars().collect();
let mut replace_pos = pos; let mut replace_pos = line_chars.len();
while replace_pos > 0 { while replace_pos > 0 {
if line_chars[replace_pos - 1] == ' ' { if line_chars[replace_pos - 1] == ' ' {
break; break;

View File

@ -104,7 +104,7 @@ fn deep_copies_with_recursive_flag() {
let yehudas_expected_copied_dir = expected_dir.join("contributors").join("yehuda"); let yehudas_expected_copied_dir = expected_dir.join("contributors").join("yehuda");
nu!( nu!(
cwd: dirs.test(), cwd: dirs.test(),
"cp originals expected --recursive" "cp originals expected --recursive"
); );

View File

@ -16,13 +16,13 @@ fn ls_lists_regular_files() {
let actual = nu!( let actual = nu!(
cwd: dirs.test(), h::pipeline( cwd: dirs.test(), h::pipeline(
r#" r#"
ls ls
| get name | get name
| lines | lines
| split-column "." | split-column "."
| get Column2 | get Column2
| str --to-int | str --to-int
| sum | sum
| echo $it | echo $it
"# "#
)); ));
@ -45,13 +45,13 @@ fn ls_lists_regular_files_using_asterisk_wildcard() {
let actual = nu!( let actual = nu!(
cwd: dirs.test(), h::pipeline( cwd: dirs.test(), h::pipeline(
r#" r#"
ls *.txt ls *.txt
| get name | get name
| lines | lines
| split-column "." | split-column "."
| get Column2 | get Column2
| str --to-int | str --to-int
| sum | sum
| echo $it | echo $it
"# "#
)); ));
@ -74,13 +74,13 @@ fn ls_lists_regular_files_using_question_mark_wildcard() {
let actual = nu!( let actual = nu!(
cwd: dirs.test(), h::pipeline( cwd: dirs.test(), h::pipeline(
r#" r#"
ls *.??.txt ls *.??.txt
| get name | get name
| lines | lines
| split-column "." | split-column "."
| get Column2 | get Column2
| str --to-int | str --to-int
| sum | sum
| echo $it | echo $it
"# "#
)); ));

View File

@ -28,7 +28,7 @@ fn overwrites_if_moving_to_existing_file() {
Playground::setup("mv_test_2", |dirs, sandbox| { Playground::setup("mv_test_2", |dirs, sandbox| {
sandbox sandbox
.with_files(vec![ .with_files(vec![
EmptyFile("andres.txt"), EmptyFile("andres.txt"),
EmptyFile("jonathan.txt") EmptyFile("jonathan.txt")
]); ]);

View File

@ -8,14 +8,14 @@ fn lines() {
let actual = nu!( let actual = nu!(
cwd: "tests/fixtures/formats", h::pipeline( cwd: "tests/fixtures/formats", h::pipeline(
r#" r#"
open cargo_sample.toml --raw open cargo_sample.toml --raw
| lines | lines
| skip-while $it != "[dependencies]" | skip-while $it != "[dependencies]"
| skip 1 | skip 1
| first 1 | first 1
| split-column "=" | split-column "="
| get Column1 | get Column1
| trim | trim
| echo $it | echo $it
"# "#
)); ));

View File

@ -73,7 +73,7 @@ fn upcases() {
cwd: dirs.test(), cwd: dirs.test(),
"open sample.toml | str package.name --upcase | get package.name | echo $it" "open sample.toml | str package.name --upcase | get package.name | echo $it"
); );
assert_eq!(actual, "NUSHELL"); assert_eq!(actual, "NUSHELL");
}) })
} }
@ -83,11 +83,11 @@ fn converts_to_int() {
let actual = nu!( let actual = nu!(
cwd: "tests/fixtures/formats", h::pipeline( cwd: "tests/fixtures/formats", h::pipeline(
r#" r#"
open caco3_plastics.csv open caco3_plastics.csv
| first 1 | first 1
| str tariff_item --to-int | str tariff_item --to-int
| where tariff_item == 2509000000 | where tariff_item == 2509000000
| get tariff_item | get tariff_item
| echo $it | echo $it
"# "#
)); ));
@ -110,9 +110,9 @@ fn replaces() {
let actual = nu!( let actual = nu!(
cwd: dirs.test(), h::pipeline( cwd: dirs.test(), h::pipeline(
r#" r#"
open sample.toml open sample.toml
| str package.name --replace wykittenshell | str package.name --replace wykittenshell
| get package.name | get package.name
| echo $it | echo $it
"# "#
)); ));
@ -136,9 +136,9 @@ fn find_and_replaces() {
let actual = nu!( let actual = nu!(
cwd: dirs.test(), h::pipeline( cwd: dirs.test(), h::pipeline(
r#" r#"
open sample.toml open sample.toml
| str fortune.teller.phone --find-replace KATZ "5289" | str fortune.teller.phone --find-replace KATZ "5289"
| get fortune.teller.phone | get fortune.teller.phone
| echo $it | echo $it
"# "#
)); ));
@ -162,9 +162,9 @@ fn find_and_replaces_without_passing_field() {
let actual = nu!( let actual = nu!(
cwd: dirs.test(), h::pipeline( cwd: dirs.test(), h::pipeline(
r#" r#"
open sample.toml open sample.toml
| get fortune.teller.phone | get fortune.teller.phone
| str --find-replace KATZ "5289" | str --find-replace KATZ "5289"
| echo $it | echo $it
"# "#
)); ));

View File

@ -28,13 +28,13 @@ fn converts_structured_table_to_csv_text() {
let actual = nu!( let actual = nu!(
cwd: dirs.test(), h::pipeline( cwd: dirs.test(), h::pipeline(
r#" r#"
open csv_text_sample.txt open csv_text_sample.txt
| lines | lines
| split-column "," a b c d origin | split-column "," a b c d origin
| last 1 | last 1
| to-csv | to-csv
| lines | lines
| nth 1 | nth 1
| echo "$it" | echo "$it"
"# "#
)); ));
@ -58,11 +58,11 @@ fn converts_structured_table_to_csv_text_skipping_headers_after_conversion() {
let actual = nu!( let actual = nu!(
cwd: dirs.test(), h::pipeline( cwd: dirs.test(), h::pipeline(
r#" r#"
open csv_text_sample.txt open csv_text_sample.txt
| lines | lines
| split-column "," a b c d origin | split-column "," a b c d origin
| last 1 | last 1
| to-csv --headerless | to-csv --headerless
| echo "$it" | echo "$it"
"# "#
)); ));
@ -87,11 +87,11 @@ fn converts_from_csv_text_to_structured_table() {
let actual = nu!( let actual = nu!(
cwd: dirs.test(), h::pipeline( cwd: dirs.test(), h::pipeline(
r#" r#"
open los_tres_caballeros.txt open los_tres_caballeros.txt
| from-csv | from-csv
| get rusty_luck | get rusty_luck
| str --to-int | str --to-int
| sum | sum
| echo $it | echo $it
"# "#
)); ));
@ -116,11 +116,11 @@ fn converts_from_csv_text_skipping_headers_to_structured_table() {
let actual = nu!( let actual = nu!(
cwd: dirs.test(), h::pipeline( cwd: dirs.test(), h::pipeline(
r#" r#"
open los_tres_amigos.txt open los_tres_amigos.txt
| from-csv --headerless | from-csv --headerless
| get Column3 | get Column3
| str --to-int | str --to-int
| sum | sum
| echo $it | echo $it
"# "#
)); ));
@ -134,10 +134,10 @@ fn can_convert_table_to_json_text_and_from_json_text_back_into_table() {
let actual = nu!( let actual = nu!(
cwd: "tests/fixtures/formats", h::pipeline( cwd: "tests/fixtures/formats", h::pipeline(
r#" r#"
open sgml_description.json open sgml_description.json
| to-json | to-json
| from-json | from-json
| get glossary.GlossDiv.GlossList.GlossEntry.GlossSee | get glossary.GlossDiv.GlossList.GlossEntry.GlossSee
| echo $it | echo $it
"# "#
)); ));
@ -153,8 +153,8 @@ fn converts_from_json_text_to_structured_table() {
r#" r#"
{ {
"katz": [ "katz": [
{"name": "Yehuda", "rusty_luck": 1}, {"name": "Yehuda", "rusty_luck": 1},
{"name": "Jonathan", "rusty_luck": 1}, {"name": "Jonathan", "rusty_luck": 1},
{"name": "Andres", "rusty_luck": 1}, {"name": "Andres", "rusty_luck": 1},
{"name":"GorbyPuff", "rusty_luck": 1} {"name":"GorbyPuff", "rusty_luck": 1}
] ]
@ -177,8 +177,8 @@ fn converts_from_json_text_recognizing_objects_independendtly_to_structured_tabl
sandbox.with_files(vec![FileWithContentToBeTrimmed( sandbox.with_files(vec![FileWithContentToBeTrimmed(
"katz.txt", "katz.txt",
r#" r#"
{"name": "Yehuda", "rusty_luck": 1} {"name": "Yehuda", "rusty_luck": 1}
{"name": "Jonathan", "rusty_luck": 1} {"name": "Jonathan", "rusty_luck": 1}
{"name": "Andres", "rusty_luck": 1} {"name": "Andres", "rusty_luck": 1}
{"name":"GorbyPuff", "rusty_luck": 3} {"name":"GorbyPuff", "rusty_luck": 3}
"#, "#,
@ -187,10 +187,10 @@ fn converts_from_json_text_recognizing_objects_independendtly_to_structured_tabl
let actual = nu!( let actual = nu!(
cwd: dirs.test(), h::pipeline( cwd: dirs.test(), h::pipeline(
r#" r#"
open katz.txt open katz.txt
| from-json --objects | from-json --objects
| where name == "GorbyPuff" | where name == "GorbyPuff"
| get rusty_luck | get rusty_luck
| echo $it | echo $it
"# "#
)); ));
@ -213,14 +213,14 @@ fn converts_structured_table_to_json_text() {
let actual = nu!( let actual = nu!(
cwd: dirs.test(), h::pipeline( cwd: dirs.test(), h::pipeline(
r#" r#"
open sample.txt open sample.txt
| lines | lines
| split-column "," name luck | split-column "," name luck
| pick name | pick name
| to-json | to-json
| nth 0 | nth 0
| from-json | from-json
| get name | get name
| echo $it | echo $it
"# "#
)); ));
@ -254,13 +254,13 @@ fn converts_structured_table_to_tsv_text() {
let actual = nu!( let actual = nu!(
cwd: dirs.test(), h::pipeline( cwd: dirs.test(), h::pipeline(
r#" r#"
open tsv_text_sample.txt open tsv_text_sample.txt
| lines | lines
| split-column "\t" a b c d origin | split-column "\t" a b c d origin
| last 1 | last 1
| to-tsv | to-tsv
| lines | lines
| nth 1 | nth 1
| echo "$it" | echo "$it"
"# "#
)); ));
@ -284,11 +284,11 @@ fn converts_structured_table_to_tsv_text_skipping_headers_after_conversion() {
let actual = nu!( let actual = nu!(
cwd: dirs.test(), h::pipeline( cwd: dirs.test(), h::pipeline(
r#" r#"
open tsv_text_sample.txt open tsv_text_sample.txt
| lines | lines
| split-column "\t" a b c d origin | split-column "\t" a b c d origin
| last 1 | last 1
| to-tsv --headerless | to-tsv --headerless
| echo "$it" | echo "$it"
"# "#
)); ));
@ -313,11 +313,11 @@ fn converts_from_tsv_text_to_structured_table() {
let actual = nu!( let actual = nu!(
cwd: dirs.test(), h::pipeline( cwd: dirs.test(), h::pipeline(
r#" r#"
open los_tres_amigos.txt open los_tres_amigos.txt
| from-tsv | from-tsv
| get rusty_luck | get rusty_luck
| str --to-int | str --to-int
| sum | sum
| echo $it | echo $it
"# "#
)); ));
@ -412,10 +412,10 @@ fn can_convert_table_to_yaml_text_and_from_yaml_text_back_into_table() {
let actual = nu!( let actual = nu!(
cwd: "tests/fixtures/formats", h::pipeline( cwd: "tests/fixtures/formats", h::pipeline(
r#" r#"
open appveyor.yml open appveyor.yml
| to-yaml | to-yaml
| from-yaml | from-yaml
| get environment.global.PROJECT_NAME | get environment.global.PROJECT_NAME
| echo $it | echo $it
"# "#
)); ));
@ -428,16 +428,16 @@ fn can_sort_by_column() {
let actual = nu!( let actual = nu!(
cwd: "tests/fixtures/formats", h::pipeline( cwd: "tests/fixtures/formats", h::pipeline(
r#" r#"
open cargo_sample.toml --raw open cargo_sample.toml --raw
| lines | lines
| skip 1 | skip 1
| first 4 | first 4
| split-column "=" | split-column "="
| sort-by Column1 | sort-by Column1
| skip 1 | skip 1
| first 1 | first 1
| get Column1 | get Column1
| trim | trim
| echo $it | echo $it
"# "#
)); ));
@ -450,13 +450,13 @@ fn can_split_by_column() {
let actual = nu!( let actual = nu!(
cwd: "tests/fixtures/formats", h::pipeline( cwd: "tests/fixtures/formats", h::pipeline(
r#" r#"
open cargo_sample.toml --raw open cargo_sample.toml --raw
| lines | lines
| skip 1 | skip 1
| first 1 | first 1
| split-column "=" | split-column "="
| get Column1 | get Column1
| trim | trim
| echo $it | echo $it
"# "#
)); ));
@ -469,9 +469,9 @@ fn can_sum() {
let actual = nu!( let actual = nu!(
cwd: "tests/fixtures/formats", h::pipeline( cwd: "tests/fixtures/formats", h::pipeline(
r#" r#"
open sgml_description.json open sgml_description.json
| get glossary.GlossDiv.GlossList.GlossEntry.Sections | get glossary.GlossDiv.GlossList.GlossEntry.Sections
| sum | sum
| echo $it | echo $it
"# "#
)); ));
@ -525,10 +525,10 @@ fn embed() {
let actual = nu!( let actual = nu!(
cwd: dirs.test(), h::pipeline( cwd: dirs.test(), h::pipeline(
r#" r#"
open los_tres_caballeros.txt open los_tres_caballeros.txt
| from-csv | from-csv
| embed caballeros | embed caballeros
| get caballeros | get caballeros
| nth 0 | nth 0
| get last_name | get last_name
| echo $it | echo $it
@ -555,8 +555,8 @@ fn get() {
let actual = nu!( let actual = nu!(
cwd: dirs.test(), h::pipeline( cwd: dirs.test(), h::pipeline(
r#" r#"
open los_tres_caballeros.txt open los_tres_caballeros.txt
| from-csv | from-csv
| nth 1 | nth 1
| get last_name | get last_name
| echo $it | echo $it

View File

@ -6,11 +6,11 @@ use helpers as h;
fn pipeline_helper() { fn pipeline_helper() {
let actual = h::pipeline( let actual = h::pipeline(
r#" r#"
open los_tres_amigos.txt open los_tres_amigos.txt
| from-csv | from-csv
| get rusty_luck | get rusty_luck
| str --to-int | str --to-int
| sum | sum
| echo "$it" | echo "$it"
"#); "#);
@ -30,7 +30,7 @@ fn external_num() {
#[test] #[test]
fn external_has_correct_quotes() { fn external_has_correct_quotes() {
let actual = nu!( let actual = nu!(
cwd: ".", cwd: ".",
r#"echo "hello world""# r#"echo "hello world""#
); );
@ -44,9 +44,9 @@ fn add_plugin() {
let actual = nu!( let actual = nu!(
cwd: "tests/fixtures/formats", h::pipeline( cwd: "tests/fixtures/formats", h::pipeline(
r#" r#"
open cargo_sample.toml open cargo_sample.toml
| add dev-dependencies.newdep "1" | add dev-dependencies.newdep "1"
| get dev-dependencies.newdep | get dev-dependencies.newdep
| echo $it | echo $it
"# "#
)); ));
@ -59,9 +59,9 @@ fn edit_plugin() {
let actual = nu!( let actual = nu!(
cwd: "tests/fixtures/formats", h::pipeline( cwd: "tests/fixtures/formats", h::pipeline(
r#" r#"
open cargo_sample.toml open cargo_sample.toml
| edit dev-dependencies.pretty_assertions "7" | edit dev-dependencies.pretty_assertions "7"
| get dev-dependencies.pretty_assertions | get dev-dependencies.pretty_assertions
| echo $it | echo $it
"# "#
)); ));