diff --git a/crates/nu-command/src/bits/not.rs b/crates/nu-command/src/bits/not.rs index 027bfeff4..1b5b2475d 100644 --- a/crates/nu-command/src/bits/not.rs +++ b/crates/nu-command/src/bits/not.rs @@ -90,7 +90,7 @@ impl Command for SubCommand { Example { description: "Apply logical negation to a list of numbers, treat input as 2 bytes number", - example: "[4 3 2] | bits not -n 2", + example: "[4 3 2] | bits not -n '2'", result: Some(Value::List { vals: vec![ Value::test_int(65531), diff --git a/crates/nu-command/src/bits/rotate_right.rs b/crates/nu-command/src/bits/rotate_right.rs index f6e5fba8e..6c43c1554 100644 --- a/crates/nu-command/src/bits/rotate_right.rs +++ b/crates/nu-command/src/bits/rotate_right.rs @@ -85,7 +85,7 @@ impl Command for SubCommand { }, Example { description: "Rotate right a list of numbers of one byte", - example: "[15 33 92] | bits ror 2 -n 1", + example: "[15 33 92] | bits ror 2 -n '1'", result: Some(Value::List { vals: vec![ Value::test_int(195), diff --git a/crates/nu-command/src/bits/shift_left.rs b/crates/nu-command/src/bits/shift_left.rs index c0e4b238b..21d0a448c 100644 --- a/crates/nu-command/src/bits/shift_left.rs +++ b/crates/nu-command/src/bits/shift_left.rs @@ -85,7 +85,7 @@ impl Command for SubCommand { }, Example { description: "Shift left a number with 1 byte by 7 bits", - example: "2 | bits shl 7 -n 1", + example: "2 | bits shl 7 -n '1'", result: Some(Value::test_int(0)), }, Example { diff --git a/crates/nu-command/src/conversions/fill.rs b/crates/nu-command/src/conversions/fill.rs index f560daa5c..58791b38e 100644 --- a/crates/nu-command/src/conversions/fill.rs +++ b/crates/nu-command/src/conversions/fill.rs @@ -105,7 +105,7 @@ impl Command for Fill { Example { description: "Fill a number on the left side to a width of 5 with the character '0'", - example: "1 | fill --alignment right --character 0 --width 5", + example: "1 | fill --alignment right --character '0' --width 5", result: Some(Value::String { val: "00001".into(), span: Span::test_data(), @@ -113,7 +113,7 @@ impl Command for Fill { }, Example { description: "Fill a number on both sides to a width of 5 with the character '0'", - example: "1.1 | fill --alignment center --character 0 --width 5", + example: "1.1 | fill --alignment center --character '0' --width 5", result: Some(Value::String { val: "01.10".into(), span: Span::test_data(), @@ -122,7 +122,7 @@ impl Command for Fill { Example { description: "Fill a filesize on the left side to a width of 5 with the character '0'", - example: "1kib | fill --alignment middle --character 0 --width 10", + example: "1kib | fill --alignment middle --character '0' --width 10", result: Some(Value::String { val: "0001024000".into(), span: Span::test_data(), diff --git a/crates/nu-command/src/debug/debug_.rs b/crates/nu-command/src/debug/debug_.rs index 255bbc0b5..34be1be10 100644 --- a/crates/nu-command/src/debug/debug_.rs +++ b/crates/nu-command/src/debug/debug_.rs @@ -76,7 +76,8 @@ impl Command for Debug { }, Example { description: "Debug print a table", - example: "[[version patch]; [0.1.0 false] [0.1.1 true] [0.2.0 false]] | debug", + example: + "[[version patch]; ['0.1.0' false] ['0.1.1' true] ['0.2.0' false]] | debug", result: Some(Value::List { vals: vec![ Value::test_string("{version: 0.1.0, patch: false}"), diff --git a/crates/nu-command/src/filters/find.rs b/crates/nu-command/src/filters/find.rs index f634fb4d8..bb92cd0e6 100644 --- a/crates/nu-command/src/filters/find.rs +++ b/crates/nu-command/src/filters/find.rs @@ -119,7 +119,7 @@ impl Command for Find { }, Example { description: "Find value in records", - example: r#"[[version name]; [0.1.0 nushell] [0.1.1 fish] [0.2.0 zsh]] | find -r "nu""#, + example: r#"[[version name]; ['0.1.0' nushell] ['0.1.1' fish] ['0.2.0' zsh]] | find -r "nu""#, result: Some(Value::List { vals: vec![Value::test_record( vec!["version", "name"], diff --git a/crates/nu-command/src/shells/g.rs b/crates/nu-command/src/shells/g.rs index a5eb1b7c5..570600582 100644 --- a/crates/nu-command/src/shells/g.rs +++ b/crates/nu-command/src/shells/g.rs @@ -3,7 +3,7 @@ use nu_engine::CallExt; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::{ - Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Type, + Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type, Value, }; /// Source a file for environment variables. @@ -23,7 +23,7 @@ impl Command for GotoShell { ]) .optional( "shell_number", - SyntaxShape::String, + SyntaxShape::OneOf(vec![SyntaxShape::Int, SyntaxShape::String]), "shell number to change to", ) .category(Category::Shells) @@ -40,23 +40,32 @@ impl Command for GotoShell { call: &Call, _input: PipelineData, ) -> Result { - let new_shell: Option> = call.opt(engine_state, stack, 0)?; + let new_shell: Option = call.opt(engine_state, stack, 0)?; match new_shell { - Some(shell_span) => { - if shell_span.item == "-" { - switch_shell(engine_state, stack, call, shell_span.span, SwitchTo::Last) - } else { - let n = shell_span - .item - .parse::() - .map_err(|_| ShellError::NotFound { - span: shell_span.span, - })?; - - switch_shell(engine_state, stack, call, shell_span.span, SwitchTo::Nth(n)) + Some(shell_span) => match &shell_span { + Value::String { val, span } => { + if val == "-" { + switch_shell(engine_state, stack, call, *span, SwitchTo::Last) + } else { + Err(ShellError::TypeMismatch { + err_message: "int or '-'".into(), + span: *span, + }) + } } - } + Value::Int { val, span } => switch_shell( + engine_state, + stack, + call, + *span, + SwitchTo::Nth(*val as usize), + ), + _ => Err(ShellError::TypeMismatch { + err_message: "int or '-'".into(), + span: call.head, + }), + }, None => list_shells(engine_state, stack, call.head), } } diff --git a/crates/nu-command/src/strings/char_.rs b/crates/nu-command/src/strings/char_.rs index 0884f40ec..d3acf9c0b 100644 --- a/crates/nu-command/src/strings/char_.rs +++ b/crates/nu-command/src/strings/char_.rs @@ -197,7 +197,7 @@ impl Command for Char { }, Example { description: "Output Unicode character", - example: r#"char -u 1f378"#, + example: r#"char -u '1f378'"#, result: Some(Value::test_string("\u{1f378}")), }, Example { @@ -207,7 +207,7 @@ impl Command for Char { }, Example { description: "Output multi-byte Unicode character", - example: r#"char -u 1F468 200D 1F466 200D 1F466"#, + example: r#"char -u '1F468' '200D' '1F466' '200D' '1F466'"#, result: Some(Value::test_string( "\u{1F468}\u{200D}\u{1F466}\u{200D}\u{1F466}", )), diff --git a/crates/nu-command/src/viewers/griddle.rs b/crates/nu-command/src/viewers/griddle.rs index b26e5ef8f..bffc232b0 100644 --- a/crates/nu-command/src/viewers/griddle.rs +++ b/crates/nu-command/src/viewers/griddle.rs @@ -160,7 +160,7 @@ prints out the list properly."# }, Example { description: "Render a table with 'name' column in it to a grid", - example: "[[name patch]; [0.1.0 false] [0.1.1 true] [0.2.0 false]] | grid", + example: "[[name patch]; ['0.1.0' false] ['0.1.1' true] ['0.2.0' false]] | grid", result: Some(Value::test_string("0.1.0 │ 0.1.1 │ 0.2.0\n")), }, ] diff --git a/crates/nu-command/tests/commands/all.rs b/crates/nu-command/tests/commands/all.rs index 89c446829..948a459a5 100644 --- a/crates/nu-command/tests/commands/all.rs +++ b/crates/nu-command/tests/commands/all.rs @@ -44,10 +44,10 @@ fn checks_all_columns_of_a_table_is_true() { r#" echo [ [ first_name, last_name, rusty_at, likes ]; - [ Andrés, Robalino, 10/11/2013, 1 ] - [ JT, Turner, 10/12/2013, 1 ] - [ Darren, Schroeder, 10/11/2013, 1 ] - [ Yehuda, Katz, 10/11/2013, 1 ] + [ Andrés, Robalino, '10/11/2013', 1 ] + [ JT, Turner, '10/12/2013', 1 ] + [ Darren, Schroeder, '10/11/2013', 1 ] + [ Yehuda, Katz, '10/11/2013', 1 ] ] | all {|x| $x.likes > 0 } "# diff --git a/crates/nu-command/tests/commands/any.rs b/crates/nu-command/tests/commands/any.rs index c61f6c538..f01c10320 100644 --- a/crates/nu-command/tests/commands/any.rs +++ b/crates/nu-command/tests/commands/any.rs @@ -20,12 +20,12 @@ fn checks_any_column_of_a_table_is_true() { r#" echo [ [ first_name, last_name, rusty_at, likes ]; - [ Andrés, Robalino, 10/11/2013, 1 ] - [ JT, Turner, 10/12/2013, 1 ] - [ Darren, Schroeder, 10/11/2013, 1 ] - [ Yehuda, Katz, 10/11/2013, 1 ] + [ Andrés, Robalino, '10/11/2013', 1 ] + [ JT, Turner, '10/12/2013', 1 ] + [ Darren, Schroeder, '10/11/2013', 1 ] + [ Yehuda, Katz, '10/11/2013', 1 ] ] - | any {|x| $x.rusty_at == 10/12/2013 } + | any {|x| $x.rusty_at == '10/12/2013' } "# )); diff --git a/crates/nu-command/tests/commands/cal.rs b/crates/nu-command/tests/commands/cal.rs index 70261fd4c..61c0ba2e7 100644 --- a/crates/nu-command/tests/commands/cal.rs +++ b/crates/nu-command/tests/commands/cal.rs @@ -33,7 +33,7 @@ fn cal_friday_the_thirteenths_in_2015() { let actual = nu!( cwd: ".", pipeline( r#" - cal --full-year 2015 | default friday 0 | where friday == 13 | length + cal --full-year 2015 | default 0 friday | where friday == 13 | length "# )); diff --git a/crates/nu-command/tests/commands/move_/mv.rs b/crates/nu-command/tests/commands/move_/mv.rs index 2e1414a59..56064822b 100644 --- a/crates/nu-command/tests/commands/move_/mv.rs +++ b/crates/nu-command/tests/commands/move_/mv.rs @@ -367,7 +367,7 @@ fn does_not_error_when_some_file_is_moving_into_itself() { let original_dir = dirs.test().join("11"); let expected = dirs.test().join("12/11"); - nu!(cwd: dirs.test(), "mv 1* 12"); + nu!(cwd: dirs.test(), "mv `1*` `12`"); assert!(!original_dir.exists()); assert!(expected.exists()); diff --git a/crates/nu-command/tests/commands/reject.rs b/crates/nu-command/tests/commands/reject.rs index 06440b0f7..d393016c8 100644 --- a/crates/nu-command/tests/commands/reject.rs +++ b/crates/nu-command/tests/commands/reject.rs @@ -7,9 +7,9 @@ fn regular_columns() { echo [ [first_name, last_name, rusty_at, type]; - [Andrés Robalino 10/11/2013 A] - [JT Turner 10/12/2013 B] - [Yehuda Katz 10/11/2013 A] + [Andrés Robalino '10/11/2013' A] + [JT Turner '10/12/2013' B] + [Yehuda Katz '10/11/2013' A] ] | reject type first_name | columns diff --git a/crates/nu-command/tests/commands/run_external.rs b/crates/nu-command/tests/commands/run_external.rs index cd6833117..1a7e5b6a1 100644 --- a/crates/nu-command/tests/commands/run_external.rs +++ b/crates/nu-command/tests/commands/run_external.rs @@ -219,7 +219,7 @@ fn external_command_expand_tilde_with_back_quotes() { "external command not expand tilde with quotes", |dirs, _| { let actual = nu!(cwd: dirs.test(), pipeline(r#"nu --testbin nonu `~`"#)); - assert!(!actual.out.contains("~")); + assert!(!actual.out.contains('~')); }, ) } diff --git a/crates/nu-command/tests/commands/select.rs b/crates/nu-command/tests/commands/select.rs index 02a606364..5b4fd9b7c 100644 --- a/crates/nu-command/tests/commands/select.rs +++ b/crates/nu-command/tests/commands/select.rs @@ -9,9 +9,9 @@ fn regular_columns() { echo [ [first_name, last_name, rusty_at, type]; - [Andrés Robalino 10/11/2013 A] - [JT Turner 10/12/2013 B] - [Yehuda Katz 10/11/2013 A] + [Andrés Robalino '10/11/2013' A] + [JT Turner '10/12/2013' B] + [Yehuda Katz '10/11/2013' A] ] | select rusty_at last_name | get 0 @@ -72,9 +72,9 @@ fn fails_if_given_unknown_column_name() { echo [ [first_name, last_name, rusty_at, type]; - [Andrés Robalino 10/11/2013 A] - [JT Turner 10/12/2013 B] - [Yehuda Katz 10/11/2013 A] + [Andrés Robalino '10/11/2013' A] + [JT Turner '10/12/2013' B] + [Yehuda Katz '10/11/2013' A] ] | select rrusty_at first_name | length diff --git a/crates/nu-command/tests/commands/str_/mod.rs b/crates/nu-command/tests/commands/str_/mod.rs index b7ff45c34..6d5c5c62c 100644 --- a/crates/nu-command/tests/commands/str_/mod.rs +++ b/crates/nu-command/tests/commands/str_/mod.rs @@ -234,7 +234,7 @@ fn substrings_the_input() { cwd: dirs.test(), pipeline( r#" open sample.toml - | str substring 6,14 fortune.teller.phone + | str substring '6,14' fortune.teller.phone | get fortune.teller.phone "# )); @@ -258,7 +258,7 @@ fn substring_errors_if_start_index_is_greater_than_end_index() { cwd: dirs.test(), pipeline( r#" open sample.toml - | str substring 6,5 fortune.teller.phone + | str substring '6,5' fortune.teller.phone "# )); @@ -283,7 +283,7 @@ fn substrings_the_input_and_returns_the_string_if_end_index_exceeds_length() { cwd: dirs.test(), pipeline( r#" open sample.toml - | str substring 0,999 package.name + | str substring '0,999' package.name | get package.name "# )); @@ -307,7 +307,7 @@ fn substrings_the_input_and_returns_blank_if_start_index_exceeds_length() { cwd: dirs.test(), pipeline( r#" open sample.toml - | str substring 50,999 package.name + | str substring '50,999' package.name | get package.name "# )); @@ -331,7 +331,7 @@ fn substrings_the_input_and_treats_start_index_as_zero_if_blank_start_index_give cwd: dirs.test(), pipeline( r#" open sample.toml - | str substring ,2 package.name + | str substring ',2' package.name | get package.name "# )); @@ -355,7 +355,7 @@ fn substrings_the_input_and_treats_end_index_as_length_if_blank_end_index_given( cwd: dirs.test(), pipeline( r#" open sample.toml - | str substring 3, package.name + | str substring '3,' package.name | get package.name "# )); diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index 8f390ddd9..70ea11c18 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -1744,6 +1744,72 @@ pub fn parse_paren_expr( } } +pub fn parse_numberlike_expr( + working_set: &mut StateWorkingSet, + span: Span, + shape: &SyntaxShape, + expand_aliases_denylist: &[usize], +) -> (Expression, Option) { + let bytes = working_set.get_span_contents(span); + match shape { + SyntaxShape::Binary => parse_binary(working_set, span), + SyntaxShape::Number => parse_number(bytes, span), + SyntaxShape::Decimal => parse_float(bytes, span), + SyntaxShape::Int => parse_int(bytes, span), + SyntaxShape::Duration => parse_duration(working_set, span), + SyntaxShape::DateTime => parse_datetime(working_set, span), + SyntaxShape::Filesize => parse_filesize(working_set, span), + SyntaxShape::Range => parse_range(working_set, span, expand_aliases_denylist), + SyntaxShape::CellPath => parse_simple_cell_path(working_set, span, expand_aliases_denylist), + SyntaxShape::Any => { + if bytes == b"0b" { + // FIXME: having to work around this filesize that also looks like a binary value + parse_filesize(working_set, span) + } else if bytes.starts_with(b"0x[") + || bytes.starts_with(b"0b[") + || bytes.starts_with(b"0o[") + { + parse_binary(working_set, span) + } else if bytes.starts_with(b"0x") + || bytes.starts_with(b"0b") + || bytes.starts_with(b"0o") + { + parse_int(bytes, span) + } else { + for shape in &[ + SyntaxShape::Range, + SyntaxShape::Int, + SyntaxShape::Binary, + SyntaxShape::Filesize, + SyntaxShape::Duration, + SyntaxShape::DateTime, //FIXME requires 3 failed conversion attempts before failing + SyntaxShape::Number, + ] { + let (result, err) = + parse_value(working_set, span, shape, expand_aliases_denylist); + if err.is_none() { + return (result, err); + } + } + ( + garbage(span), + Some(ParseError::Expected( + "number-like value (int, float, date, etc)".into(), + span, + )), + ) + } + } + _ => ( + garbage(span), + Some(ParseError::Expected( + "number-like value (int, float, date, etc)".into(), + span, + )), + ), + } +} + pub fn parse_brace_expr( working_set: &mut StateWorkingSet, span: Span, @@ -4891,7 +4957,9 @@ pub fn parse_value( None, ); } - + b"-inf" | b"inf" | b"NaN" => { + return parse_numberlike_expr(working_set, span, shape, expand_aliases_denylist); + } _ => {} } @@ -4915,6 +4983,20 @@ pub fn parse_value( ); } }, + x if x.is_ascii_digit() => { + // Anything that starts with a number now has to be a number-like value + // These include values like ints, floats, dates, durations, etc + // To create a string, wrap in quotes, to create a bare word, wrap in backticks + return parse_numberlike_expr(working_set, span, shape, expand_aliases_denylist); + } + b'-' | b'+' => { + if bytes.len() > 1 && bytes[1].is_ascii_digit() { + // Anything that starts with a negative number now has to be a number-like value + // These include values like ints, floats, dates, durations, etc + // To create a string, wrap in quotes, to create a bare word, wrap in backticks + return parse_numberlike_expr(working_set, span, shape, expand_aliases_denylist); + } + } _ => {} } @@ -4925,12 +5007,6 @@ pub fn parse_value( expression.custom_completion = Some(*custom_completion); (expression, err) } - SyntaxShape::Number => parse_number(bytes, span), - SyntaxShape::Decimal => parse_float(bytes, span), - SyntaxShape::Int => parse_int(bytes, span), - SyntaxShape::Duration => parse_duration(working_set, span), - SyntaxShape::DateTime => parse_datetime(working_set, span), - SyntaxShape::Filesize => parse_filesize(working_set, span), SyntaxShape::Range => parse_range(working_set, span, expand_aliases_denylist), SyntaxShape::Filepath => parse_filepath(working_set, span), SyntaxShape::Directory => parse_directory(working_set, span), @@ -5004,32 +5080,11 @@ pub fn parse_value( //parse_value(working_set, span, &SyntaxShape::Table) parse_full_cell_path(working_set, None, span, expand_aliases_denylist) } else { - /* Parser very sensitive to order of shapes tried. Recording the original order for postierity let shapes = [ - SyntaxShape::Binary, - SyntaxShape::Int, - SyntaxShape::Number, - SyntaxShape::Range, - SyntaxShape::DateTime, - SyntaxShape::Filesize, - SyntaxShape::Duration, - SyntaxShape::Record, - SyntaxShape::Closure(None), - SyntaxShape::Block, - SyntaxShape::String, - ]; - */ - let shapes = [ - SyntaxShape::Binary, - SyntaxShape::Filesize, - SyntaxShape::Duration, SyntaxShape::Range, - SyntaxShape::DateTime, //FIXME requires 3 failed conversion attempts before failing SyntaxShape::Record, SyntaxShape::Closure(None), SyntaxShape::Block, - SyntaxShape::Int, - SyntaxShape::Number, SyntaxShape::String, ]; for shape in shapes.iter() { @@ -5054,7 +5109,10 @@ pub fn parse_value( ) } } - _ => (garbage(span), Some(ParseError::IncompleteParser(span))), + x => ( + garbage(span), + Some(ParseError::Expected(x.to_type().to_string(), span)), + ), } } diff --git a/crates/nu-parser/tests/test_parser.rs b/crates/nu-parser/tests/test_parser.rs index 800a9faeb..d1a83eecc 100644 --- a/crates/nu-parser/tests/test_parser.rs +++ b/crates/nu-parser/tests/test_parser.rs @@ -194,7 +194,7 @@ pub fn multi_test_parse_int() { ), Test( "semver data not confused for int", - b"1.0.1", + b"'1.0.1'", Expr::String("1.0.1".into()), None, ), diff --git a/crates/nu-utils/standard_library/test_asserts.nu b/crates/nu-utils/standard_library/test_asserts.nu index ddb21049f..43f716685 100644 --- a/crates/nu-utils/standard_library/test_asserts.nu +++ b/crates/nu-utils/standard_library/test_asserts.nu @@ -11,13 +11,13 @@ export def test_assert_equal [] { assert equal (1 + 2) 3 assert equal (0.1 + 0.2 | into string | into decimal) 0.3 # 0.30000000000000004 == 0.3 assert error { assert equal 1 "foo" } - assert error { assert equal (1 + 2) 4) } + assert error { assert equal (1 + 2) "4)" } } export def test_assert_not_equal [] { assert not equal (1 + 2) 4 assert not equal 1 "foo" - assert not equal (1 + 2) 3) + assert not equal (1 + 2) "3)" assert error { assert not equal 1 1 } }