Declare input and output types of commands (#6796)

* Add failing test that list of ints and floats is List<Number>

* Start defining subtype relation

* Make it possible to declare input and output types for commands

- Enforce them in tests

* Declare input and output types of commands

* Add formatted signatures to `help commands` table

* Revert SyntaxShape::Table -> Type::Table change

* Revert unnecessary derive(Hash) on SyntaxShape

Co-authored-by: JT <547158+jntrnr@users.noreply.github.com>
This commit is contained in:
Dan Davison 2022-11-09 16:55:05 -05:00 committed by GitHub
parent f878276de7
commit df94052180
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
238 changed files with 2315 additions and 756 deletions

2
Cargo.lock generated
View File

@ -2743,6 +2743,8 @@ dependencies = [
"num-format", "num-format",
"serde", "serde",
"serde_json", "serde_json",
"strum 0.24.1",
"strum_macros 0.24.3",
"sys-locale", "sys-locale",
"thiserror", "thiserror",
"typetag", "typetag",

View File

@ -2,7 +2,7 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value, Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -15,6 +15,8 @@ impl Command for SubCommand {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("bits and") Signature::build("bits and")
.input_output_types(vec![(Type::Int, Type::Int)])
.vectorizes_over_list(true)
.required( .required(
"target", "target",
SyntaxShape::Int, SyntaxShape::Int,

View File

@ -3,7 +3,7 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value, Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -16,6 +16,8 @@ impl Command for SubCommand {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("bits not") Signature::build("bits not")
.input_output_types(vec![(Type::Int, Type::Int)])
.vectorizes_over_list(true)
.switch( .switch(
"signed", "signed",
"always treat input number as a signed number", "always treat input number as a signed number",

View File

@ -2,7 +2,7 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value, Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -15,6 +15,8 @@ impl Command for SubCommand {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("bits or") Signature::build("bits or")
.input_output_types(vec![(Type::Int, Type::Int)])
.vectorizes_over_list(true)
.required( .required(
"target", "target",
SyntaxShape::Int, SyntaxShape::Int,

View File

@ -3,7 +3,7 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value, Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
}; };
use num_traits::int::PrimInt; use num_traits::int::PrimInt;
use std::fmt::Display; use std::fmt::Display;
@ -18,6 +18,8 @@ impl Command for SubCommand {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("bits rol") Signature::build("bits rol")
.input_output_types(vec![(Type::Int, Type::Int)])
.vectorizes_over_list(true)
.required("bits", SyntaxShape::Int, "number of bits to rotate left") .required("bits", SyntaxShape::Int, "number of bits to rotate left")
.switch( .switch(
"signed", "signed",

View File

@ -3,7 +3,7 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value, Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
}; };
use num_traits::int::PrimInt; use num_traits::int::PrimInt;
use std::fmt::Display; use std::fmt::Display;
@ -18,6 +18,8 @@ impl Command for SubCommand {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("bits ror") Signature::build("bits ror")
.input_output_types(vec![(Type::Int, Type::Int)])
.vectorizes_over_list(true)
.required("bits", SyntaxShape::Int, "number of bits to rotate right") .required("bits", SyntaxShape::Int, "number of bits to rotate right")
.switch( .switch(
"signed", "signed",

View File

@ -3,7 +3,7 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value, Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
}; };
use num_traits::CheckedShl; use num_traits::CheckedShl;
use std::fmt::Display; use std::fmt::Display;
@ -18,6 +18,8 @@ impl Command for SubCommand {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("bits shl") Signature::build("bits shl")
.input_output_types(vec![(Type::Int, Type::Int)])
.vectorizes_over_list(true)
.required("bits", SyntaxShape::Int, "number of bits to shift left") .required("bits", SyntaxShape::Int, "number of bits to shift left")
.switch( .switch(
"signed", "signed",

View File

@ -3,7 +3,7 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value, Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
}; };
use num_traits::CheckedShr; use num_traits::CheckedShr;
use std::fmt::Display; use std::fmt::Display;
@ -18,6 +18,8 @@ impl Command for SubCommand {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("bits shr") Signature::build("bits shr")
.input_output_types(vec![(Type::Int, Type::Int)])
.vectorizes_over_list(true)
.required("bits", SyntaxShape::Int, "number of bits to shift right") .required("bits", SyntaxShape::Int, "number of bits to shift right")
.switch( .switch(
"signed", "signed",

View File

@ -2,7 +2,7 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value, Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -15,6 +15,8 @@ impl Command for SubCommand {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("bits xor") Signature::build("bits xor")
.input_output_types(vec![(Type::Int, Type::Int)])
.vectorizes_over_list(true)
.required( .required(
"target", "target",
SyntaxShape::Int, SyntaxShape::Int,

View File

@ -4,7 +4,7 @@ use nu_protocol::ast::Call;
use nu_protocol::ast::CellPath; use nu_protocol::ast::CellPath;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::Category; use nu_protocol::Category;
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value}; use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value};
struct Arguments { struct Arguments {
added_data: Vec<u8>, added_data: Vec<u8>,
@ -30,6 +30,8 @@ impl Command for BytesAdd {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("bytes add") Signature::build("bytes add")
.input_output_types(vec![(Type::Binary, Type::Binary)])
.vectorizes_over_list(true)
.required("data", SyntaxShape::Binary, "the binary to add") .required("data", SyntaxShape::Binary, "the binary to add")
.named( .named(
"index", "index",

View File

@ -4,7 +4,7 @@ use nu_protocol::ast::Call;
use nu_protocol::ast::CellPath; use nu_protocol::ast::CellPath;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value, Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
}; };
use std::cmp::Ordering; use std::cmp::Ordering;
@ -115,6 +115,8 @@ impl Command for BytesAt {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("bytes at") Signature::build("bytes at")
.input_output_types(vec![(Type::Binary, Type::Binary)])
.vectorizes_over_list(true)
.required("range", SyntaxShape::Any, "the indexes to get bytes") .required("range", SyntaxShape::Any, "the indexes to get bytes")
.rest( .rest(
"rest", "rest",

View File

@ -3,7 +3,7 @@ use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape, Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
Value, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -24,6 +24,7 @@ impl Command for BytesBuild {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("bytes build") Signature::build("bytes build")
.input_output_types(vec![(Type::Nothing, Type::Binary)])
.rest("rest", SyntaxShape::Any, "list of bytes") .rest("rest", SyntaxShape::Any, "list of bytes")
.category(Category::Bytes) .category(Category::Bytes)
} }

View File

@ -3,7 +3,7 @@ use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape, Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
Value, Type, Value,
}; };
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -16,6 +16,7 @@ impl Command for BytesCollect {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("bytes collect") Signature::build("bytes collect")
.input_output_types(vec![(Type::List(Box::new(Type::Binary)), Type::Binary)])
.optional( .optional(
"separator", "separator",
SyntaxShape::Binary, SyntaxShape::Binary,

View File

@ -4,7 +4,7 @@ use nu_protocol::ast::Call;
use nu_protocol::ast::CellPath; use nu_protocol::ast::CellPath;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::Category; use nu_protocol::Category;
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value}; use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value};
struct Arguments { struct Arguments {
pattern: Vec<u8>, pattern: Vec<u8>,
@ -28,6 +28,7 @@ impl Command for BytesEndsWith {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("bytes ends-with") Signature::build("bytes ends-with")
.input_output_types(vec![(Type::Binary, Type::Bool)])
.required("pattern", SyntaxShape::Binary, "the pattern to match") .required("pattern", SyntaxShape::Binary, "the pattern to match")
.rest( .rest(
"rest", "rest",

View File

@ -3,7 +3,7 @@ use nu_engine::CallExt;
use nu_protocol::ast::{Call, CellPath}; use nu_protocol::ast::{Call, CellPath};
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value, Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
}; };
struct Arguments { struct Arguments {
@ -29,6 +29,10 @@ impl Command for BytesIndexOf {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("bytes index-of") Signature::build("bytes index-of")
.input_output_types(vec![
(Type::Binary, Type::Int),
(Type::Binary, Type::List(Box::new(Type::Int))),
])
.required( .required(
"pattern", "pattern",
SyntaxShape::Binary, SyntaxShape::Binary,

View File

@ -4,7 +4,7 @@ use nu_protocol::ast::Call;
use nu_protocol::ast::CellPath; use nu_protocol::ast::CellPath;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::Category; use nu_protocol::Category;
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value}; use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value};
#[derive(Clone)] #[derive(Clone)]
pub struct BytesLen; pub struct BytesLen;
@ -16,6 +16,8 @@ impl Command for BytesLen {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("bytes length") Signature::build("bytes length")
.input_output_types(vec![(Type::Binary, Type::Int)])
.vectorizes_over_list(true)
.rest( .rest(
"rest", "rest",
SyntaxShape::CellPath, SyntaxShape::CellPath,

View File

@ -3,7 +3,8 @@ use nu_engine::CallExt;
use nu_protocol::{ use nu_protocol::{
ast::{Call, CellPath}, ast::{Call, CellPath},
engine::{Command, EngineState, Stack}, engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value, Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type,
Value,
}; };
struct Arguments { struct Arguments {
@ -29,6 +30,7 @@ impl Command for BytesRemove {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("bytes remove") Signature::build("bytes remove")
.input_output_types(vec![(Type::Binary, Type::Binary)])
.required("pattern", SyntaxShape::Binary, "the pattern to find") .required("pattern", SyntaxShape::Binary, "the pattern to find")
.rest( .rest(
"rest", "rest",

View File

@ -3,7 +3,8 @@ use nu_engine::CallExt;
use nu_protocol::{ use nu_protocol::{
ast::{Call, CellPath}, ast::{Call, CellPath},
engine::{Command, EngineState, Stack}, engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value, Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type,
Value,
}; };
struct Arguments { struct Arguments {
@ -29,6 +30,7 @@ impl Command for BytesReplace {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("bytes replace") Signature::build("bytes replace")
.input_output_types(vec![(Type::Binary, Type::Binary)])
.required("find", SyntaxShape::Binary, "the pattern to find") .required("find", SyntaxShape::Binary, "the pattern to find")
.required("replace", SyntaxShape::Binary, "the replacement pattern") .required("replace", SyntaxShape::Binary, "the replacement pattern")
.rest( .rest(

View File

@ -4,7 +4,7 @@ use nu_protocol::ast::Call;
use nu_protocol::ast::CellPath; use nu_protocol::ast::CellPath;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::Category; use nu_protocol::Category;
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value}; use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value};
#[derive(Clone)] #[derive(Clone)]
@ -17,6 +17,7 @@ impl Command for BytesReverse {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("bytes reverse") Signature::build("bytes reverse")
.input_output_types(vec![(Type::Binary, Type::Binary)])
.rest( .rest(
"rest", "rest",
SyntaxShape::CellPath, SyntaxShape::CellPath,

View File

@ -4,7 +4,7 @@ use nu_protocol::ast::Call;
use nu_protocol::ast::CellPath; use nu_protocol::ast::CellPath;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::Category; use nu_protocol::Category;
use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value}; use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value};
struct Arguments { struct Arguments {
pattern: Vec<u8>, pattern: Vec<u8>,
@ -28,6 +28,7 @@ impl Command for BytesStartsWith {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("bytes starts-with") Signature::build("bytes starts-with")
.input_output_types(vec![(Type::Binary, Type::Bool)])
.required("pattern", SyntaxShape::Binary, "the pattern to match") .required("pattern", SyntaxShape::Binary, "the pattern to match")
.rest( .rest(
"rest", "rest",

View File

@ -13,7 +13,7 @@ use std::hash::{Hash, Hasher};
/// ```text /// ```text
/// assert_eq!(HashableValue::Bool {val: true, span: Span{start: 0, end: 1}}, HashableValue::Bool {val: true, span: Span{start: 90, end: 1000}}) /// assert_eq!(HashableValue::Bool {val: true, span: Span{start: 0, end: 1}}, HashableValue::Bool {val: true, span: Span{start: 90, end: 1000}})
/// ``` /// ```
#[derive(Eq, Debug)] #[derive(Eq, Debug, Ord, PartialOrd)]
pub enum HashableValue { pub enum HashableValue {
Bool { Bool {
val: bool, val: bool,

View File

@ -1,10 +1,11 @@
use super::hashable_value::HashableValue; use super::hashable_value::HashableValue;
use itertools::Itertools;
use nu_engine::CallExt; use nu_engine::CallExt;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape,
Value, Type, Value,
}; };
use std::collections::HashMap; use std::collections::HashMap;
use std::iter; use std::iter;
@ -24,6 +25,7 @@ impl Command for Histogram {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("histogram") Signature::build("histogram")
.input_output_types(vec![(Type::List(Box::new(Type::Any)), Type::Table(vec![])),])
.optional("column-name", SyntaxShape::String, "column name to calc frequency, no need to provide if input is just a list") .optional("column-name", SyntaxShape::String, "column name to calc frequency, no need to provide if input is just a list")
.optional("frequency-column-name", SyntaxShape::String, "histogram's frequency column, default to be frequency column output") .optional("frequency-column-name", SyntaxShape::String, "histogram's frequency column, default to be frequency column output")
.named("percentage-type", SyntaxShape::String, "percentage calculate method, can be 'normalize' or 'relative', in 'normalize', defaults to be 'normalize'", Some('t')) .named("percentage-type", SyntaxShape::String, "percentage calculate method, can be 'normalize' or 'relative', in 'normalize', defaults to be 'normalize'", Some('t'))
@ -36,23 +38,48 @@ impl Command for Histogram {
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
vec![ vec![
Example { Example {
description: "Get a histogram for the types of files", description: "Compute a histogram of file types",
example: "ls | histogram type", example: "ls | histogram type",
result: None, result: None,
}, },
Example { Example {
description: description:
"Get a histogram for the types of files, with frequency column named freq", "Compute a histogram for the types of files, with frequency column named freq",
example: "ls | histogram type freq", example: "ls | histogram type freq",
result: None, result: None,
}, },
Example { Example {
description: "Get a histogram for a list of numbers", description: "Compute a histogram for a list of numbers",
example: "echo [1 2 3 1 1 1 2 2 1 1] | histogram", example: "echo [1 2 1] | histogram",
result: None, result: Some(Value::List {
vals: vec![Value::Record {
cols: vec!["value".to_string(), "count".to_string(), "quantile".to_string(), "percentage".to_string(), "frequency".to_string()],
vals: vec![
Value::test_int(1),
Value::test_int(2),
Value::test_float(0.6666666666666666),
Value::test_string("66.67%"),
Value::test_string("******************************************************************"),
],
span: Span::test_data(),
},
Value::Record {
cols: vec!["value".to_string(), "count".to_string(), "quantile".to_string(), "percentage".to_string(), "frequency".to_string()],
vals: vec![
Value::test_int(2),
Value::test_int(1),
Value::test_float(0.3333333333333333),
Value::test_string("33.33%"),
Value::test_string("*********************************"),
],
span: Span::test_data(),
}],
span: Span::test_data(),
}
),
}, },
Example { Example {
description: "Get a histogram for a list of numbers, and percentage is based on the maximum value", description: "Compute a histogram for a list of numbers, and percentage is based on the maximum value",
example: "echo [1 2 3 1 1 1 2 2 1 1] | histogram --percentage-type relative", example: "echo [1 2 3 1 1 1 2 2 1 1] | histogram --percentage-type relative",
result: None, result: None,
} }
@ -213,7 +240,7 @@ fn histogram_impl(
freq_column.to_string(), freq_column.to_string(),
]; ];
const MAX_FREQ_COUNT: f64 = 100.0; const MAX_FREQ_COUNT: f64 = 100.0;
for (val, count) in counter.into_iter() { for (val, count) in counter.into_iter().sorted() {
let quantile = match calc_method { let quantile = match calc_method {
PercentageCalcMethod::Normalize => count as f64 / total_cnt as f64, PercentageCalcMethod::Normalize => count as f64 / total_cnt as f64,
PercentageCalcMethod::Relative => count as f64 / max_cnt as f64, PercentageCalcMethod::Relative => count as f64 / max_cnt as f64,

View File

@ -3,7 +3,7 @@ use nu_engine::CallExt;
use nu_protocol::{ use nu_protocol::{
ast::{Call, CellPath}, ast::{Call, CellPath},
engine::{Command, EngineState, Stack}, engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Value, Category, Example, PipelineData, ShellError, Signature, Span, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -19,7 +19,9 @@ impl Command for Fmt {
} }
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("fmt").category(Category::Conversions) Signature::build("fmt")
.input_output_types(vec![(Type::Number, Type::Record(vec![]))])
.category(Category::Conversions)
} }
fn search_terms(&self) -> Vec<&str> { fn search_terms(&self) -> Vec<&str> {

View File

@ -4,7 +4,7 @@ use nu_protocol::{
ast::{Call, CellPath}, ast::{Call, CellPath},
engine::{Command, EngineState, Stack}, engine::{Command, EngineState, Stack},
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape, Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
Value, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -17,6 +17,16 @@ impl Command for SubCommand {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("into binary") Signature::build("into binary")
.input_output_types(vec![
(Type::Binary, Type::Binary),
(Type::Int, Type::Binary),
(Type::Number, Type::Binary),
(Type::String, Type::Binary),
(Type::Bool, Type::Binary),
(Type::Filesize, Type::Binary),
(Type::Date, Type::Binary),
])
.allow_variants_without_examples(true) // TODO: supply exhaustive examples
.rest( .rest(
"rest", "rest",
SyntaxShape::CellPath, SyntaxShape::CellPath,

View File

@ -3,7 +3,7 @@ use nu_engine::CallExt;
use nu_protocol::{ use nu_protocol::{
ast::{Call, CellPath}, ast::{Call, CellPath},
engine::{Command, EngineState, Stack}, engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value, Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -16,6 +16,13 @@ impl Command for SubCommand {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("into bool") Signature::build("into bool")
.input_output_types(vec![
(Type::Int, Type::Bool),
(Type::Number, Type::Bool),
(Type::String, Type::Bool),
(Type::Bool, Type::Bool),
(Type::List(Box::new(Type::Any)), Type::Table(vec![])),
])
.rest( .rest(
"rest", "rest",
SyntaxShape::CellPath, SyntaxShape::CellPath,
@ -89,6 +96,11 @@ impl Command for SubCommand {
example: "1 | into bool", example: "1 | into bool",
result: Some(Value::boolean(true, span)), result: Some(Value::boolean(true, span)),
}, },
Example {
description: "convert decimal to boolean",
example: "0.3 | into bool",
result: Some(Value::boolean(true, span)),
},
Example { Example {
description: "convert decimal string to boolean", description: "convert decimal string to boolean",
example: "'0.0' | into bool", example: "'0.0' | into bool",

View File

@ -7,7 +7,7 @@ use nu_protocol::ast::CellPath;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Spanned, Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Spanned,
SyntaxShape, Value, SyntaxShape, Type, Value,
}; };
struct Arguments { struct Arguments {
@ -64,7 +64,11 @@ impl Command for SubCommand {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("into datetime") Signature::build("into datetime")
.named( .input_output_types(vec![
(Type::Int, Type::Date),
(Type::String, Type::Date),
])
.named(
"timezone", "timezone",
SyntaxShape::String, SyntaxShape::String,
"Specify timezone if the input is a Unix timestamp. Valid options: 'UTC' ('u') or 'LOCAL' ('l')", "Specify timezone if the input is a Unix timestamp. Valid options: 'UTC' ('u') or 'LOCAL' ('l')",

View File

@ -3,7 +3,7 @@ use nu_engine::CallExt;
use nu_protocol::{ use nu_protocol::{
ast::{Call, CellPath}, ast::{Call, CellPath},
engine::{Command, EngineState, Stack}, engine::{Command, EngineState, Stack},
Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -15,11 +15,16 @@ impl Command for SubCommand {
} }
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("into decimal").rest( Signature::build("into decimal")
"rest", .input_output_types(vec![
SyntaxShape::CellPath, (Type::String, Type::Number),
"optionally convert text into decimal by column paths", (Type::Bool, Type::Number),
) ])
.rest(
"rest",
SyntaxShape::CellPath,
"optionally convert text into decimal by column paths",
)
} }
fn usage(&self) -> &str { fn usage(&self) -> &str {

View File

@ -3,7 +3,7 @@ use nu_parser::parse_duration_bytes;
use nu_protocol::{ use nu_protocol::{
ast::{Call, CellPath, Expr}, ast::{Call, CellPath, Expr},
engine::{Command, EngineState, Stack}, engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Unit, Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Unit,
Value, Value,
}; };
@ -17,6 +17,13 @@ impl Command for SubCommand {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("into duration") Signature::build("into duration")
.input_output_types(vec![
(Type::String, Type::Duration),
(Type::Duration, Type::Duration),
// TODO: --convert option should be implemented as `format duration`
(Type::String, Type::String),
(Type::Duration, Type::String),
])
.named( .named(
"convert", "convert",
SyntaxShape::String, SyntaxShape::String,
@ -121,11 +128,19 @@ impl Command for SubCommand {
span, span,
}), }),
}, },
Example {
description: "Convert duration to duration",
example: "420sec | into duration",
result: Some(Value::Duration {
val: 7 * 60 * 1000 * 1000 * 1000,
span,
}),
},
Example { Example {
description: "Convert duration to the requested duration as a string", description: "Convert duration to the requested duration as a string",
example: "420sec | into duration --convert min", example: "420sec | into duration --convert ms",
result: Some(Value::String { result: Some(Value::String {
val: "7 min".to_string(), val: "420000 ms".to_string(),
span, span,
}), }),
}, },

View File

@ -3,7 +3,7 @@ use nu_engine::CallExt;
use nu_protocol::{ use nu_protocol::{
ast::{Call, CellPath}, ast::{Call, CellPath},
engine::{Command, EngineState, Stack}, engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value, Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -16,6 +16,12 @@ impl Command for SubCommand {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("into filesize") Signature::build("into filesize")
.input_output_types(vec![
(Type::Int, Type::Filesize),
(Type::Number, Type::Filesize),
(Type::String, Type::Filesize),
(Type::Filesize, Type::Filesize),
])
.rest( .rest(
"rest", "rest",
SyntaxShape::CellPath, SyntaxShape::CellPath,

View File

@ -3,7 +3,7 @@ use nu_engine::CallExt;
use nu_protocol::{ use nu_protocol::{
ast::{Call, CellPath}, ast::{Call, CellPath},
engine::{Command, EngineState, Stack}, engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value, Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
}; };
struct Arguments { struct Arguments {
@ -28,6 +28,16 @@ impl Command for SubCommand {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("into int") Signature::build("into int")
.input_output_types(vec![
(Type::String, Type::Int),
(Type::Number, Type::Int),
(Type::Bool, Type::Int),
// Unix timestamp in seconds
(Type::Date, Type::Int),
// TODO: Users should do this by dividing a Filesize by a Filesize explicitly
(Type::Filesize, Type::Int),
])
.vectorizes_over_list(true)
.named("radix", SyntaxShape::Number, "radix of integer", Some('r')) .named("radix", SyntaxShape::Number, "radix of integer", Some('r'))
.switch("little-endian", "use little-endian byte decoding", None) .switch("little-endian", "use little-endian byte decoding", None)
.rest( .rest(

View File

@ -4,7 +4,7 @@ use nu_protocol::{
ast::{Call, CellPath}, ast::{Call, CellPath},
engine::{Command, EngineState, Stack}, engine::{Command, EngineState, Stack},
into_code, Category, Config, Example, IntoPipelineData, PipelineData, ShellError, Signature, into_code, Category, Config, Example, IntoPipelineData, PipelineData, ShellError, Signature,
Span, SyntaxShape, Value, Span, SyntaxShape, Type, Value,
}; };
use nu_utils::get_system_locale; use nu_utils::get_system_locale;
use num_format::ToFormattedString; use num_format::ToFormattedString;
@ -32,6 +32,16 @@ impl Command for SubCommand {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("into string") Signature::build("into string")
.input_output_types(vec![
(Type::Binary, Type::String),
(Type::Int, Type::String),
(Type::Number, Type::String),
(Type::String, Type::String),
(Type::Bool, Type::String),
(Type::Filesize, Type::String),
(Type::Date, Type::String),
])
.allow_variants_without_examples(true) // https://github.com/nushell/nushell/issues/7032
// FIXME - need to support column paths // FIXME - need to support column paths
.rest( .rest(
"rest", "rest",
@ -135,11 +145,12 @@ impl Command for SubCommand {
span: Span::test_data(), span: Span::test_data(),
}), }),
}, },
Example { // TODO: This should work but does not; see https://github.com/nushell/nushell/issues/7032
description: "convert date to string", // Example {
example: "date now | into string", // description: "convert date to string",
result: None, // example: "'2020-10-10 10:00:00 +02:00' | into datetime | into string",
}, // result: Some(Value::test_string("Sat Oct 10 10:00:00 2020")),
// },
Example { Example {
description: "convert filepath to string", description: "convert filepath to string",
example: "ls Cargo.toml | get name | into string", example: "ls Cargo.toml | get name | into string",
@ -147,8 +158,8 @@ impl Command for SubCommand {
}, },
Example { Example {
description: "convert filesize to string", description: "convert filesize to string",
example: "ls Cargo.toml | get size | into string", example: "1KiB | into string",
result: None, result: Some(Value::test_string("1,024 B")),
}, },
] ]
} }

View File

@ -1,6 +1,6 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, Signature, SyntaxShape}; use nu_protocol::{Category, Example, PipelineData, Signature, Span, SyntaxShape, Type, Value};
#[derive(Clone)] #[derive(Clone)]
pub struct Alias; pub struct Alias;
@ -16,6 +16,7 @@ impl Command for Alias {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("alias") Signature::build("alias")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.required("name", SyntaxShape::String, "name of the alias") .required("name", SyntaxShape::String, "name of the alias")
.required( .required(
"initial_value", "initial_value",
@ -53,12 +54,12 @@ impl Command for Alias {
Example { Example {
description: "Alias ll to ls -l", description: "Alias ll to ls -l",
example: "alias ll = ls -l", example: "alias ll = ls -l",
result: None, result: Some(Value::nothing(Span::test_data())),
}, },
Example { Example {
description: "Make an alias that makes a list of all custom commands", description: "Make an alias that makes a list of all custom commands",
example: "alias customs = ($nu.scope.commands | where is_custom | get command)", example: "alias customs = ($nu.scope.commands | where is_custom | get command)",
result: None, result: Some(Value::nothing(Span::test_data())),
}, },
] ]
} }

View File

@ -3,7 +3,8 @@ use nu_parser::parse;
use nu_protocol::{ use nu_protocol::{
ast::Call, ast::Call,
engine::{Command, EngineState, Stack, StateWorkingSet}, engine::{Command, EngineState, Stack, StateWorkingSet},
Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type,
Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -20,6 +21,7 @@ impl Command for Ast {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("ast") Signature::build("ast")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.required( .required(
"pipeline", "pipeline",
SyntaxShape::String, SyntaxShape::String,
@ -50,17 +52,17 @@ impl Command for Ast {
Example { Example {
description: "Print the ast of a string", description: "Print the ast of a string",
example: "ast 'hello'", example: "ast 'hello'",
result: None, result: Some(Value::nothing(Span::test_data())),
}, },
Example { Example {
description: "Print the ast of a pipeline", description: "Print the ast of a pipeline",
example: "ast 'ls | where name =~ README'", example: "ast 'ls | where name =~ README'",
result: None, result: Some(Value::nothing(Span::test_data())),
}, },
Example { Example {
description: "Print the ast of a pipeline with an error", description: "Print the ast of a pipeline with an error",
example: "ast 'for x in 1..10 { echo $x '", example: "ast 'for x in 1..10 { echo $x '",
result: None, result: Some(Value::nothing(Span::test_data())),
}, },
] ]
} }

View File

@ -4,7 +4,7 @@ use nu_protocol::engine::ReplOperation;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::Category; use nu_protocol::Category;
use nu_protocol::IntoPipelineData; use nu_protocol::IntoPipelineData;
use nu_protocol::{PipelineData, ShellError, Signature, SyntaxShape, Value}; use nu_protocol::{PipelineData, ShellError, Signature, SyntaxShape, Type, Value};
#[derive(Clone)] #[derive(Clone)]
pub struct Commandline; pub struct Commandline;
@ -16,6 +16,7 @@ impl Command for Commandline {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("commandline") Signature::build("commandline")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.switch( .switch(
"append", "append",
"appends the string to the end of the buffer", "appends the string to the end of the buffer",

View File

@ -1,6 +1,6 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, Span, Value}; use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, Span, Type, Value};
#[derive(Clone)] #[derive(Clone)]
pub struct Debug; pub struct Debug;
@ -15,11 +15,17 @@ impl Command for Debug {
} }
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("debug").category(Category::Core).switch( Signature::build("debug")
"raw", .input_output_types(vec![
"Prints the raw value representation", (
Some('r'), Type::List(Box::new(Type::Any)),
) Type::List(Box::new(Type::String)),
),
(Type::Table(vec![]), Type::List(Box::new(Type::String))),
(Type::Any, Type::String),
])
.category(Category::Core)
.switch("raw", "Prints the raw value representation", Some('r'))
} }
fn run( fn run(
@ -54,12 +60,20 @@ impl Command for Debug {
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
vec![ vec![
Example { Example {
description: "Print the value of a string", description: "Debug print a string",
example: "'hello' | debug", example: "'hello' | debug",
result: Some(Value::test_string("hello")), result: Some(Value::test_string("hello")),
}, },
Example { Example {
description: "Print the value of a table", description: "Debug print a list",
example: "['hello'] | debug",
result: Some(Value::List {
vals: vec![Value::test_string("hello")],
span: Span::test_data(),
}),
},
Example {
description: "Debug print a table",
example: "echo [[version patch]; [0.1.0 false] [0.1.1 true] [0.2.0 false]] | debug", example: "echo [[version patch]; [0.1.0 false] [0.1.1 true] [0.2.0 false]] | debug",
result: Some(Value::List { result: Some(Value::List {
vals: vec![ vals: vec![

View File

@ -1,6 +1,6 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, Signature, SyntaxShape, Value}; use nu_protocol::{Category, Example, PipelineData, Signature, SyntaxShape, Type, Value};
#[derive(Clone)] #[derive(Clone)]
pub struct Def; pub struct Def;
@ -16,6 +16,7 @@ impl Command for Def {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("def") Signature::build("def")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.required("def_name", SyntaxShape::String, "definition name") .required("def_name", SyntaxShape::String, "definition name")
.required("params", SyntaxShape::Signature, "parameters") .required("params", SyntaxShape::Signature, "parameters")
.required( .required(

View File

@ -1,6 +1,6 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, Signature, Span, SyntaxShape, Value}; use nu_protocol::{Category, Example, PipelineData, Signature, Span, SyntaxShape, Type, Value};
#[derive(Clone)] #[derive(Clone)]
pub struct DefEnv; pub struct DefEnv;
@ -16,6 +16,7 @@ impl Command for DefEnv {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("def-env") Signature::build("def-env")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.required("def_name", SyntaxShape::String, "definition name") .required("def_name", SyntaxShape::String, "definition name")
.required("params", SyntaxShape::Signature, "parameters") .required("params", SyntaxShape::Signature, "parameters")
.required( .required(

View File

@ -1,7 +1,7 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Value, Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -17,7 +17,9 @@ impl Command for Describe {
} }
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("describe").category(Category::Core) Signature::build("describe")
.input_output_types(vec![(Type::Any, Type::String)])
.category(Category::Core)
} }
fn run( fn run(

View File

@ -3,7 +3,7 @@ use nu_protocol::ast::Call;
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack}; use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, ListStream, PipelineData, RawStream, ShellError, Signature, SyntaxShape, Category, Example, ListStream, PipelineData, RawStream, ShellError, Signature, SyntaxShape,
Value, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -20,6 +20,7 @@ impl Command for Do {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("do") Signature::build("do")
.input_output_types(vec![(Type::Any, Type::Any)])
.required("block", SyntaxShape::Any, "the block to run") .required("block", SyntaxShape::Any, "the block to run")
.switch( .switch(
"ignore-errors", "ignore-errors",
@ -197,8 +198,13 @@ impl Command for Do {
}, },
Example { Example {
description: "Run the block, with a positional parameter", description: "Run the block, with a positional parameter",
example: r#"do {|x| 100 + $x } 50"#, example: r#"do {|x| 100 + $x } 77"#,
result: Some(Value::test_int(150)), result: Some(Value::test_int(177)),
},
Example {
description: "Run the block, with input",
example: r#"77 | do {|x| 100 + $in }"#,
result: None, // TODO: returns 177
}, },
] ]
} }

View File

@ -2,7 +2,8 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, ListStream, PipelineData, ShellError, Signature, Span, SyntaxShape, Value, Category, Example, ListStream, PipelineData, ShellError, Signature, Span, SyntaxShape, Type,
Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -19,6 +20,7 @@ impl Command for Echo {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("echo") Signature::build("echo")
.input_output_types(vec![(Type::Nothing, Type::Any)])
.rest("rest", SyntaxShape::Any, "the values to echo") .rest("rest", SyntaxShape::Any, "the values to echo")
.category(Category::Core) .category(Category::Core)
} }

View File

@ -2,7 +2,7 @@ use nu_engine::get_full_help;
use nu_protocol::{ use nu_protocol::{
ast::Call, ast::Call,
engine::{Command, EngineState, Stack}, engine::{Command, EngineState, Stack},
Category, Example, IntoPipelineData, PipelineData, Signature, Span, Value, Category, Example, IntoPipelineData, PipelineData, Signature, Span, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -14,7 +14,9 @@ impl Command for ExportCommand {
} }
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("export").category(Category::Core) Signature::build("export")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.category(Category::Core)
} }
fn usage(&self) -> &str { fn usage(&self) -> &str {

View File

@ -1,6 +1,6 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, Signature, SyntaxShape}; use nu_protocol::{Category, Example, PipelineData, Signature, SyntaxShape, Type};
#[derive(Clone)] #[derive(Clone)]
pub struct ExportAlias; pub struct ExportAlias;
@ -16,6 +16,7 @@ impl Command for ExportAlias {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("export alias") Signature::build("export alias")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.required("name", SyntaxShape::String, "name of the alias") .required("name", SyntaxShape::String, "name of the alias")
.required( .required(
"initial_value", "initial_value",

View File

@ -1,6 +1,6 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, Signature, Span, SyntaxShape, Value}; use nu_protocol::{Category, Example, PipelineData, Signature, Span, SyntaxShape, Type, Value};
#[derive(Clone)] #[derive(Clone)]
pub struct ExportDef; pub struct ExportDef;
@ -16,6 +16,7 @@ impl Command for ExportDef {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("export def") Signature::build("export def")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.required("name", SyntaxShape::String, "definition name") .required("name", SyntaxShape::String, "definition name")
.required("params", SyntaxShape::Signature, "parameters") .required("params", SyntaxShape::Signature, "parameters")
.required( .required(

View File

@ -1,6 +1,6 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, Signature, Span, SyntaxShape, Value}; use nu_protocol::{Category, Example, PipelineData, Signature, Span, SyntaxShape, Type, Value};
#[derive(Clone)] #[derive(Clone)]
pub struct ExportDefEnv; pub struct ExportDefEnv;
@ -16,6 +16,7 @@ impl Command for ExportDefEnv {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("export def-env") Signature::build("export def-env")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.required("name", SyntaxShape::String, "definition name") .required("name", SyntaxShape::String, "definition name")
.required("params", SyntaxShape::Signature, "parameters") .required("params", SyntaxShape::Signature, "parameters")
.required( .required(

View File

@ -1,6 +1,6 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, Signature, SyntaxShape}; use nu_protocol::{Category, Example, PipelineData, Signature, SyntaxShape, Type};
#[derive(Clone)] #[derive(Clone)]
pub struct ExportExtern; pub struct ExportExtern;
@ -16,6 +16,7 @@ impl Command for ExportExtern {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("export extern") Signature::build("export extern")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.required("def_name", SyntaxShape::String, "definition name") .required("def_name", SyntaxShape::String, "definition name")
.required("params", SyntaxShape::Signature, "parameters") .required("params", SyntaxShape::Signature, "parameters")
.category(Category::Core) .category(Category::Core)

View File

@ -1,6 +1,6 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, Signature, Span, SyntaxShape, Value}; use nu_protocol::{Category, Example, PipelineData, Signature, Span, SyntaxShape, Type, Value};
#[derive(Clone)] #[derive(Clone)]
pub struct ExportUse; pub struct ExportUse;
@ -16,6 +16,7 @@ impl Command for ExportUse {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("export use") Signature::build("export use")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.required("pattern", SyntaxShape::ImportPattern, "import pattern") .required("pattern", SyntaxShape::ImportPattern, "import pattern")
.category(Category::Core) .category(Category::Core)
} }

View File

@ -1,6 +1,6 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, Signature, SyntaxShape}; use nu_protocol::{Category, Example, PipelineData, Signature, SyntaxShape, Type};
#[derive(Clone)] #[derive(Clone)]
pub struct Extern; pub struct Extern;
@ -16,6 +16,7 @@ impl Command for Extern {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("extern") Signature::build("extern")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.required("def_name", SyntaxShape::String, "definition name") .required("def_name", SyntaxShape::String, "definition name")
.required("params", SyntaxShape::Signature, "parameters") .required("params", SyntaxShape::Signature, "parameters")
.category(Category::Core) .category(Category::Core)

View File

@ -3,7 +3,7 @@ use nu_protocol::ast::Call;
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack}; use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, ListStream, PipelineData, Signature, Span, Category, Example, IntoInterruptiblePipelineData, ListStream, PipelineData, Signature, Span,
SyntaxShape, Value, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -20,6 +20,7 @@ impl Command for For {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("for") Signature::build("for")
.input_output_types(vec![(Type::Nothing, Type::List(Box::new(Type::Any)))])
.required( .required(
"var_name", "var_name",
SyntaxShape::VarWithOptType, SyntaxShape::VarWithOptType,

View File

@ -1,4 +1,5 @@
use fancy_regex::Regex; use fancy_regex::Regex;
use itertools::Itertools;
use nu_ansi_term::{ use nu_ansi_term::{
Color::{Default, Red, White}, Color::{Default, Red, White},
Style, Style,
@ -9,7 +10,7 @@ use nu_protocol::{
ast::Call, ast::Call,
engine::{Command, EngineState, Stack}, engine::{Command, EngineState, Stack},
span, Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, span, Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData,
ShellError, Signature, Span, Spanned, SyntaxShape, Value, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
}; };
use std::borrow::Borrow; use std::borrow::Borrow;
#[derive(Clone)] #[derive(Clone)]
@ -22,6 +23,7 @@ impl Command for Help {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("help") Signature::build("help")
.input_output_types(vec![(Type::Nothing, Type::String)])
.rest( .rest(
"rest", "rest",
SyntaxShape::String, SyntaxShape::String,
@ -162,6 +164,16 @@ fn help(
span: head, span: head,
}); });
cols.push("signatures".into());
vals.push(Value::String {
val: sig
.input_output_types
.iter()
.map(|(i, o)| format!("{:?} => {:?}", i.to_shape(), o.to_shape()))
.join("\n"),
span: head,
});
cols.push("search_terms".into()); cols.push("search_terms".into());
vals.push(if search_terms.is_empty() { vals.push(if search_terms.is_empty() {
Value::nothing(head) Value::nothing(head)
@ -259,6 +271,16 @@ fn help(
span: head, span: head,
}); });
cols.push("signatures".into());
vals.push(Value::String {
val: sig
.input_output_types
.iter()
.map(|(i, o)| format!("{:?} => {:?}", i.to_shape(), o.to_shape()))
.join("\n"),
span: head,
});
cols.push("search_terms".into()); cols.push("search_terms".into());
vals.push(if search_terms.is_empty() { vals.push(if search_terms.is_empty() {
Value::nothing(head) Value::nothing(head)

View File

@ -1,7 +1,7 @@
use nu_protocol::ast::{Call, Expr, Expression}; use nu_protocol::ast::{Call, Expr, Expression};
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value, Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -14,6 +14,7 @@ impl Command for Hide {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("hide") Signature::build("hide")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.required("pattern", SyntaxShape::ImportPattern, "import pattern") .required("pattern", SyntaxShape::ImportPattern, "import pattern")
.category(Category::Core) .category(Category::Core)
} }

View File

@ -3,7 +3,7 @@ use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
did_you_mean, Category, Example, PipelineData, ShellError, Signature, Span, Spanned, did_you_mean, Category, Example, PipelineData, ShellError, Signature, Span, Spanned,
SyntaxShape, Value, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -16,6 +16,7 @@ impl Command for HideEnv {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("hide-env") Signature::build("hide-env")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.rest( .rest(
"name", "name",
SyntaxShape::String, SyntaxShape::String,

View File

@ -2,7 +2,7 @@ use nu_engine::{eval_block, eval_expression, eval_expression_with_input, CallExt
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack}; use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, FromValue, PipelineData, ShellError, Signature, SyntaxShape, Value, Category, Example, FromValue, PipelineData, ShellError, Signature, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -19,6 +19,7 @@ impl Command for If {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("if") Signature::build("if")
.input_output_types(vec![(Type::Any, Type::Any)])
.required("cond", SyntaxShape::Expression, "condition to check") .required("cond", SyntaxShape::Expression, "condition to check")
.required( .required(
"then_block", "then_block",

View File

@ -1,6 +1,6 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, Signature}; use nu_protocol::{Category, Example, PipelineData, Signature, Span, Type, Value};
#[derive(Clone)] #[derive(Clone)]
pub struct Ignore; pub struct Ignore;
@ -15,7 +15,9 @@ impl Command for Ignore {
} }
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("ignore").category(Category::Core) Signature::build("ignore")
.input_output_types(vec![(Type::Any, Type::Nothing)])
.category(Category::Core)
} }
fn search_terms(&self) -> Vec<&str> { fn search_terms(&self) -> Vec<&str> {
@ -37,7 +39,7 @@ impl Command for Ignore {
vec![Example { vec![Example {
description: "Ignore the output of an echo command", description: "Ignore the output of an echo command",
example: "echo done | ignore", example: "echo done | ignore",
result: None, result: Some(Value::nothing(Span::test_data())),
}] }]
} }
} }

View File

@ -1,7 +1,7 @@
use nu_engine::eval_expression_with_input; use nu_engine::eval_expression_with_input;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, Signature, SyntaxShape}; use nu_protocol::{Category, Example, PipelineData, Signature, SyntaxShape, Type};
#[derive(Clone)] #[derive(Clone)]
pub struct Let; pub struct Let;
@ -17,6 +17,8 @@ impl Command for Let {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("let") Signature::build("let")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.allow_variants_without_examples(true)
.required("var_name", SyntaxShape::VarWithOptType, "variable name") .required("var_name", SyntaxShape::VarWithOptType, "variable name")
.required( .required(
"initial_value", "initial_value",

View File

@ -3,7 +3,7 @@ use nu_protocol::ast::{Call, Expr, Expression};
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, DataSource, Example, IntoPipelineData, PipelineData, PipelineMetadata, Signature, Category, DataSource, Example, IntoPipelineData, PipelineData, PipelineMetadata, Signature,
Span, SyntaxShape, Value, Span, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -20,6 +20,8 @@ impl Command for Metadata {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("metadata") Signature::build("metadata")
.input_output_types(vec![(Type::Nothing, Type::Record(vec![]))])
.allow_variants_without_examples(true)
.optional( .optional(
"expression", "expression",
SyntaxShape::Any, SyntaxShape::Any,

View File

@ -1,6 +1,6 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, Signature, Span, SyntaxShape, Value}; use nu_protocol::{Category, Example, PipelineData, Signature, Span, SyntaxShape, Type, Value};
#[derive(Clone)] #[derive(Clone)]
pub struct Module; pub struct Module;
@ -16,6 +16,7 @@ impl Command for Module {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("module") Signature::build("module")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.required("module_name", SyntaxShape::String, "module name") .required("module_name", SyntaxShape::String, "module name")
.required( .required(
"block", "block",

View File

@ -1,6 +1,6 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, Signature, SyntaxShape}; use nu_protocol::{Category, Example, PipelineData, Signature, SyntaxShape, Type};
#[derive(Clone)] #[derive(Clone)]
pub struct Register; pub struct Register;
@ -16,6 +16,7 @@ impl Command for Register {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("register") Signature::build("register")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.required( .required(
"plugin", "plugin",
SyntaxShape::Filepath, SyntaxShape::Filepath,

View File

@ -2,7 +2,7 @@ use nu_engine::{eval_block, find_in_dirs_env, redirect_env};
use nu_protocol::ast::{Call, Expr, Expression}; use nu_protocol::ast::{Call, Expr, Expression};
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value, Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -19,6 +19,7 @@ impl Command for Use {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("use") Signature::build("use")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.required("pattern", SyntaxShape::ImportPattern, "import pattern") .required("pattern", SyntaxShape::ImportPattern, "import pattern")
.category(Category::Core) .category(Category::Core)
} }

View File

@ -1,6 +1,6 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Example, IntoPipelineData, PipelineData, ShellError, Signature, Value}; use nu_protocol::{Example, IntoPipelineData, PipelineData, ShellError, Signature, Type, Value};
pub mod shadow { pub mod shadow {
include!(concat!(env!("OUT_DIR"), "/shadow.rs")); include!(concat!(env!("OUT_DIR"), "/shadow.rs"));
@ -16,6 +16,8 @@ impl Command for Version {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("version") Signature::build("version")
.input_output_types(vec![(Type::Nothing, Type::Record(vec![]))])
.allow_variants_without_examples(true)
} }
fn usage(&self) -> &str { fn usage(&self) -> &str {
@ -215,3 +217,13 @@ fn features_enabled() -> Vec<String> {
names names
} }
#[cfg(test)]
mod test {
#[test]
fn test_examples() {
use super::Version;
use crate::test_examples;
test_examples(Version {})
}
}

View File

@ -4,7 +4,8 @@ use nu_engine::CallExt;
use nu_protocol::{ use nu_protocol::{
ast::Call, ast::Call,
engine::{Command, EngineState, Stack}, engine::{Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value, Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type,
Value,
}; };
use nu_utils::locale::get_system_locale_string; use nu_utils::locale::get_system_locale_string;
use std::fmt::{Display, Write}; use std::fmt::{Display, Write};
@ -21,6 +22,11 @@ impl Command for SubCommand {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("date format") Signature::build("date format")
.input_output_types(vec![
(Type::Date, Type::String),
(Type::String, Type::String),
])
.allow_variants_without_examples(true) // https://github.com/nushell/nushell/issues/7032
.switch("list", "lists strftime cheatsheet", Some('l')) .switch("list", "lists strftime cheatsheet", Some('l'))
.optional( .optional(
"format string", "format string",
@ -66,8 +72,18 @@ impl Command for SubCommand {
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
vec![ vec![
// TODO: This should work but does not; see https://github.com/nushell/nushell/issues/7032
// Example {
// description: "Format a given date-time using the default format (RFC 2822).",
// example: r#"'2021-10-22 20:00:12 +01:00' | into datetime | date format"#,
// result: Some(Value::String {
// val: "Fri, 22 Oct 2021 20:00:12 +0100".to_string(),
// span: Span::test_data(),
// }),
// },
Example { Example {
description: "Format a given date using the default format (RFC 2822).", description:
"Format a given date-time as a string using the default format (RFC 2822).",
example: r#""2021-10-22 20:00:12 +01:00" | date format"#, example: r#""2021-10-22 20:00:12 +01:00" | date format"#,
result: Some(Value::String { result: Some(Value::String {
val: "Fri, 22 Oct 2021 20:00:12 +0100".to_string(), val: "Fri, 22 Oct 2021 20:00:12 +0100".to_string(),
@ -75,13 +91,13 @@ impl Command for SubCommand {
}), }),
}, },
Example { Example {
description: "Format a given date using a given format string.", description: "Format the current date-time using a given format string.",
example: "date format '%Y-%m-%d'", example: r#"date now | date format "%Y-%m-%d %H:%M:%S""#,
result: None, result: None,
}, },
Example { Example {
description: "Format a given date using a given format string.", description: "Format the current date using a given format string.",
example: r#"date format "%Y-%m-%d %H:%M:%S""#, example: r#"date now | date format "%Y-%m-%d %H:%M:%S""#,
result: None, result: None,
}, },
Example { Example {

View File

@ -3,7 +3,7 @@ use chrono::{DateTime, FixedOffset, Local};
use chrono_humanize::HumanTime; use chrono_humanize::HumanTime;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, Span, Value}; use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, Span, Type, Value};
#[derive(Clone)] #[derive(Clone)]
pub struct SubCommand; pub struct SubCommand;
@ -13,7 +13,13 @@ impl Command for SubCommand {
} }
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("date humanize").category(Category::Date) Signature::build("date humanize")
.input_output_types(vec![
(Type::Date, Type::String),
(Type::String, Type::String),
])
.allow_variants_without_examples(true)
.category(Category::Date)
} }
fn usage(&self) -> &str { fn usage(&self) -> &str {
@ -45,21 +51,11 @@ impl Command for SubCommand {
} }
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
vec![ vec![Example {
Example { description: "Print a 'humanized' format for the date, relative to now.",
description: "Print a 'humanized' format for the date, relative to now.", example: r#""2021-10-22 20:00:12 +01:00" | date humanize"#,
example: "date humanize", result: None,
result: Some(Value::String { }]
val: "now".to_string(),
span: Span::test_data(),
}),
},
Example {
description: "Print a 'humanized' format for the date, relative to now.",
example: r#""2021-10-22 20:00:12 +01:00" | date humanize"#,
result: None,
},
]
} }
} }

View File

@ -2,7 +2,7 @@ use chrono_tz::TZ_VARIANTS;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, PipelineData, Signature, Span, Value, Category, Example, IntoInterruptiblePipelineData, PipelineData, Signature, Span, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -14,7 +14,9 @@ impl Command for SubCommand {
} }
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("date list-timezone").category(Category::Date) Signature::build("date list-timezone")
.input_output_types(vec![(Type::Nothing, Type::Table(vec![]))])
.category(Category::Date)
} }
fn usage(&self) -> &str { fn usage(&self) -> &str {

View File

@ -1,7 +1,7 @@
use chrono::Local; use chrono::Local;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, IntoPipelineData, PipelineData, Signature, Value}; use nu_protocol::{Category, Example, IntoPipelineData, PipelineData, Signature, Type, Value};
#[derive(Clone)] #[derive(Clone)]
pub struct SubCommand; pub struct SubCommand;
@ -11,7 +11,9 @@ impl Command for SubCommand {
} }
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("date now").category(Category::Date) Signature::build("date now")
.input_output_types(vec![(Type::Nothing, Type::Date)])
.category(Category::Date)
} }
fn usage(&self) -> &str { fn usage(&self) -> &str {

View File

@ -2,6 +2,7 @@ use crate::date::utils::parse_date_from_string;
use chrono::{DateTime, Datelike, FixedOffset, Local, Timelike}; use chrono::{DateTime, Datelike, FixedOffset, Local, Timelike};
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::Type;
use nu_protocol::{ use nu_protocol::{
Category, Example, PipelineData, ShellError::DatetimeParseError, Signature, Span, Value, Category, Example, PipelineData, ShellError::DatetimeParseError, Signature, Span, Value,
}; };
@ -15,11 +16,17 @@ impl Command for SubCommand {
} }
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("date to-record").category(Category::Date) Signature::build("date to-record")
.input_output_types(vec![
(Type::Date, Type::Record(vec![])),
(Type::String, Type::Record(vec![])),
])
.allow_variants_without_examples(true) // https://github.com/nushell/nushell/issues/7032
.category(Category::Date)
} }
fn usage(&self) -> &str { fn usage(&self) -> &str {
"Convert the date into a structured table." "Convert the date into a record."
} }
fn search_terms(&self) -> Vec<&str> { fn search_terms(&self) -> Vec<&str> {
@ -38,46 +45,54 @@ impl Command for SubCommand {
} }
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
let example_result_1 = || {
let span = Span::test_data();
let cols = vec![
"year".into(),
"month".into(),
"day".into(),
"hour".into(),
"minute".into(),
"second".into(),
"timezone".into(),
];
let vals = vec![
Value::Int { val: 2020, span },
Value::Int { val: 4, span },
Value::Int { val: 12, span },
Value::Int { val: 22, span },
Value::Int { val: 10, span },
Value::Int { val: 57, span },
Value::String {
val: "+02:00".to_string(),
span,
},
];
Some(Value::Record { cols, vals, span })
};
vec![ vec![
Example { Example {
description: "Convert the current date into a structured table.", description: "Convert the current date into a record.",
example: "date to-table", example: "date to-record",
result: None, result: None,
}, },
Example { Example {
description: "Convert the current date into a structured table.", description: "Convert the current date into a record.",
example: "date now | date to-record", example: "date now | date to-record",
result: None, result: None,
}, },
Example { Example {
description: "Convert a given date into a structured table.", description: "Convert a date string into a record.",
example: " '2020-04-12 22:10:57 +0200' | date to-record", example: "'2020-04-12 22:10:57 +0200' | date to-record",
result: { result: example_result_1(),
let span = Span::test_data();
let cols = vec![
"year".into(),
"month".into(),
"day".into(),
"hour".into(),
"minute".into(),
"second".into(),
"timezone".into(),
];
let vals = vec![
Value::Int { val: 2020, span },
Value::Int { val: 4, span },
Value::Int { val: 12, span },
Value::Int { val: 22, span },
Value::Int { val: 10, span },
Value::Int { val: 57, span },
Value::String {
val: "+02:00".to_string(),
span,
},
];
Some(Value::Record { cols, vals, span })
},
}, },
// TODO: This should work but does not; see https://github.com/nushell/nushell/issues/7032
// Example {
// description: "Convert a date into a record.",
// example: "'2020-04-12 22:10:57 +0200' | into datetime | date to-record",
// result: example_result_1(),
// },
] ]
} }
} }

View File

@ -2,6 +2,7 @@ use crate::date::utils::parse_date_from_string;
use chrono::{DateTime, Datelike, FixedOffset, Local, Timelike}; use chrono::{DateTime, Datelike, FixedOffset, Local, Timelike};
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::Type;
use nu_protocol::{ use nu_protocol::{
Category, Example, PipelineData, ShellError::DatetimeParseError, Signature, Span, Value, Category, Example, PipelineData, ShellError::DatetimeParseError, Signature, Span, Value,
}; };
@ -15,7 +16,13 @@ impl Command for SubCommand {
} }
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("date to-table").category(Category::Date) Signature::build("date to-table")
.input_output_types(vec![
(Type::Date, Type::Table(vec![])),
(Type::String, Type::Table(vec![])),
])
.allow_variants_without_examples(true) // https://github.com/nushell/nushell/issues/7032
.category(Category::Date)
} }
fn usage(&self) -> &str { fn usage(&self) -> &str {
@ -38,49 +45,57 @@ impl Command for SubCommand {
} }
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
let example_result_1 = || {
let span = Span::test_data();
let cols = vec![
"year".into(),
"month".into(),
"day".into(),
"hour".into(),
"minute".into(),
"second".into(),
"timezone".into(),
];
let vals = vec![
Value::Int { val: 2020, span },
Value::Int { val: 4, span },
Value::Int { val: 12, span },
Value::Int { val: 22, span },
Value::Int { val: 10, span },
Value::Int { val: 57, span },
Value::String {
val: "+02:00".to_string(),
span,
},
];
Some(Value::List {
vals: vec![Value::Record { cols, vals, span }],
span,
})
};
vec![ vec![
Example { Example {
description: "Convert the date into a structured table.", description: "Convert the current date into a table.",
example: "date to-table", example: "date to-table",
result: None, result: None,
}, },
Example { Example {
description: "Convert the date into a structured table.", description: "Convert the date into a table.",
example: "date now | date to-table", example: "date now | date to-table",
result: None, result: None,
}, },
Example { Example {
description: "Convert a given date into a structured table.", description: "Convert a given date into a table.",
example: " '2020-04-12 22:10:57 +0200' | date to-table", example: "'2020-04-12 22:10:57 +0200' | date to-table",
result: { result: example_result_1(),
let span = Span::test_data();
let cols = vec![
"year".into(),
"month".into(),
"day".into(),
"hour".into(),
"minute".into(),
"second".into(),
"timezone".into(),
];
let vals = vec![
Value::Int { val: 2020, span },
Value::Int { val: 4, span },
Value::Int { val: 12, span },
Value::Int { val: 22, span },
Value::Int { val: 10, span },
Value::Int { val: 57, span },
Value::String {
val: "+02:00".to_string(),
span,
},
];
Some(Value::List {
vals: vec![Value::Record { cols, vals, span }],
span,
})
},
}, },
// TODO: This should work but does not; see https://github.com/nushell/nushell/issues/7032
// Example {
// description: "Convert a given date into a table.",
// example: "'2020-04-12 22:10:57 +0200' | into datetime | date to-table",
// result: example_result_1(),
// },
] ]
} }
} }

View File

@ -5,7 +5,7 @@ use nu_engine::CallExt;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value, Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
}; };
use chrono::{FixedOffset, TimeZone}; use chrono::{FixedOffset, TimeZone};
@ -20,6 +20,8 @@ impl Command for SubCommand {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("date to-timezone") Signature::build("date to-timezone")
.input_output_types(vec![(Type::Date, Type::Date), (Type::String, Type::Date)])
.allow_variants_without_examples(true) // https://github.com/nushell/nushell/issues/7032
.required("time zone", SyntaxShape::String, "time zone description") .required("time zone", SyntaxShape::String, "time zone description")
.category(Category::Date) .category(Category::Date)
} }
@ -62,6 +64,16 @@ impl Command for SubCommand {
} }
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
let example_result_1 = || {
let dt = FixedOffset::east(5 * 3600)
.ymd(2020, 10, 10)
.and_hms(13, 00, 00);
Some(Value::Date {
val: dt,
span: Span::test_data(),
})
};
vec![ vec![
Example { Example {
description: "Get the current date in UTC+05:00", description: "Get the current date in UTC+05:00",
@ -81,19 +93,14 @@ impl Command for SubCommand {
Example { Example {
description: "Get the current date in Hawaii", description: "Get the current date in Hawaii",
example: r#""2020-10-10 10:00:00 +02:00" | date to-timezone "+0500""#, example: r#""2020-10-10 10:00:00 +02:00" | date to-timezone "+0500""#,
// result: None result: example_result_1(),
// The following should be the result of the test, but it fails. Cannot figure it out why.
result: {
let dt = FixedOffset::east(5 * 3600)
.ymd(2020, 10, 10)
.and_hms(13, 00, 00);
Some(Value::Date {
val: dt,
span: Span::test_data(),
})
},
}, },
// TODO: This should work but does not; see https://github.com/nushell/nushell/issues/7032
// Example {
// description: "Get the current date in Hawaii, from a datetime object",
// example: r#""2020-10-10 10:00:00 +02:00" | into datetime | date to-timezone "+0500""#,
// result: example_result_1(),
// },
] ]
} }
} }

View File

@ -2,7 +2,7 @@ use nu_engine::{eval_block, redirect_env, CallExt};
use nu_protocol::{ use nu_protocol::{
ast::Call, ast::Call,
engine::{CaptureBlock, Command, EngineState, Stack}, engine::{CaptureBlock, Command, EngineState, Stack},
Category, Example, PipelineData, Signature, Span, SyntaxShape, Value, Category, Example, PipelineData, Signature, Span, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -15,6 +15,7 @@ impl Command for ExportEnv {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("export-env") Signature::build("export-env")
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
.required( .required(
"block", "block",
SyntaxShape::Block(Some(vec![])), SyntaxShape::Block(Some(vec![])),
@ -53,11 +54,20 @@ impl Command for ExportEnv {
} }
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
vec![Example { vec![
description: "Set an environment", Example {
example: r#"export-env { let-env SPAM = 'eggs' }; $env.SPAM"#, description: "Set an environment variable",
result: Some(Value::string("eggs", Span::test_data())), example: r#"export-env { let-env SPAM = 'eggs' }"#,
}] result: Some(Value::Nothing {
span: Span::test_data(),
}),
},
Example {
description: "Set an environment variable and examine its value",
example: r#"export-env { let-env SPAM = 'eggs' }; $env.SPAM"#,
result: Some(Value::string("eggs", Span::test_data())),
},
]
} }
} }

View File

@ -4,7 +4,7 @@ use nu_engine::{eval_block, CallExt};
use nu_protocol::{ use nu_protocol::{
ast::Call, ast::Call,
engine::{CaptureBlock, Command, EngineState, Stack}, engine::{CaptureBlock, Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Value, Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -17,6 +17,7 @@ impl Command for WithEnv {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("with-env") Signature::build("with-env")
.input_output_types(vec![(Type::Any, Type::Any)])
.required( .required(
"variable", "variable",
SyntaxShape::Any, SyntaxShape::Any,

View File

@ -1,75 +1,206 @@
#[cfg(test)] #[cfg(test)]
use nu_engine::eval_block; use nu_protocol::engine::Command;
#[cfg(test)]
use nu_parser::parse;
#[cfg(test)]
use nu_protocol::{
engine::{Command, EngineState, Stack, StateWorkingSet},
PipelineData, Span, Value,
};
#[cfg(test)]
use crate::To;
#[cfg(test)]
use super::{
Ansi, Date, From, If, Into, LetEnv, Math, Path, Random, Split, SplitColumn, SplitRow, Str,
StrJoin, StrLength, StrReplace, Url, Wrap,
};
#[cfg(test)] #[cfg(test)]
pub fn test_examples(cmd: impl Command + 'static) { pub fn test_examples(cmd: impl Command + 'static) {
use crate::BuildString; test_examples::test_examples(cmd);
}
let examples = cmd.examples(); #[cfg(test)]
let mut engine_state = Box::new(EngineState::new()); mod test_examples {
use super::super::{
let delta = { Ansi, BuildString, Date, Echo, From, If, Into, LetEnv, Math, Path, Random, Split,
// Base functions that are needed for testing SplitColumn, SplitRow, Str, StrJoin, StrLength, StrReplace, Url, Wrap,
// Try to keep this working set small to keep tests running as fast as possible
let mut working_set = StateWorkingSet::new(&*engine_state);
working_set.add_decl(Box::new(Str));
working_set.add_decl(Box::new(StrJoin));
working_set.add_decl(Box::new(StrLength));
working_set.add_decl(Box::new(StrReplace));
working_set.add_decl(Box::new(BuildString));
working_set.add_decl(Box::new(From));
working_set.add_decl(Box::new(If));
working_set.add_decl(Box::new(To));
working_set.add_decl(Box::new(Into));
working_set.add_decl(Box::new(Random));
working_set.add_decl(Box::new(Split));
working_set.add_decl(Box::new(SplitColumn));
working_set.add_decl(Box::new(SplitRow));
working_set.add_decl(Box::new(Math));
working_set.add_decl(Box::new(Path));
working_set.add_decl(Box::new(Date));
working_set.add_decl(Box::new(Url));
working_set.add_decl(Box::new(Ansi));
working_set.add_decl(Box::new(Wrap));
working_set.add_decl(Box::new(LetEnv));
use super::Echo;
working_set.add_decl(Box::new(Echo));
// Adding the command that is being tested to the working set
working_set.add_decl(Box::new(cmd));
working_set.render()
}; };
use crate::To;
use itertools::Itertools;
use nu_engine;
use nu_parser;
use nu_protocol::{
ast::Block,
engine::{Command, EngineState, Stack, StateDelta, StateWorkingSet},
Example, PipelineData, Signature, Span, Type, Value,
};
use std::{collections::HashSet, path::PathBuf};
let cwd = std::env::current_dir().expect("Could not get current working directory."); pub fn test_examples(cmd: impl Command + 'static) {
let examples = cmd.examples();
let signature = cmd.signature();
let mut engine_state = make_engine_state(cmd.clone_box());
engine_state let cwd = std::env::current_dir().expect("Could not get current working directory.");
.merge_delta(delta)
.expect("Error merging delta");
for example in examples { let mut witnessed_type_transformations = HashSet::<(Type, Type)>::new();
// Skip tests that don't have results to compare to
if example.result.is_none() { for example in examples {
continue; if example.result.is_none() {
continue;
}
witnessed_type_transformations.extend(
check_example_input_and_output_types_match_command_signature(
&example,
&cwd,
&mut make_engine_state(cmd.clone_box()),
&signature.input_output_types,
signature.operates_on_cell_paths(),
signature.vectorizes_over_list,
),
);
check_example_evaluates_to_expected_output(&example, &cwd, &mut engine_state);
} }
let start = std::time::Instant::now();
check_all_signature_input_output_types_entries_have_examples(
signature,
witnessed_type_transformations,
);
}
fn make_engine_state(cmd: Box<dyn Command>) -> Box<EngineState> {
let mut engine_state = Box::new(EngineState::new());
let delta = {
// Base functions that are needed for testing
// Try to keep this working set small to keep tests running as fast as possible
let mut working_set = StateWorkingSet::new(&*engine_state);
working_set.add_decl(Box::new(Str));
working_set.add_decl(Box::new(StrJoin));
working_set.add_decl(Box::new(StrLength));
working_set.add_decl(Box::new(StrReplace));
working_set.add_decl(Box::new(BuildString));
working_set.add_decl(Box::new(From));
working_set.add_decl(Box::new(If));
working_set.add_decl(Box::new(To));
working_set.add_decl(Box::new(Into));
working_set.add_decl(Box::new(Random));
working_set.add_decl(Box::new(Split));
working_set.add_decl(Box::new(SplitColumn));
working_set.add_decl(Box::new(SplitRow));
working_set.add_decl(Box::new(Math));
working_set.add_decl(Box::new(Path));
working_set.add_decl(Box::new(Date));
working_set.add_decl(Box::new(Url));
working_set.add_decl(Box::new(Ansi));
working_set.add_decl(Box::new(Wrap));
working_set.add_decl(Box::new(LetEnv));
working_set.add_decl(Box::new(Echo));
// Adding the command that is being tested to the working set
working_set.add_decl(cmd);
working_set.render()
};
engine_state
.merge_delta(delta)
.expect("Error merging delta");
engine_state
}
fn check_example_input_and_output_types_match_command_signature<'a>(
example: &Example,
cwd: &PathBuf,
engine_state: &mut Box<EngineState>,
signature_input_output_types: &Vec<(Type, Type)>,
signature_operates_on_cell_paths: bool,
signature_vectorizes_over_list: bool,
) -> HashSet<(Type, Type)> {
let mut witnessed_type_transformations = HashSet::<(Type, Type)>::new();
// Skip tests that don't have results to compare to
if let Some(example_output) = example.result.as_ref() {
if let Some(example_input_type) =
eval_pipeline_without_terminal_expression(example.example, &cwd, engine_state)
{
let example_input_type = example_input_type.get_type();
let example_output_type = example_output.get_type();
let example_matches_signature =
signature_input_output_types
.iter()
.any(|(sig_in_type, sig_out_type)| {
example_input_type.is_subtype(sig_in_type)
&& example_output_type.is_subtype(sig_out_type)
&& {
witnessed_type_transformations
.insert((sig_in_type.clone(), sig_out_type.clone()));
true
}
});
// The example type checks as vectorization over an input list if both:
// 1. The command is declared to vectorize over list input.
// 2. There exists an entry t -> u in the type map such that the
// example_input_type is a subtype of list<t> and the
// example_output_type is a subtype of list<u>.
let example_matches_signature_via_vectorization_over_list =
signature_vectorizes_over_list
&& match &example_input_type {
Type::List(ex_in_type) => {
match signature_input_output_types.iter().find_map(
|(sig_in_type, sig_out_type)| {
if ex_in_type.is_subtype(sig_in_type) {
Some((sig_in_type, sig_out_type))
} else {
None
}
},
) {
Some((sig_in_type, sig_out_type)) => match &example_output_type
{
Type::List(ex_out_type)
if ex_out_type.is_subtype(sig_out_type) =>
{
witnessed_type_transformations.insert((
sig_in_type.clone(),
sig_out_type.clone(),
));
true
}
_ => false,
},
None => false,
}
}
_ => false,
};
// The example type checks as a cell path operation if both:
// 1. The command is declared to operate on cell paths.
// 2. The example_input_type is list or record or table, and the example
// output shape is the same as the input shape.
let example_matches_signature_via_cell_path_operation =
signature_operates_on_cell_paths
&& example_input_type.accepts_cell_paths()
// TODO: This is too permissive; it should make use of the signature.input_output_types at least.
&& example_output_type.to_shape() == example_input_type.to_shape();
if !(example_matches_signature
|| example_matches_signature_via_vectorization_over_list
|| example_matches_signature_via_cell_path_operation)
{
assert!(
false,
"The example `{}` demonstrates a transformation of type {:?} -> {:?}. \
However, this does not match the declared signature: {:?}.{} \
For this command, `vectorizes_over_list` is {} and `operates_on_cell_paths()` is {}.",
example.example,
example_input_type,
example_output_type,
signature_input_output_types,
if signature_input_output_types.is_empty() { " (Did you forget to declare the input and output types for the command?)" } else { "" },
signature_vectorizes_over_list,
signature_operates_on_cell_paths
);
};
};
}
witnessed_type_transformations
}
fn check_example_evaluates_to_expected_output(
example: &Example,
cwd: &PathBuf,
engine_state: &mut Box<EngineState>,
) {
let mut stack = Stack::new(); let mut stack = Stack::new();
// Set up PWD // Set up PWD
@ -85,30 +216,82 @@ pub fn test_examples(cmd: impl Command + 'static) {
.merge_env(&mut stack, &cwd) .merge_env(&mut stack, &cwd)
.expect("Error merging environment"); .expect("Error merging environment");
let (block, delta) = { let empty_input = PipelineData::new(Span::test_data());
let mut working_set = StateWorkingSet::new(&*engine_state); let result = eval(example.example, empty_input, &cwd, engine_state);
let (output, err) = parse(
&mut working_set, // Note. Value implements PartialEq for Bool, Int, Float, String and Block
None, // If the command you are testing requires to compare another case, then
example.example.as_bytes(), // you need to define its equality in the Value struct
false, if let Some(expected) = example.result.as_ref() {
&[], assert_eq!(
&result, expected,
"The example result differs from the expected value",
)
}
}
fn check_all_signature_input_output_types_entries_have_examples(
signature: Signature,
witnessed_type_transformations: HashSet<(Type, Type)>,
) {
let declared_type_transformations =
HashSet::from_iter(signature.input_output_types.into_iter());
assert!(
witnessed_type_transformations.is_subset(&declared_type_transformations),
"This should not be possible (bug in test): the type transformations \
collected in the course of matching examples to the signature type map \
contain type transformations not present in the signature type map."
);
if !signature.allow_variants_without_examples {
assert_eq!(
witnessed_type_transformations,
declared_type_transformations,
"There are entries in the signature type map which do not correspond to any example: \
{:?}",
declared_type_transformations
.difference(&witnessed_type_transformations)
.map(|(s1, s2)| format!("{} -> {}", s1, s2))
.join(", ")
); );
}
}
if let Some(err) = err { fn eval(
panic!("test parse error in `{}`: {:?}", example.example, err) contents: &str,
} input: PipelineData,
cwd: &PathBuf,
engine_state: &mut Box<EngineState>,
) -> Value {
let (block, delta) = parse(contents, engine_state);
eval_block(block, input, cwd, engine_state, delta)
}
(output, working_set.render()) fn parse(contents: &str, engine_state: &Box<EngineState>) -> (Block, StateDelta) {
}; let mut working_set = StateWorkingSet::new(&*engine_state);
let (output, err) =
nu_parser::parse(&mut working_set, None, contents.as_bytes(), false, &[]);
if let Some(err) = err {
panic!("test parse error in `{}`: {:?}", contents, err)
}
(output, working_set.render())
}
fn eval_block(
block: Block,
input: PipelineData,
cwd: &PathBuf,
engine_state: &mut Box<EngineState>,
delta: StateDelta,
) -> Value {
engine_state engine_state
.merge_delta(delta) .merge_delta(delta)
.expect("Error merging delta"); .expect("Error merging delta");
let mut stack = Stack::new(); let mut stack = Stack::new();
// Set up PWD
stack.add_env_var( stack.add_env_var(
"PWD".to_string(), "PWD".to_string(),
Value::String { Value::String {
@ -117,33 +300,34 @@ pub fn test_examples(cmd: impl Command + 'static) {
}, },
); );
match eval_block( match nu_engine::eval_block(&engine_state, &mut stack, &block, input, true, true) {
&engine_state, Err(err) => panic!("test eval error in `{}`: {:?}", "TODO", err),
&mut stack, Ok(result) => result.into_value(Span::test_data()),
&block, }
PipelineData::new(Span::test_data()), }
true,
true,
) {
Err(err) => panic!("test eval error in `{}`: {:?}", example.example, err),
Ok(result) => {
let result = result.into_value(Span::test_data());
println!("input: {}", example.example);
println!("result: {:?}", result);
println!("done: {:?}", start.elapsed());
// Note. Value implements PartialEq for Bool, Int, Float, String and Block fn eval_pipeline_without_terminal_expression(
// If the command you are testing requires to compare another case, then src: &str,
// you need to define its equality in the Value struct cwd: &PathBuf,
if let Some(expected) = example.result { engine_state: &mut Box<EngineState>,
if result != expected { ) -> Option<Value> {
panic!( let (mut block, delta) = parse(src, engine_state);
"the example result is different to expected value: {:?} != {:?}", match block.pipelines.len() {
result, expected 1 => {
) let n_expressions = block.pipelines[0].expressions.len();
} block.pipelines[0].expressions.truncate(&n_expressions - 1);
if !block.pipelines[0].expressions.is_empty() {
let empty_input = PipelineData::new(Span::test_data());
Some(eval_block(block, empty_input, &cwd, engine_state, delta))
} else {
Some(Value::nothing(Span::test_data()))
} }
} }
_ => {
// E.g. multiple semicolon-separated statements
None
}
} }
} }
} }

View File

@ -2,7 +2,8 @@ use nu_engine::{eval_block, CallExt};
use nu_protocol::{ use nu_protocol::{
ast::Call, ast::Call,
engine::{CaptureBlock, Command, EngineState, Stack}, engine::{CaptureBlock, Command, EngineState, Stack},
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value, Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Type,
Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -15,6 +16,10 @@ impl Command for All {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build(self.name()) Signature::build(self.name())
.input_output_types(vec![
(Type::List(Box::new(Type::Any)), Type::Bool),
(Type::Table(vec![]), Type::Bool),
])
.required( .required(
"predicate", "predicate",
SyntaxShape::RowCondition, SyntaxShape::RowCondition,

View File

@ -2,7 +2,8 @@ use nu_engine::{eval_block, CallExt};
use nu_protocol::{ use nu_protocol::{
ast::Call, ast::Call,
engine::{CaptureBlock, Command, EngineState, Stack}, engine::{CaptureBlock, Command, EngineState, Stack},
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value, Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Type,
Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -15,6 +16,10 @@ impl Command for Any {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build(self.name()) Signature::build(self.name())
.input_output_types(vec![
(Type::List(Box::new(Type::Any)), Type::Bool),
(Type::Table(vec![]), Type::Bool),
])
.required( .required(
"predicate", "predicate",
SyntaxShape::RowCondition, SyntaxShape::RowCondition,

View File

@ -3,7 +3,7 @@ use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span, Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span,
SyntaxShape, Value, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -16,6 +16,10 @@ impl Command for Append {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("append") Signature::build("append")
.input_output_types(vec![(
Type::List(Box::new(Type::Any)),
Type::List(Box::new(Type::Any)),
)])
.required("row", SyntaxShape::Any, "the row, list, or table to append") .required("row", SyntaxShape::Any, "the row, list, or table to append")
.category(Category::Filters) .category(Category::Filters)
} }

View File

@ -2,7 +2,7 @@ use nu_engine::{eval_block, redirect_env, CallExt};
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack}; use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, IntoPipelineData, PipelineData, Signature, SyntaxShape, Value, Category, Example, IntoPipelineData, PipelineData, Signature, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -15,6 +15,7 @@ impl Command for Collect {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("collect") Signature::build("collect")
.input_output_types(vec![(Type::List(Box::new(Type::Any)), Type::Any)])
.required( .required(
"block", "block",
SyntaxShape::Block(Some(vec![SyntaxShape::Any])), SyntaxShape::Block(Some(vec![SyntaxShape::Any])),

View File

@ -3,7 +3,7 @@ use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, ShellError, Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, ShellError,
Signature, Span, Value, Signature, Span, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -15,7 +15,12 @@ impl Command for Columns {
} }
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build(self.name()).category(Category::Filters) Signature::build(self.name())
.input_output_types(vec![(
Type::Table(vec![]),
Type::List(Box::new(Type::String)),
)])
.category(Category::Filters)
} }
fn usage(&self) -> &str { fn usage(&self) -> &str {

View File

@ -1,7 +1,7 @@
use nu_engine::CallExt; use nu_engine::CallExt;
use nu_protocol::{ use nu_protocol::{
ast::Call, engine::Command, engine::EngineState, engine::Stack, Category, Example, ast::Call, engine::Command, engine::EngineState, engine::Stack, Category, Example,
PipelineData, ShellError, Signature, Span, SyntaxShape, Value, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -14,6 +14,19 @@ impl Command for Compact {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("compact") Signature::build("compact")
.input_output_types(vec![
(
Type::List(Box::new(Type::Any)),
Type::List(Box::new(Type::Any)),
),
(Type::Table(vec![]), Type::Table(vec![])),
(
// TODO: Should table be a subtype of List<Any>? If so then this
// entry would be unnecessary.
Type::Table(vec![]),
Type::List(Box::new(Type::Any)),
),
])
.rest( .rest(
"columns", "columns",
SyntaxShape::Any, SyntaxShape::Any,

View File

@ -1,7 +1,9 @@
use nu_engine::CallExt; use nu_engine::CallExt;
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, Signature, Span, Spanned, SyntaxShape, Value}; use nu_protocol::{
Category, Example, PipelineData, Signature, Span, Spanned, SyntaxShape, Type, Value,
};
#[derive(Clone)] #[derive(Clone)]
pub struct Default; pub struct Default;
@ -13,6 +15,9 @@ impl Command for Default {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("default") Signature::build("default")
// TODO: Give more specific type signature?
// TODO: Declare usage of cell paths in signature? (It seems to behave as if it uses cell paths)
.input_output_types(vec![(Type::Any, Type::Any)])
.required( .required(
"default value", "default value",
SyntaxShape::Any, SyntaxShape::Any,

View File

@ -3,7 +3,7 @@ use nu_protocol::ast::{Call, CellPath};
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, FromValue, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Category, Example, FromValue, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData,
ShellError, Signature, Span, SyntaxShape, Value, ShellError, Signature, Span, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -16,6 +16,7 @@ impl Command for DropColumn {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build(self.name()) Signature::build(self.name())
.input_output_types(vec![(Type::Table(vec![]), Type::Table(vec![]))])
.optional( .optional(
"columns", "columns",
SyntaxShape::Int, SyntaxShape::Int,
@ -25,7 +26,7 @@ impl Command for DropColumn {
} }
fn usage(&self) -> &str { fn usage(&self) -> &str {
"Remove the last number of columns. If you want to remove columns by name, try 'reject'." "Remove N columns at the right-hand end of the input table. To remove columns by name, use 'reject'."
} }
fn search_terms(&self) -> Vec<&str> { fn search_terms(&self) -> Vec<&str> {

View File

@ -4,7 +4,7 @@ use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span, Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span,
SyntaxShape, Value, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -17,16 +17,19 @@ impl Command for Drop {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("drop") Signature::build("drop")
.optional( .input_output_types(vec![
"rows", (Type::Table(vec![]), Type::Table(vec![])),
SyntaxShape::Int, (
"starting from the back, the number of rows to remove", Type::List(Box::new(Type::Any)),
) Type::List(Box::new(Type::Any)),
),
])
.optional("rows", SyntaxShape::Int, "The number of items to remove")
.category(Category::Filters) .category(Category::Filters)
} }
fn usage(&self) -> &str { fn usage(&self) -> &str {
"Remove the last several rows of the input. Counterpart of 'skip'. Opposite of 'last'." "Remove items/rows from the end of the input list/table. Counterpart of 'skip'. Opposite of 'last'."
} }
fn search_terms(&self) -> Vec<&str> { fn search_terms(&self) -> Vec<&str> {
@ -37,7 +40,7 @@ impl Command for Drop {
vec![ vec![
Example { Example {
example: "[0,1,2,3] | drop", example: "[0,1,2,3] | drop",
description: "Remove the last item of a list/table", description: "Remove the last item of a list",
result: Some(Value::List { result: Some(Value::List {
vals: vec![Value::test_int(0), Value::test_int(1), Value::test_int(2)], vals: vec![Value::test_int(0), Value::test_int(1), Value::test_int(2)],
span: Span::test_data(), span: Span::test_data(),
@ -45,7 +48,7 @@ impl Command for Drop {
}, },
Example { Example {
example: "[0,1,2,3] | drop 0", example: "[0,1,2,3] | drop 0",
description: "Remove zero item of a list/table", description: "Remove zero item of a list",
result: Some(Value::List { result: Some(Value::List {
vals: vec![ vals: vec![
Value::test_int(0), Value::test_int(0),
@ -58,12 +61,24 @@ impl Command for Drop {
}, },
Example { Example {
example: "[0,1,2,3] | drop 2", example: "[0,1,2,3] | drop 2",
description: "Remove the last two items of a list/table", description: "Remove the last two items of a list",
result: Some(Value::List { result: Some(Value::List {
vals: vec![Value::test_int(0), Value::test_int(1)], vals: vec![Value::test_int(0), Value::test_int(1)],
span: Span::test_data(), span: Span::test_data(),
}), }),
}, },
Example {
description: "Remove the last row in a table",
example: "[[a, b]; [1, 2] [3, 4]] | drop 1",
result: Some(Value::List {
vals: vec![Value::Record {
cols: vec!["a".to_string(), "b".to_string()],
vals: vec![Value::test_int(1), Value::test_int(2)],
span: Span::test_data(),
}],
span: Span::test_data(),
}),
},
] ]
} }

View File

@ -4,7 +4,7 @@ use nu_protocol::ast::{Call, RangeInclusion};
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, FromValue, IntoInterruptiblePipelineData, PipelineData, PipelineIterator, Category, Example, FromValue, IntoInterruptiblePipelineData, PipelineData, PipelineIterator,
Range, ShellError, Signature, Span, Spanned, SyntaxShape, Value, Range, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -17,6 +17,10 @@ impl Command for DropNth {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("drop nth") Signature::build("drop nth")
.input_output_types(vec![(
Type::List(Box::new(Type::Any)),
Type::List(Box::new(Type::Any)),
)])
.required( .required(
"row number or row range", "row number or row range",
// FIXME: we can make this accept either Int or Range when we can compose SyntaxShapes // FIXME: we can make this accept either Int or Range when we can compose SyntaxShapes

View File

@ -4,7 +4,7 @@ use nu_protocol::ast::Call;
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack}; use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Signature, Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Signature,
Span, SyntaxShape, Value, Span, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -35,6 +35,10 @@ with 'transpose' first."#
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("each") Signature::build("each")
.input_output_types(vec![(
Type::List(Box::new(Type::Any)),
Type::List(Box::new(Type::Any)),
)])
.required( .required(
"block", "block",
SyntaxShape::Block(Some(vec![SyntaxShape::Any])), SyntaxShape::Block(Some(vec![SyntaxShape::Any])),

View File

@ -3,7 +3,7 @@ use nu_protocol::ast::Call;
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack}; use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Signature, Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Signature,
Span, SyntaxShape, Value, Span, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -24,6 +24,10 @@ impl Command for EachWhile {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build(self.name()) Signature::build(self.name())
.input_output_types(vec![(
Type::List(Box::new(Type::Any)),
Type::List(Box::new(Type::Any)),
)])
.required( .required(
"block", "block",
SyntaxShape::Block(Some(vec![SyntaxShape::Any])), SyntaxShape::Block(Some(vec![SyntaxShape::Any])),

View File

@ -2,7 +2,7 @@ use nu_engine::CallExt;
use nu_protocol::ast::{Call, CellPath}; use nu_protocol::ast::{Call, CellPath};
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, IntoPipelineData, PipelineData, Signature, Span, SyntaxShape, Value, Category, Example, IntoPipelineData, PipelineData, Signature, Span, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -15,6 +15,7 @@ impl Command for Empty {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("is-empty") Signature::build("is-empty")
.input_output_types(vec![(Type::Any, Type::Bool)])
.rest( .rest(
"rest", "rest",
SyntaxShape::CellPath, SyntaxShape::CellPath,

View File

@ -4,7 +4,7 @@ use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span, Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span,
SyntaxShape, Value, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -17,6 +17,10 @@ impl Command for Every {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("every") Signature::build("every")
.input_output_types(vec![(
Type::List(Box::new(Type::Any)),
Type::List(Box::new(Type::Any)),
)])
.required( .required(
"stride", "stride",
SyntaxShape::Int, SyntaxShape::Int,

View File

@ -9,7 +9,7 @@ use nu_protocol::{
ast::Call, ast::Call,
engine::{CaptureBlock, Command, EngineState, Stack}, engine::{CaptureBlock, Command, EngineState, Stack},
Category, Config, Example, IntoInterruptiblePipelineData, ListStream, PipelineData, ShellError, Category, Config, Example, IntoInterruptiblePipelineData, ListStream, PipelineData, ShellError,
Signature, Span, SyntaxShape, Value, Signature, Span, SyntaxShape, Type, Value,
}; };
use nu_utils::get_ls_colors; use nu_utils::get_ls_colors;
@ -23,6 +23,20 @@ impl Command for Find {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build(self.name()) Signature::build(self.name())
.input_output_types(vec![
(
// TODO: This is too permissive; if we could express this
// using a type parameter it would be List<T> -> List<T>.
Type::List(Box::new(Type::Any)),
Type::List(Box::new(Type::Any)),
),
(Type::String, Type::String),
(
// For find -p
Type::Table(vec![]),
Type::Table(vec![]),
),
])
.named( .named(
"predicate", "predicate",
SyntaxShape::Block(Some(vec![SyntaxShape::Any])), SyntaxShape::Block(Some(vec![SyntaxShape::Any])),

View File

@ -16,6 +16,24 @@ impl Command for First {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("first") Signature::build("first")
.input_output_types(vec![
(
// TODO: This variant duplicates the functionality of
// `take`. See #6611, #6611, #6893
// TODO: This is too permissive; if we could express this
// using a type parameter style it would be List<T> ->
// List<T>.
Type::List(Box::new(Type::Any)),
Type::List(Box::new(Type::Any)),
),
(
// TODO: This is too permissive; if we could express this
// using a type parameter it would be List<T> -> T.
Type::List(Box::new(Type::Any)),
Type::Any,
),
(Type::Binary, Type::Binary),
])
.optional( .optional(
"rows", "rows",
SyntaxShape::Int, SyntaxShape::Int,

View File

@ -4,7 +4,7 @@ use nu_protocol::ast::{Call, CellPath, PathMember};
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value, Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -17,6 +17,13 @@ impl Command for Flatten {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("flatten") Signature::build("flatten")
.input_output_types(vec![
(
Type::List(Box::new(Type::Any)),
Type::List(Box::new(Type::Any)),
),
(Type::Record(vec![]), Type::Table(vec![])),
])
.rest( .rest(
"rest", "rest",
SyntaxShape::String, SyntaxShape::String,

View File

@ -3,7 +3,7 @@ use nu_protocol::ast::{Call, CellPath};
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Signature, Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Signature,
SyntaxShape, Value, Span, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -20,6 +20,15 @@ impl Command for Get {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("get") Signature::build("get")
.input_output_types(vec![
(
// TODO: This is too permissive; if we could express this
// using a type parameter it would be List<T> -> T.
Type::List(Box::new(Type::Any)),
Type::Any,
),
(Type::Table(vec![]), Type::Any),
])
.required( .required(
"cell_path", "cell_path",
SyntaxShape::CellPath, SyntaxShape::CellPath,
@ -92,6 +101,24 @@ impl Command for Get {
} }
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
vec![ vec![
Example {
description: "Get an item from a list",
example: "[0 1 2] | get 1",
result: Some(Value::test_int(1)),
},
Example {
description: "Get a column from a table",
example: "[{A: A0}] | get A",
result: Some(Value::List {
vals: vec![Value::test_string("A0")],
span: Span::test_data(),
}),
},
Example {
description: "Get a cell from a table",
example: "[{A: A0}] | get 0.A",
result: Some(Value::test_string("A0")),
},
Example { Example {
description: "Extract the name of files as a list", description: "Extract the name of files as a list",
example: "ls | get name", example: "ls | get name",
@ -125,3 +152,15 @@ impl Command for Get {
] ]
} }
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_examples() {
use crate::test_examples;
test_examples(Get)
}
}

View File

@ -3,7 +3,7 @@ use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, PipelineData, Signature, Span, Spanned, Category, Example, IntoInterruptiblePipelineData, PipelineData, Signature, Span, Spanned,
SyntaxShape, Value, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -16,6 +16,14 @@ impl Command for Group {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("group") Signature::build("group")
// TODO: It accepts Table also, but currently there is no Table
// example. Perhaps Table should be a subtype of List, in which case
// the current signature would suffice even when a Table example
// exists.
.input_output_types(vec![(
Type::List(Box::new(Type::Any)),
Type::List(Box::new(Type::List(Box::new(Type::Any)))),
)])
.required("group_size", SyntaxShape::Int, "the size of each group") .required("group_size", SyntaxShape::Int, "the size of each group")
.category(Category::Filters) .category(Category::Filters)
} }

View File

@ -3,7 +3,7 @@ use nu_protocol::ast::Call;
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack}; use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape,
Value, Type, Value,
}; };
use indexmap::IndexMap; use indexmap::IndexMap;
@ -17,15 +17,20 @@ impl Command for GroupBy {
} }
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("group-by").optional( Signature::build("group-by")
"grouper", // TODO: It accepts Table also, but currently there is no Table
SyntaxShape::Any, // example. Perhaps Table should be a subtype of List, in which case
"the grouper value to use", // the current signature would suffice even when a Table example
) // exists.
.input_output_types(vec![(
Type::List(Box::new(Type::Any)),
Type::Record(vec![]),
)])
.optional("grouper", SyntaxShape::Any, "the grouper value to use")
} }
fn usage(&self) -> &str { fn usage(&self) -> &str {
"Split a table into groups based on one column's values, and return a record with those groups." "Splits a list or table into groups, and returns a record containing those groups."
} }
fn run( fn run(
@ -47,7 +52,7 @@ impl Command for GroupBy {
}, },
Example { Example {
description: "You can also group by raw values by leaving out the argument", description: "You can also group by raw values by leaving out the argument",
example: "echo ['1' '3' '1' '3' '2' '1' '1'] | group-by", example: "['1' '3' '1' '3' '2' '1' '1'] | group-by",
result: Some(Value::Record { result: Some(Value::Record {
cols: vec!["1".to_string(), "3".to_string(), "2".to_string()], cols: vec!["1".to_string(), "3".to_string(), "2".to_string()],
vals: vec![ vals: vec![

View File

@ -1,7 +1,8 @@
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Config, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Value, Category, Config, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Type,
Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -13,7 +14,16 @@ impl Command for Headers {
} }
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build(self.name()).category(Category::Filters) Signature::build(self.name())
.input_output_types(vec![
(Type::Table(vec![]), Type::Table(vec![])),
(
// Tables with missing values are List<Any>
Type::List(Box::new(Type::Any)),
Type::Table(vec![]),
),
])
.category(Category::Filters)
} }
fn usage(&self) -> &str { fn usage(&self) -> &str {

View File

@ -3,7 +3,7 @@ use nu_protocol::ast::{Call, CellPath, PathMember};
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack}; use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, FromValue, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Category, Example, FromValue, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData,
ShellError, Signature, Span, SyntaxShape, Value, ShellError, Signature, Span, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -16,6 +16,14 @@ impl Command for Insert {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("insert") Signature::build("insert")
.input_output_types(vec![
(Type::Record(vec![]), Type::Record(vec![])),
// TODO: It accepts table input also (in which case it repeats
// the value across all table rows) but currently there is no
// example of the table variant so it cannot be in the
// signature.
// (Type::Table(vec![]), Type::Table(vec![])),
])
.required( .required(
"field", "field",
SyntaxShape::CellPath, SyntaxShape::CellPath,
@ -49,8 +57,8 @@ impl Command for Insert {
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
vec![Example { vec![Example {
description: "Insert a new value", description: "Insert a new entry into a record",
example: "echo {'name': 'nu', 'stars': 5} | insert alias 'Nushell'", example: "{'name': 'nu', 'stars': 5} | insert alias 'Nushell'",
result: Some(Value::Record { result: Some(Value::Record {
cols: vec!["name".into(), "stars".into(), "alias".into()], cols: vec!["name".into(), "stars".into(), "alias".into()],
vals: vec![ vals: vec![

View File

@ -4,7 +4,7 @@ use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, ShellError, Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, ShellError,
Signature, Span, SyntaxShape, Value, Signature, Span, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -17,6 +17,23 @@ impl Command for Last {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("last") Signature::build("last")
.input_output_types(vec![
(
// TODO: This variant duplicates the functionality of
// `take`. See #6611, #6611, #6893
// TODO: This is too permissive; if we could express this
// using a type parameter style it would be List<T> ->
// List<T>.
Type::List(Box::new(Type::Any)),
Type::List(Box::new(Type::Any)),
),
(
// TODO: This is too permissive; if we could express this
// using a type parameter it would be List<T> -> T.
Type::List(Box::new(Type::Any)),
Type::Any,
),
])
.optional( .optional(
"rows", "rows",
SyntaxShape::Int, SyntaxShape::Int,

View File

@ -3,7 +3,7 @@ use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, ShellError, Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, ShellError,
Signature, Span, Value, Signature, Span, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -20,6 +20,10 @@ impl Command for Length {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("length") Signature::build("length")
.input_output_types(vec![
(Type::List(Box::new(Type::Any)), Type::Int),
(Type::Table(vec![]), Type::Int),
])
.switch("column", "Show the number of columns in a table", Some('c')) .switch("column", "Show the number of columns in a table", Some('c'))
.category(Category::Filters) .category(Category::Filters)
} }

View File

@ -2,7 +2,7 @@ use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, PipelineData, RawStream, ShellError, Category, Example, IntoInterruptiblePipelineData, PipelineData, RawStream, ShellError,
Signature, Span, Value, Signature, Span, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -19,6 +19,7 @@ impl Command for Lines {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("lines") Signature::build("lines")
.input_output_types(vec![(Type::String, Type::List(Box::new(Type::String)))])
.switch("skip-empty", "skip empty lines", Some('s')) .switch("skip-empty", "skip empty lines", Some('s'))
.category(Category::Filters) .category(Category::Filters)
} }

View File

@ -3,7 +3,7 @@ use nu_protocol::ast::Call;
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack}; use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, FromValue, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Category, Example, FromValue, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData,
ShellError, Signature, Span, SyntaxShape, Value, ShellError, Signature, Span, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -29,6 +29,10 @@ repeating this process with row 1, and so on."#
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("merge") Signature::build("merge")
.input_output_types(vec![
(Type::Record(vec![]), Type::Record(vec![])),
(Type::Table(vec![]), Type::Table(vec![])),
])
.required( .required(
"block", "block",
// Both this and `update` should have a shape more like <record> | <table> | <block> than just <any>. -Leon 2022-10-27 // Both this and `update` should have a shape more like <record> | <table> | <block> than just <any>. -Leon 2022-10-27
@ -64,10 +68,11 @@ repeating this process with row 1, and so on."#
Example { Example {
example: "{a: 1, b: 2} | merge {c: 3}", example: "{a: 1, b: 2} | merge {c: 3}",
description: "Merge two records", description: "Merge two records",
result: Some(Value::test_record( result: Some(Value::Record {
vec!["a", "b", "c"], cols: vec!["a".to_string(), "b".to_string(), "c".to_string()],
vec![Value::test_int(1), Value::test_int(2), Value::test_int(3)], vals: vec![Value::test_int(1), Value::test_int(2), Value::test_int(3)],
)), span: Span::test_data(),
}),
}, },
Example { Example {
example: "{a: 1, b: 3} | merge { { b: 2 } | merge { c: 4 } }", example: "{a: 1, b: 3} | merge { { b: 2 } | merge { c: 4 } }",
@ -77,6 +82,17 @@ repeating this process with row 1, and so on."#
vec![Value::test_int(1), Value::test_int(2), Value::test_int(4)], vec![Value::test_int(1), Value::test_int(2), Value::test_int(4)],
)), )),
}, },
Example {
example: "[{columnA: A0 columnB: B0}] | merge [{columnA: 'A0*'}]",
description: "Merge two tables, overwriting overlapping columns",
result: Some(Value::List {
vals: vec![Value::test_record(
vec!["columnA", "columnB"],
vec![Value::test_string("A0*"), Value::test_string("B0")],
)],
span: Span::test_data(),
}),
},
] ]
} }

View File

@ -3,7 +3,7 @@ use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, ShellError, Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, ShellError,
Signature, Span, Spanned, SyntaxShape, Value, Signature, Span, Spanned, SyntaxShape, Type, Value,
}; };
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -26,6 +26,10 @@ impl Command for Move {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("move") Signature::build("move")
.input_output_types(vec![
(Type::Table(vec![]), Type::Table(vec![])),
(Type::Record(vec![]), Type::Record(vec![])),
])
.rest("columns", SyntaxShape::String, "the columns to move") .rest("columns", SyntaxShape::String, "the columns to move")
.named( .named(
"after", "after",

View File

@ -3,7 +3,7 @@ use nu_protocol::ast::Call;
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack}; use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Signature, Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Signature,
Span, SyntaxShape, Value, Span, SyntaxShape, Type, Value,
}; };
use rayon::prelude::*; use rayon::prelude::*;
@ -23,6 +23,10 @@ impl Command for ParEach {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("par-each") Signature::build("par-each")
.input_output_types(vec![(
Type::List(Box::new(Type::Any)),
Type::List(Box::new(Type::Any)),
)])
.required( .required(
"block", "block",
SyntaxShape::Block(Some(vec![SyntaxShape::Any])), SyntaxShape::Block(Some(vec![SyntaxShape::Any])),

View File

@ -3,7 +3,7 @@ use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span, Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span,
SyntaxShape, Value, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -16,6 +16,10 @@ impl Command for Prepend {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("prepend") Signature::build("prepend")
.input_output_types(vec![(
Type::List(Box::new(Type::Any)),
Type::List(Box::new(Type::Any)),
)])
.required( .required(
"row", "row",
SyntaxShape::Any, SyntaxShape::Any,

View File

@ -4,7 +4,7 @@ use nu_protocol::ast::{Call, RangeInclusion};
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span, Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span,
SyntaxShape, Value, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -17,6 +17,10 @@ impl Command for Range {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("range") Signature::build("range")
.input_output_types(vec![(
Type::List(Box::new(Type::Any)),
Type::List(Box::new(Type::Any)),
)])
.required( .required(
"rows", "rows",
SyntaxShape::Range, SyntaxShape::Range,

View File

@ -5,7 +5,7 @@ use nu_engine::{eval_block, CallExt};
use nu_protocol::ast::Call; use nu_protocol::ast::Call;
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack}; use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape, Value, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape, Type, Value,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -18,6 +18,7 @@ impl Command for Reduce {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("reduce") Signature::build("reduce")
.input_output_types(vec![(Type::List(Box::new(Type::Any)), Type::Any)])
.named( .named(
"fold", "fold",
SyntaxShape::Any, SyntaxShape::Any,

Some files were not shown because too many files have changed in this diff Show More