2021-09-20 21:37:26 +00:00
use miette ::Diagnostic ;
2021-10-01 05:11:49 +00:00
use serde ::{ Deserialize , Serialize } ;
2021-09-20 21:37:26 +00:00
use thiserror ::Error ;
New commands: `break`, `continue`, `return`, and `loop` (#7230)
# Description
This adds `break`, `continue`, `return`, and `loop`.
* `break` - breaks out a loop
* `continue` - continues a loop at the next iteration
* `return` - early return from a function call
* `loop` - loop forever (until the loop hits a break)
Examples:
```
for i in 1..10 {
if $i == 5 {
continue
}
print $i
}
```
```
for i in 1..10 {
if $i == 5 {
break
}
print $i
}
```
```
def foo [x] {
if true {
return 2
}
$x
}
foo 100
```
```
loop { print "hello, forever" }
```
```
[1, 2, 3, 4, 5] | each {|x|
if $x > 3 { break }
$x
}
```
# User-Facing Changes
Adds the above commands.
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-11-24 20:39:16 +00:00
use crate ::{ ast ::Operator , Span , Type , Value } ;
2021-09-02 01:29:43 +00:00
2021-11-03 00:26:09 +00:00
/// The fundamental error type for the evaluation engine. These cases represent different kinds of errors
/// the evaluator might face, along with helpful spans to label. An error renderer will take this error value
/// and pass it into an error viewer to display to the user.
2021-10-01 05:11:49 +00:00
#[ derive(Debug, Clone, Error, Diagnostic, Serialize, Deserialize) ]
2021-09-02 01:29:43 +00:00
pub enum ShellError {
2022-04-14 05:08:46 +00:00
/// An operator received two arguments of incompatible types.
///
/// ## Resolution
///
/// Check each argument's type and convert one or both as needed.
2021-09-20 21:37:26 +00:00
#[ error( " Type mismatch during operation. " ) ]
#[ diagnostic(code(nu::shell::type_mismatch), url(docsrs)) ]
2021-09-02 01:29:43 +00:00
OperatorMismatch {
2021-09-20 21:37:26 +00:00
#[ label = " type mismatch for operator " ]
2021-09-02 01:29:43 +00:00
op_span : Span ,
lhs_ty : Type ,
2021-09-20 21:37:26 +00:00
#[ label( " {lhs_ty} " ) ]
2021-09-02 01:29:43 +00:00
lhs_span : Span ,
rhs_ty : Type ,
2021-09-20 21:37:26 +00:00
#[ label( " {rhs_ty} " ) ]
2021-09-02 01:29:43 +00:00
rhs_span : Span ,
} ,
2021-09-20 21:37:26 +00:00
2022-04-14 05:08:46 +00:00
/// An arithmetic operation's resulting value overflowed its possible size.
///
/// ## Resolution
///
/// Check the inputs to the operation and add guards for their sizes.
/// Integers are generally of size i64, floats are generally f64.
2021-10-20 05:58:25 +00:00
#[ error( " Operator overflow. " ) ]
2022-11-29 21:30:02 +00:00
#[ diagnostic(code(nu::shell::operator_overflow), url(docsrs), help( " {2} " )) ]
OperatorOverflow ( String , #[ label = " {0} " ] Span , String ) ,
2021-10-20 05:58:25 +00:00
2022-04-14 05:08:46 +00:00
/// The pipelined input into a command was not of the expected type. For example, it might
/// expect a string input, but received a table instead.
///
/// ## Resolution
///
/// Check the relevant pipeline and extract or convert values as needed.
2021-10-09 01:02:01 +00:00
#[ error( " Pipeline mismatch. " ) ]
#[ diagnostic(code(nu::shell::pipeline_mismatch), url(docsrs)) ]
2021-12-02 23:11:25 +00:00
PipelineMismatch (
String ,
#[ label( " expected: {0} " ) ] Span ,
#[ label( " value originates from here " ) ] Span ,
) ,
2023-01-01 05:56:59 +00:00
#[ error( " Input type not supported. " ) ]
last, skip, drop, take until, take while, skip until, skip while, where, reverse, shuffle, append, prepend and sort-by raise error when given non-lists (#7623)
Closes https://github.com/nushell/nushell/issues/6941
2022-12-31 11:35:12 +00:00
#[ diagnostic(code(nu::shell::only_supports_this_input_type), url(docsrs)) ]
Standardise the use of ShellError::UnsupportedInput and ShellError::TypeMismatch and add spans to every instance of the former (#7217)
# Description
* I was dismayed to discover recently that UnsupportedInput and
TypeMismatch are used *extremely* inconsistently across the codebase.
UnsupportedInput is sometimes used for input type-checks (as per the
name!!), but *also* used for argument type-checks. TypeMismatch is also
used for both.
I thus devised the following standard: input type-checking *only* uses
UnsupportedInput, and argument type-checking *only* uses TypeMismatch.
Moreover, to differentiate them, UnsupportedInput now has *two* error
arrows (spans), one pointing at the command and the other at the input
origin, while TypeMismatch only has the one (because the command should
always be nearby)
* In order to apply that standard, a very large number of
UnsupportedInput uses were changed so that the input's span could be
retrieved and delivered to it.
* Additionally, I noticed many places where **errors are not propagated
correctly**: there are lots of `match` sites which take a Value::Error,
then throw it away and replace it with a new Value::Error with
less/misleading information (such as reporting the error as an
"incorrect type"). I believe that the earliest errors are the most
important, and should always be propagated where possible.
* Also, to standardise one broad subset of UnsupportedInput error
messages, who all used slightly different wordings of "expected
`<type>`, got `<type>`", I created OnlySupportsThisInputType as a
variant of it.
* Finally, a bunch of error sites that had "repeated spans" - i.e. where
an error expected two spans, but `call.head` was given for both - were
fixed to use different spans.
# Example
BEFORE
```
〉20b | str starts-with 'a'
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #31:1:1]
1 │ 20b | str starts-with 'a'
· ┬
· ╰── Input's type is filesize. This command only works with strings.
╰────
〉'a' | math cos
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #33:1:1]
1 │ 'a' | math cos
· ─┬─
· ╰── Only numerical values are supported, input type: String
╰────
〉0x[12] | encode utf8
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #38:1:1]
1 │ 0x[12] | encode utf8
· ───┬──
· ╰── non-string input
╰────
```
AFTER
```
〉20b | str starts-with 'a'
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #1:1:1]
1 │ 20b | str starts-with 'a'
· ┬ ───────┬───────
· │ ╰── only string input data is supported
· ╰── input type: filesize
╰────
〉'a' | math cos
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #2:1:1]
1 │ 'a' | math cos
· ─┬─ ────┬───
· │ ╰── only numeric input data is supported
· ╰── input type: string
╰────
〉0x[12] | encode utf8
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #3:1:1]
1 │ 0x[12] | encode utf8
· ───┬── ───┬──
· │ ╰── only string input data is supported
· ╰── input type: binary
╰────
```
# User-Facing Changes
Various error messages suddenly make more sense (i.e. have two arrows
instead of one).
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-12-23 06:48:53 +00:00
OnlySupportsThisInputType (
String ,
String ,
#[ label( " only {0} input data is supported " ) ] Span ,
#[ label( " input type: {1} " ) ] Span ,
) ,
/// No input value was piped into the command.
///
/// ## Resolution
///
/// Only use this command to process values from a previous expression.
#[ error( " Pipeline empty. " ) ]
#[ diagnostic(code(nu::shell::pipeline_mismatch), url(docsrs)) ]
PipelineEmpty ( #[ label( " no input value was piped in " ) ] Span ) ,
2022-04-14 05:08:46 +00:00
/// A command received an argument of the wrong type.
///
/// ## Resolution
///
/// Convert the argument type before passing it in, or change the command to accept the type.
Standardise the use of ShellError::UnsupportedInput and ShellError::TypeMismatch and add spans to every instance of the former (#7217)
# Description
* I was dismayed to discover recently that UnsupportedInput and
TypeMismatch are used *extremely* inconsistently across the codebase.
UnsupportedInput is sometimes used for input type-checks (as per the
name!!), but *also* used for argument type-checks. TypeMismatch is also
used for both.
I thus devised the following standard: input type-checking *only* uses
UnsupportedInput, and argument type-checking *only* uses TypeMismatch.
Moreover, to differentiate them, UnsupportedInput now has *two* error
arrows (spans), one pointing at the command and the other at the input
origin, while TypeMismatch only has the one (because the command should
always be nearby)
* In order to apply that standard, a very large number of
UnsupportedInput uses were changed so that the input's span could be
retrieved and delivered to it.
* Additionally, I noticed many places where **errors are not propagated
correctly**: there are lots of `match` sites which take a Value::Error,
then throw it away and replace it with a new Value::Error with
less/misleading information (such as reporting the error as an
"incorrect type"). I believe that the earliest errors are the most
important, and should always be propagated where possible.
* Also, to standardise one broad subset of UnsupportedInput error
messages, who all used slightly different wordings of "expected
`<type>`, got `<type>`", I created OnlySupportsThisInputType as a
variant of it.
* Finally, a bunch of error sites that had "repeated spans" - i.e. where
an error expected two spans, but `call.head` was given for both - were
fixed to use different spans.
# Example
BEFORE
```
〉20b | str starts-with 'a'
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #31:1:1]
1 │ 20b | str starts-with 'a'
· ┬
· ╰── Input's type is filesize. This command only works with strings.
╰────
〉'a' | math cos
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #33:1:1]
1 │ 'a' | math cos
· ─┬─
· ╰── Only numerical values are supported, input type: String
╰────
〉0x[12] | encode utf8
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #38:1:1]
1 │ 0x[12] | encode utf8
· ───┬──
· ╰── non-string input
╰────
```
AFTER
```
〉20b | str starts-with 'a'
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #1:1:1]
1 │ 20b | str starts-with 'a'
· ┬ ───────┬───────
· │ ╰── only string input data is supported
· ╰── input type: filesize
╰────
〉'a' | math cos
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #2:1:1]
1 │ 'a' | math cos
· ─┬─ ────┬───
· │ ╰── only numeric input data is supported
· ╰── input type: string
╰────
〉0x[12] | encode utf8
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #3:1:1]
1 │ 0x[12] | encode utf8
· ───┬── ───┬──
· │ ╰── only string input data is supported
· ╰── input type: binary
╰────
```
# User-Facing Changes
Various error messages suddenly make more sense (i.e. have two arrows
instead of one).
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-12-23 06:48:53 +00:00
#[ error( " Type mismatch. " ) ]
2021-12-02 23:11:25 +00:00
#[ diagnostic(code(nu::shell::type_mismatch), url(docsrs)) ]
Standardise the use of ShellError::UnsupportedInput and ShellError::TypeMismatch and add spans to every instance of the former (#7217)
# Description
* I was dismayed to discover recently that UnsupportedInput and
TypeMismatch are used *extremely* inconsistently across the codebase.
UnsupportedInput is sometimes used for input type-checks (as per the
name!!), but *also* used for argument type-checks. TypeMismatch is also
used for both.
I thus devised the following standard: input type-checking *only* uses
UnsupportedInput, and argument type-checking *only* uses TypeMismatch.
Moreover, to differentiate them, UnsupportedInput now has *two* error
arrows (spans), one pointing at the command and the other at the input
origin, while TypeMismatch only has the one (because the command should
always be nearby)
* In order to apply that standard, a very large number of
UnsupportedInput uses were changed so that the input's span could be
retrieved and delivered to it.
* Additionally, I noticed many places where **errors are not propagated
correctly**: there are lots of `match` sites which take a Value::Error,
then throw it away and replace it with a new Value::Error with
less/misleading information (such as reporting the error as an
"incorrect type"). I believe that the earliest errors are the most
important, and should always be propagated where possible.
* Also, to standardise one broad subset of UnsupportedInput error
messages, who all used slightly different wordings of "expected
`<type>`, got `<type>`", I created OnlySupportsThisInputType as a
variant of it.
* Finally, a bunch of error sites that had "repeated spans" - i.e. where
an error expected two spans, but `call.head` was given for both - were
fixed to use different spans.
# Example
BEFORE
```
〉20b | str starts-with 'a'
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #31:1:1]
1 │ 20b | str starts-with 'a'
· ┬
· ╰── Input's type is filesize. This command only works with strings.
╰────
〉'a' | math cos
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #33:1:1]
1 │ 'a' | math cos
· ─┬─
· ╰── Only numerical values are supported, input type: String
╰────
〉0x[12] | encode utf8
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #38:1:1]
1 │ 0x[12] | encode utf8
· ───┬──
· ╰── non-string input
╰────
```
AFTER
```
〉20b | str starts-with 'a'
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #1:1:1]
1 │ 20b | str starts-with 'a'
· ┬ ───────┬───────
· │ ╰── only string input data is supported
· ╰── input type: filesize
╰────
〉'a' | math cos
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #2:1:1]
1 │ 'a' | math cos
· ─┬─ ────┬───
· │ ╰── only numeric input data is supported
· ╰── input type: string
╰────
〉0x[12] | encode utf8
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #3:1:1]
1 │ 0x[12] | encode utf8
· ───┬── ───┬──
· │ ╰── only string input data is supported
· ╰── input type: binary
╰────
```
# User-Facing Changes
Various error messages suddenly make more sense (i.e. have two arrows
instead of one).
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-12-23 06:48:53 +00:00
TypeMismatch ( String , #[ label = " {0} " ] Span ) ,
2021-10-09 01:02:01 +00:00
2022-10-25 01:22:57 +00:00
/// A command received an argument of the wrong type.
///
/// ## Resolution
///
/// Convert the argument type before passing it in, or change the command to accept the type.
Standardise the use of ShellError::UnsupportedInput and ShellError::TypeMismatch and add spans to every instance of the former (#7217)
# Description
* I was dismayed to discover recently that UnsupportedInput and
TypeMismatch are used *extremely* inconsistently across the codebase.
UnsupportedInput is sometimes used for input type-checks (as per the
name!!), but *also* used for argument type-checks. TypeMismatch is also
used for both.
I thus devised the following standard: input type-checking *only* uses
UnsupportedInput, and argument type-checking *only* uses TypeMismatch.
Moreover, to differentiate them, UnsupportedInput now has *two* error
arrows (spans), one pointing at the command and the other at the input
origin, while TypeMismatch only has the one (because the command should
always be nearby)
* In order to apply that standard, a very large number of
UnsupportedInput uses were changed so that the input's span could be
retrieved and delivered to it.
* Additionally, I noticed many places where **errors are not propagated
correctly**: there are lots of `match` sites which take a Value::Error,
then throw it away and replace it with a new Value::Error with
less/misleading information (such as reporting the error as an
"incorrect type"). I believe that the earliest errors are the most
important, and should always be propagated where possible.
* Also, to standardise one broad subset of UnsupportedInput error
messages, who all used slightly different wordings of "expected
`<type>`, got `<type>`", I created OnlySupportsThisInputType as a
variant of it.
* Finally, a bunch of error sites that had "repeated spans" - i.e. where
an error expected two spans, but `call.head` was given for both - were
fixed to use different spans.
# Example
BEFORE
```
〉20b | str starts-with 'a'
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #31:1:1]
1 │ 20b | str starts-with 'a'
· ┬
· ╰── Input's type is filesize. This command only works with strings.
╰────
〉'a' | math cos
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #33:1:1]
1 │ 'a' | math cos
· ─┬─
· ╰── Only numerical values are supported, input type: String
╰────
〉0x[12] | encode utf8
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #38:1:1]
1 │ 0x[12] | encode utf8
· ───┬──
· ╰── non-string input
╰────
```
AFTER
```
〉20b | str starts-with 'a'
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #1:1:1]
1 │ 20b | str starts-with 'a'
· ┬ ───────┬───────
· │ ╰── only string input data is supported
· ╰── input type: filesize
╰────
〉'a' | math cos
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #2:1:1]
1 │ 'a' | math cos
· ─┬─ ────┬───
· │ ╰── only numeric input data is supported
· ╰── input type: string
╰────
〉0x[12] | encode utf8
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #3:1:1]
1 │ 0x[12] | encode utf8
· ───┬── ───┬──
· │ ╰── only string input data is supported
· ╰── input type: binary
╰────
```
# User-Facing Changes
Various error messages suddenly make more sense (i.e. have two arrows
instead of one).
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-12-23 06:48:53 +00:00
#[ error( " Type mismatch. " ) ]
2022-10-25 01:22:57 +00:00
#[ diagnostic(code(nu::shell::type_mismatch), url(docsrs)) ]
TypeMismatchGenericMessage {
err_message : String ,
#[ label = " {err_message} " ]
span : Span ,
} ,
2022-04-14 05:08:46 +00:00
/// This value cannot be used with this operator.
///
/// ## Resolution
///
/// Not all values, for example custom values, can be used with all operators. Either
/// implement support for the operator on this type, or convert the type to a supported one.
2021-09-20 21:37:26 +00:00
#[ error( " Unsupported operator: {0}. " ) ]
#[ diagnostic(code(nu::shell::unsupported_operator), url(docsrs)) ]
UnsupportedOperator ( Operator , #[ label = " unsupported operator " ] Span ) ,
2022-11-11 06:51:08 +00:00
/// This value cannot be used with this operator.
///
/// ## Resolution
///
/// Assignment requires that you assign to a variable or variable cell path.
#[ error( " Assignment operations require a variable. " ) ]
#[ diagnostic(code(nu::shell::assignment_requires_variable), url(docsrs)) ]
AssignmentRequiresVar ( #[ label = " needs to be a variable " ] Span ) ,
/// This value cannot be used with this operator.
///
/// ## Resolution
///
/// Assignment requires that you assign to a mutable variable or cell path.
#[ error( " Assignment to an immutable variable. " ) ]
#[ diagnostic(code(nu::shell::assignment_requires_mutable_variable), url(docsrs)) ]
AssignmentRequiresMutableVar ( #[ label = " needs to be a mutable variable " ] Span ) ,
2022-04-14 05:08:46 +00:00
/// An operator was not recognized during evaluation.
///
/// ## Resolution
///
/// Did you write the correct operator?
#[ error( " Unknown operator: {0}. " ) ]
2021-09-20 21:37:26 +00:00
#[ diagnostic(code(nu::shell::unknown_operator), url(docsrs)) ]
2022-04-14 05:08:46 +00:00
UnknownOperator ( String , #[ label = " unknown operator " ] Span ) ,
2021-09-20 21:37:26 +00:00
2022-04-14 05:08:46 +00:00
/// An expected command parameter is missing.
///
/// ## Resolution
///
/// Add the expected parameter and try again.
2021-10-07 22:20:23 +00:00
#[ error( " Missing parameter: {0}. " ) ]
#[ diagnostic(code(nu::shell::missing_parameter), url(docsrs)) ]
MissingParameter ( String , #[ label = " missing parameter: {0} " ] Span ) ,
2022-04-14 05:08:46 +00:00
/// Two parameters conflict with each other or are otherwise mutually exclusive.
///
/// ## Resolution
///
/// Remove one of the parameters/options and try again.
2021-10-10 04:13:15 +00:00
#[ error( " Incompatible parameters. " ) ]
#[ diagnostic(code(nu::shell::incompatible_parameters), url(docsrs)) ]
IncompatibleParameters {
left_message : String ,
2022-04-14 05:08:46 +00:00
// Be cautious, as flags can share the same span, resulting in a panic (ex: `rm -pt`)
2021-10-10 04:13:15 +00:00
#[ label( " {left_message} " ) ]
left_span : Span ,
right_message : String ,
#[ label( " {right_message} " ) ]
right_span : Span ,
} ,
2022-04-14 05:08:46 +00:00
/// There's some issue with number or matching of delimiters in an expression.
///
/// ## Resolution
///
/// Check your syntax for mismatched braces, RegExp syntax errors, etc, based on the specific error message.
2021-11-09 20:17:37 +00:00
#[ error( " Delimiter error " ) ]
#[ diagnostic(code(nu::shell::delimiter_error), url(docsrs)) ]
DelimiterError ( String , #[ label( " {0} " ) ] Span ) ,
2022-04-14 05:08:46 +00:00
/// An operation received parameters with some sort of incompatibility
/// (for example, different number of rows in a table, incompatible column names, etc).
///
/// ## Resolution
///
/// Refer to the specific error message for details on what's incompatible and then fix your
/// inputs to make sure they match that way.
2021-10-10 04:13:15 +00:00
#[ error( " Incompatible parameters. " ) ]
#[ diagnostic(code(nu::shell::incompatible_parameters), url(docsrs)) ]
IncompatibleParametersSingle ( String , #[ label = " {0} " ] Span ) ,
2022-04-14 05:08:46 +00:00
/// This build of nushell implements this feature, but it has not been enabled.
///
/// ## Resolution
///
/// Rebuild nushell with the appropriate feature enabled.
2021-10-10 04:13:15 +00:00
#[ error( " Feature not enabled. " ) ]
#[ diagnostic(code(nu::shell::feature_not_enabled), url(docsrs)) ]
FeatureNotEnabled ( #[ label = " feature not enabled " ] Span ) ,
2022-04-14 05:08:46 +00:00
/// You're trying to run an unsupported external command.
///
/// ## Resolution
///
/// Make sure there's an appropriate `run-external` declaration for this external command.
2022-02-20 21:26:41 +00:00
#[ error( " Running external commands not supported " ) ]
2021-09-20 21:37:26 +00:00
#[ diagnostic(code(nu::shell::external_commands), url(docsrs)) ]
ExternalNotSupported ( #[ label = " external not supported " ] Span ) ,
2022-04-14 05:08:46 +00:00
/// The given probability input is invalid. The probability must be between 0 and 1.
///
/// ## Resolution
///
/// Make sure the probability is between 0 and 1 and try again.
2021-11-30 06:12:19 +00:00
#[ error( " Invalid Probability. " ) ]
#[ diagnostic(code(nu::shell::invalid_probability), url(docsrs)) ]
InvalidProbability ( #[ label = " invalid probability " ] Span ) ,
2022-04-14 05:08:46 +00:00
/// The first value in a `..` range must be compatible with the second one.
///
/// ## Resolution
///
/// Check to make sure both values are compatible, and that the values are enumerable in Nushell.
2021-12-02 17:26:12 +00:00
#[ error( " Invalid range {0}..{1} " ) ]
#[ diagnostic(code(nu::shell::invalid_range), url(docsrs)) ]
InvalidRange ( String , String , #[ label = " expected a valid range " ] Span ) ,
2022-04-14 05:08:46 +00:00
/// Catastrophic nushell failure. This reflects a completely unexpected or unrecoverable error.
///
/// ## Resolution
///
/// It is very likely that this is a bug. Please file an issue at https://github.com/nushell/nushell/issues with relevant information.
2021-12-02 23:11:25 +00:00
#[ error( " Nushell failed: {0}. " ) ]
#[ diagnostic(code(nu::shell::nushell_failed), url(docsrs)) ]
2022-05-07 19:39:22 +00:00
// Only use this one if Nushell completely falls over and hits a state that isn't possible or isn't recoverable
2021-12-02 23:11:25 +00:00
NushellFailed ( String ) ,
2021-09-20 21:37:26 +00:00
2022-04-14 05:08:46 +00:00
/// Catastrophic nushell failure. This reflects a completely unexpected or unrecoverable error.
///
/// ## Resolution
///
/// It is very likely that this is a bug. Please file an issue at https://github.com/nushell/nushell/issues with relevant information.
2022-01-24 19:43:38 +00:00
#[ error( " Nushell failed: {0}. " ) ]
2022-05-07 19:39:22 +00:00
#[ diagnostic(code(nu::shell::nushell_failed_spanned), url(docsrs)) ]
// Only use this one if Nushell completely falls over and hits a state that isn't possible or isn't recoverable
2022-01-24 19:43:38 +00:00
NushellFailedSpanned ( String , String , #[ label = " {1} " ] Span ) ,
2022-05-07 19:39:22 +00:00
/// Catastrophic nushell failure. This reflects a completely unexpected or unrecoverable error.
///
/// ## Resolution
///
/// It is very likely that this is a bug. Please file an issue at https://github.com/nushell/nushell/issues with relevant information.
#[ error( " Nushell failed: {0}. " ) ]
#[ diagnostic(code(nu::shell::nushell_failed_help), url(docsrs)) ]
// Only use this one if Nushell completely falls over and hits a state that isn't possible or isn't recoverable
NushellFailedHelp ( String , #[ help ] String ) ,
/// Catastrophic nushell failure. This reflects a completely unexpected or unrecoverable error.
///
/// ## Resolution
///
/// It is very likely that this is a bug. Please file an issue at https://github.com/nushell/nushell/issues with relevant information.
#[ error( " Nushell failed: {0}. " ) ]
#[ diagnostic(code(nu::shell::nushell_failed_spanned_help), url(docsrs)) ]
// Only use this one if Nushell completely falls over and hits a state that isn't possible or isn't recoverable
NushellFailedSpannedHelp ( String , String , #[ label = " {1} " ] Span , #[ help ] String ) ,
2022-04-14 05:08:46 +00:00
/// A referenced variable was not found at runtime.
///
/// ## Resolution
///
/// Check the variable name. Did you typo it? Did you forget to declare it? Is the casing right?
2021-12-15 22:56:12 +00:00
#[ error( " Variable not found " ) ]
2021-09-20 21:37:26 +00:00
#[ diagnostic(code(nu::shell::variable_not_found), url(docsrs)) ]
VariableNotFoundAtRuntime ( #[ label = " variable not found " ] Span ) ,
2022-04-14 05:08:46 +00:00
/// A referenced environment variable was not found at runtime.
///
/// ## Resolution
///
/// Check the environment variable name. Did you typo it? Did you forget to declare it? Is the casing right?
2022-01-10 01:39:25 +00:00
#[ error( " Environment variable '{0}' not found " ) ]
2022-01-04 22:30:34 +00:00
#[ diagnostic(code(nu::shell::env_variable_not_found), url(docsrs)) ]
2022-01-10 01:39:25 +00:00
EnvVarNotFoundAtRuntime ( String , #[ label = " environment variable not found " ] Span ) ,
2021-11-15 23:16:06 +00:00
2022-05-07 19:39:22 +00:00
/// A referenced module was not found at runtime.
///
/// ## Resolution
///
/// Check the module name. Did you typo it? Did you forget to declare it? Is the casing right?
#[ error( " Module '{0}' not found " ) ]
#[ diagnostic(code(nu::shell::module_not_found), url(docsrs)) ]
ModuleNotFoundAtRuntime ( String , #[ label = " module not found " ] Span ) ,
/// A referenced module or overlay was not found at runtime.
///
/// ## Resolution
///
/// Check the module name. Did you typo it? Did you forget to declare it? Is the casing right?
#[ error( " Module or overlay'{0}' not found " ) ]
2022-05-24 21:22:17 +00:00
#[ diagnostic(code(nu::shell::module_or_overlay_not_found), url(docsrs)) ]
2022-05-07 19:39:22 +00:00
ModuleOrOverlayNotFoundAtRuntime ( String , #[ label = " not a module or overlay " ] Span ) ,
/// A referenced overlay was not found at runtime.
///
/// ## Resolution
///
/// Check the overlay name. Did you typo it? Did you forget to declare it? Is the casing right?
#[ error( " Overlay '{0}' not found " ) ]
#[ diagnostic(code(nu::shell::overlay_not_found), url(docsrs)) ]
OverlayNotFoundAtRuntime ( String , #[ label = " overlay not found " ] Span ) ,
2022-04-14 05:08:46 +00:00
/// The given item was not found. This is a fairly generic error that depends on context.
///
/// ## Resolution
///
/// This error is triggered in various places, and simply signals that "something" was not found. Refer to the specific error message for further details.
2021-11-15 23:16:06 +00:00
#[ error( " Not found. " ) ]
#[ diagnostic(code(nu::parser::not_found), url(docsrs)) ]
NotFound ( #[ label = " did not find anything under this name " ] Span ) ,
2022-04-14 05:08:46 +00:00
/// Failed to convert a value of one type into a different type.
///
/// ## Resolution
///
/// Not all values can be coerced this way. Check the supported type(s) and try again.
2021-09-20 21:37:26 +00:00
#[ error( " Can't convert to {0}. " ) ]
#[ diagnostic(code(nu::shell::cant_convert), url(docsrs)) ]
2022-04-18 12:34:10 +00:00
CantConvert (
2022-03-24 12:04:31 +00:00
String ,
String ,
#[ label( " can't convert {1} to {0} " ) ] Span ,
2022-04-18 12:34:10 +00:00
#[ help ] Option < String > ,
2022-03-24 12:04:31 +00:00
) ,
2022-07-07 10:54:38 +00:00
/// Failed to convert a value of one type into a different type. Includes hint for what the first value is.
///
/// ## Resolution
///
/// Not all values can be coerced this way. Check the supported type(s) and try again.
#[ error( " Can't convert {1} `{2}` to {0}. " ) ]
#[ diagnostic(code(nu::shell::cant_convert_with_value), url(docsrs)) ]
CantConvertWithValue (
String ,
String ,
String ,
#[ label( " can't be converted to {0} " ) ] Span ,
#[ label( " this {1} value... " ) ] Span ,
#[ help ] Option < String > ,
) ,
2022-04-14 05:08:46 +00:00
/// An environment variable cannot be represented as a string.
///
/// ## Resolution
///
/// Not all types can be converted to environment variable values, which must be strings. Check the input type and try again.
2022-03-11 22:18:39 +00:00
#[ error( " {0} is not representable as a string. " ) ]
#[ diagnostic(
code ( nu ::shell ::env_var_not_a_string ) ,
url ( docsrs ) ,
help (
r #" The '{0}' environment variable must be a string or be convertible to a string.
Either make sure { 0 } is a string , or add a ' to_string ' entry for it in ENV_CONVERSIONS . " #
)
) ]
EnvVarNotAString ( String , #[ label( " value not representable as a string " ) ] Span ) ,
2022-08-31 20:32:56 +00:00
/// This environment variable cannot be set manually.
///
/// ## Resolution
///
/// This environment variable is set automatically by Nushell and cannot not be set manually.
#[ error( " {0} cannot be set manually. " ) ]
#[ diagnostic(
code ( nu ::shell ::automatic_env_var_set_manually ) ,
url ( docsrs ) ,
help (
r # "The environment variable '{0}' is set automatically by Nushell and cannot not be set manually."#
)
) ]
AutomaticEnvVarSetManually ( String , #[ label( " cannot set '{0}' manually " ) ] Span ) ,
2023-01-28 19:17:32 +00:00
/// It is not possible to replace the entire environment at once
///
/// ## Resolution
///
/// Setting the entire environment is not allowed. Change environment variables individually
/// instead.
#[ error( " Cannot replace environment. " ) ]
#[ diagnostic(
code ( nu ::shell ::cannot_replace_env ) ,
url ( docsrs ) ,
help ( r # "Assigning a value to $env is not allowed."# )
) ]
CannotReplaceEnv ( #[ label( " setting $env not allowed " ) ] Span ) ,
2022-04-14 05:08:46 +00:00
/// Division by zero is not a thing.
///
/// ## Resolution
///
/// Add a guard of some sort to check whether a denominator input to this division is zero, and branch off if that's the case.
2021-09-20 21:37:26 +00:00
#[ error( " Division by zero. " ) ]
#[ diagnostic(code(nu::shell::division_by_zero), url(docsrs)) ]
DivisionByZero ( #[ label( " division by zero " ) ] Span ) ,
2022-04-14 05:08:46 +00:00
/// An error happened while tryin to create a range.
///
/// This can happen in various unexpected situations, for example if the range would loop forever (as would be the case with a 0-increment).
///
/// ## Resolution
///
/// Check your range values to make sure they're countable and would not loop forever.
2021-09-20 21:37:26 +00:00
#[ error( " Can't convert range to countable values " ) ]
#[ diagnostic(code(nu::shell::range_to_countable), url(docsrs)) ]
CannotCreateRange ( #[ label = " can't convert to countable values " ] Span ) ,
2022-04-14 05:08:46 +00:00
/// You attempted to access an index beyond the available length of a value.
///
/// ## Resolution
///
/// Check your lengths and try again.
2021-09-20 21:37:26 +00:00
#[ error( " Row number too large (max: {0}). " ) ]
#[ diagnostic(code(nu::shell::access_beyond_end), url(docsrs)) ]
2022-03-18 21:12:54 +00:00
AccessBeyondEnd ( usize , #[ label = " index too large (max: {0}) " ] Span ) ,
2021-09-20 21:37:26 +00:00
2022-12-06 17:51:55 +00:00
/// You attempted to insert data at a list position higher than the end.
///
/// ## Resolution
///
/// To insert data into a list, assign to the last used index + 1.
#[ error( " Inserted at wrong row number (should be {0}). " ) ]
#[ diagnostic(code(nu::shell::access_beyond_end), url(docsrs)) ]
InsertAfterNextFreeIndex (
usize ,
#[ label = " can't insert at index (the next available index is {0}) " ] Span ,
) ,
2022-10-29 17:47:50 +00:00
/// You attempted to access an index when it's empty.
///
/// ## Resolution
///
/// Check your lengths and try again.
#[ error( " Row number too large (empty content). " ) ]
#[ diagnostic(code(nu::shell::access_beyond_end), url(docsrs)) ]
AccessEmptyContent ( #[ label = " index too large (empty content) " ] Span ) ,
2022-04-14 05:08:46 +00:00
/// You attempted to access an index beyond the available length of a stream.
///
/// ## Resolution
///
/// Check your lengths and try again.
2021-09-20 21:37:26 +00:00
#[ error( " Row number too large. " ) ]
#[ diagnostic(code(nu::shell::access_beyond_end_of_stream), url(docsrs)) ]
2022-03-18 21:12:54 +00:00
AccessBeyondEndOfStream ( #[ label = " index too large " ] Span ) ,
2021-09-20 21:37:26 +00:00
2022-04-14 05:08:46 +00:00
/// Tried to index into a type that does not support pathed access.
///
/// ## Resolution
///
/// Check your types. Only composite types can be pathed into.
2021-09-20 21:37:26 +00:00
#[ error( " Data cannot be accessed with a cell path " ) ]
#[ diagnostic(code(nu::shell::incompatible_path_access), url(docsrs)) ]
IncompatiblePathAccess ( String , #[ label( " {0} doesn't support cell paths " ) ] Span ) ,
2022-04-14 05:08:46 +00:00
/// The requested column does not exist.
///
/// ## Resolution
///
/// Check the spelling of your column name. Did you forget to rename a column somewhere?
2021-09-20 21:37:26 +00:00
#[ error( " Cannot find column " ) ]
#[ diagnostic(code(nu::shell::column_not_found), url(docsrs)) ]
2021-10-11 19:51:54 +00:00
CantFindColumn (
2022-11-19 17:35:55 +00:00
String ,
#[ label = " cannot find column '{0}' " ] Span ,
2021-10-11 19:51:54 +00:00
#[ label = " value originates here " ] Span ,
) ,
2021-09-20 21:37:26 +00:00
2022-04-14 05:08:46 +00:00
/// Attempted to insert a column into a table, but a column with that name already exists.
///
/// ## Resolution
///
/// Drop or rename the existing column (check `rename -h`) and try again.
2022-03-17 17:55:02 +00:00
#[ error( " Column already exists " ) ]
#[ diagnostic(code(nu::shell::column_already_exists), url(docsrs)) ]
ColumnAlreadyExists (
2022-11-19 17:35:55 +00:00
String ,
#[ label = " column '{0}' already exists " ] Span ,
2022-03-17 17:55:02 +00:00
#[ label = " value originates here " ] Span ,
) ,
2022-04-14 05:08:46 +00:00
/// The given operation can only be performed on lists.
///
/// ## Resolution
///
/// Check the input type to this command. Are you sure it's a list?
2021-11-05 03:59:12 +00:00
#[ error( " Not a list value " ) ]
#[ diagnostic(code(nu::shell::not_a_list), url(docsrs)) ]
NotAList (
#[ label = " value not a list " ] Span ,
#[ label = " value originates here " ] Span ,
) ,
2022-04-14 05:08:46 +00:00
/// An error happened while performing an external command.
///
/// ## Resolution
///
/// This error is fairly generic. Refer to the specific error message for further details.
2022-08-12 17:34:10 +00:00
#[ error( " External command failed " ) ]
2022-01-22 14:12:34 +00:00
#[ diagnostic(code(nu::shell::external_command), url(docsrs), help( " {1} " )) ]
ExternalCommand ( String , String , #[ label( " {0} " ) ] Span ) ,
2021-09-24 12:03:39 +00:00
2022-04-14 05:08:46 +00:00
/// An operation was attempted with an input unsupported for some reason.
///
/// ## Resolution
///
/// This error is fairly generic. Refer to the specific error message for further details.
2021-09-24 12:03:39 +00:00
#[ error( " Unsupported input " ) ]
#[ diagnostic(code(nu::shell::unsupported_input), url(docsrs)) ]
Standardise the use of ShellError::UnsupportedInput and ShellError::TypeMismatch and add spans to every instance of the former (#7217)
# Description
* I was dismayed to discover recently that UnsupportedInput and
TypeMismatch are used *extremely* inconsistently across the codebase.
UnsupportedInput is sometimes used for input type-checks (as per the
name!!), but *also* used for argument type-checks. TypeMismatch is also
used for both.
I thus devised the following standard: input type-checking *only* uses
UnsupportedInput, and argument type-checking *only* uses TypeMismatch.
Moreover, to differentiate them, UnsupportedInput now has *two* error
arrows (spans), one pointing at the command and the other at the input
origin, while TypeMismatch only has the one (because the command should
always be nearby)
* In order to apply that standard, a very large number of
UnsupportedInput uses were changed so that the input's span could be
retrieved and delivered to it.
* Additionally, I noticed many places where **errors are not propagated
correctly**: there are lots of `match` sites which take a Value::Error,
then throw it away and replace it with a new Value::Error with
less/misleading information (such as reporting the error as an
"incorrect type"). I believe that the earliest errors are the most
important, and should always be propagated where possible.
* Also, to standardise one broad subset of UnsupportedInput error
messages, who all used slightly different wordings of "expected
`<type>`, got `<type>`", I created OnlySupportsThisInputType as a
variant of it.
* Finally, a bunch of error sites that had "repeated spans" - i.e. where
an error expected two spans, but `call.head` was given for both - were
fixed to use different spans.
# Example
BEFORE
```
〉20b | str starts-with 'a'
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #31:1:1]
1 │ 20b | str starts-with 'a'
· ┬
· ╰── Input's type is filesize. This command only works with strings.
╰────
〉'a' | math cos
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #33:1:1]
1 │ 'a' | math cos
· ─┬─
· ╰── Only numerical values are supported, input type: String
╰────
〉0x[12] | encode utf8
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #38:1:1]
1 │ 0x[12] | encode utf8
· ───┬──
· ╰── non-string input
╰────
```
AFTER
```
〉20b | str starts-with 'a'
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #1:1:1]
1 │ 20b | str starts-with 'a'
· ┬ ───────┬───────
· │ ╰── only string input data is supported
· ╰── input type: filesize
╰────
〉'a' | math cos
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #2:1:1]
1 │ 'a' | math cos
· ─┬─ ────┬───
· │ ╰── only numeric input data is supported
· ╰── input type: string
╰────
〉0x[12] | encode utf8
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #3:1:1]
1 │ 0x[12] | encode utf8
· ───┬── ───┬──
· │ ╰── only string input data is supported
· ╰── input type: binary
╰────
```
# User-Facing Changes
Various error messages suddenly make more sense (i.e. have two arrows
instead of one).
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-12-23 06:48:53 +00:00
UnsupportedInput (
String ,
String ,
#[ label( " {0} " ) ] Span , // call head (the name of the command itself)
#[ label( " input type: {1} " ) ] Span ,
) ,
2021-10-01 21:53:13 +00:00
2022-04-14 05:08:46 +00:00
/// Failed to parse an input into a datetime value.
///
/// ## Resolution
///
/// Make sure your datetime input format is correct.
///
/// For example, these are some valid formats:
///
/// * "5 pm"
/// * "2020/12/4"
/// * "2020.12.04 22:10 +2"
/// * "2020-04-12 22:10:57 +02:00"
/// * "2020-04-12T22:10:57.213231+02:00"
/// * "Tue, 1 Jul 2003 10:52:37 +0200""#
2022-02-28 01:21:46 +00:00
#[ error( " Unable to parse datetime " ) ]
#[ diagnostic(
code ( nu ::shell ::datetime_parse_error ) ,
url ( docsrs ) ,
help (
r #" Examples of supported inputs:
* " 5 pm "
* " 2020/12/4 "
* " 2020.12.04 22:10 +2 "
* " 2020-04-12 22:10:57 +02:00 "
* " 2020-04-12T22:10:57.213231+02:00 "
* " Tue, 1 Jul 2003 10:52:37 +0200 " " #
)
) ]
DatetimeParseError ( #[ label( " datetime parsing failed " ) ] Span ) ,
2022-04-14 05:08:46 +00:00
/// A network operation failed.
///
/// ## Resolution
///
/// It's always DNS.
2022-01-04 02:01:18 +00:00
#[ error( " Network failure " ) ]
#[ diagnostic(code(nu::shell::network_failure), url(docsrs)) ]
NetworkFailure ( String , #[ label( " {0} " ) ] Span ) ,
2022-04-14 05:08:46 +00:00
/// Help text for this command could not be found.
///
/// ## Resolution
///
/// Check the spelling for the requested command and try again. Are you sure it's defined and your configurations are loading correctly? Can you execute it?
2021-10-09 01:02:01 +00:00
#[ error( " Command not found " ) ]
#[ diagnostic(code(nu::shell::command_not_found), url(docsrs)) ]
CommandNotFound ( #[ label( " command not found " ) ] Span ) ,
2022-12-30 15:44:37 +00:00
/// This alias could not be found
///
/// ## Resolution
///
/// The alias does not exist in the current scope. It might exist in another scope or overlay or be hidden.
#[ error( " Alias not found " ) ]
#[ diagnostic(code(nu::shell::alias_not_found), url(docsrs)) ]
AliasNotFound ( #[ label( " alias not found " ) ] Span ) ,
2022-04-14 05:08:46 +00:00
/// A flag was not found.
2021-10-01 21:53:13 +00:00
#[ error( " Flag not found " ) ]
#[ diagnostic(code(nu::shell::flag_not_found), url(docsrs)) ]
2022-04-14 05:08:46 +00:00
// NOTE: Seems to be unused. Removable?
2021-10-01 21:53:13 +00:00
FlagNotFound ( String , #[ label( " {0} not found " ) ] Span ) ,
2021-10-05 03:43:07 +00:00
2022-04-14 05:08:46 +00:00
/// Failed to find a file during a nushell operation.
///
/// ## Resolution
///
/// Does the file in the error message exist? Is it readable and accessible? Is the casing right?
2021-10-05 03:43:07 +00:00
#[ error( " File not found " ) ]
#[ diagnostic(code(nu::shell::file_not_found), url(docsrs)) ]
FileNotFound ( #[ label( " file not found " ) ] Span ) ,
2022-04-14 05:08:46 +00:00
/// Failed to find a file during a nushell operation.
///
/// ## Resolution
///
/// Does the file in the error message exist? Is it readable and accessible? Is the casing right?
2021-10-05 21:08:39 +00:00
#[ error( " File not found " ) ]
#[ diagnostic(code(nu::shell::file_not_found), url(docsrs)) ]
FileNotFoundCustom ( String , #[ label( " {0} " ) ] Span ) ,
2022-04-14 05:08:46 +00:00
/// A plugin failed to load.
///
/// ## Resolution
///
2022-08-24 04:32:41 +00:00
/// This is a fairly generic error. Refer to the specific error message for further details.
2021-12-18 15:52:27 +00:00
#[ error( " Plugin failed to load: {0} " ) ]
2021-12-05 03:11:19 +00:00
#[ diagnostic(code(nu::shell::plugin_failed_to_load), url(docsrs)) ]
2021-12-02 23:11:25 +00:00
PluginFailedToLoad ( String ) ,
2022-04-14 05:08:46 +00:00
/// A message from a plugin failed to encode.
///
/// ## Resolution
///
/// This is likely a bug with the plugin itself.
2021-12-18 15:52:27 +00:00
#[ error( " Plugin failed to encode: {0} " ) ]
2021-12-05 03:11:19 +00:00
#[ diagnostic(code(nu::shell::plugin_failed_to_encode), url(docsrs)) ]
PluginFailedToEncode ( String ) ,
2022-04-14 05:08:46 +00:00
/// A message to a plugin failed to decode.
///
/// ## Resolution
///
/// This is either an issue with the inputs to a plugin (bad JSON?) or a bug in the plugin itself. Fix or report as appropriate.
2021-12-18 15:52:27 +00:00
#[ error( " Plugin failed to decode: {0} " ) ]
2021-12-05 03:11:19 +00:00
#[ diagnostic(code(nu::shell::plugin_failed_to_decode), url(docsrs)) ]
PluginFailedToDecode ( String ) ,
2022-08-24 04:32:41 +00:00
/// I/O operation interrupted.
///
/// ## Resolution
///
/// This is a generic error. Refer to the specific error message for further details.
#[ error( " I/O interrupted " ) ]
#[ diagnostic(code(nu::shell::io_interrupted), url(docsrs)) ]
IOInterrupted ( String , #[ label( " {0} " ) ] Span ) ,
2022-04-14 05:08:46 +00:00
/// An I/O operation failed.
///
/// ## Resolution
///
/// This is a generic error. Refer to the specific error message for further details.
2021-12-02 23:11:25 +00:00
#[ error( " I/O error " ) ]
2022-01-04 22:30:34 +00:00
#[ diagnostic(code(nu::shell::io_error), url(docsrs), help( " {0} " )) ]
2021-12-02 23:11:25 +00:00
IOError ( String ) ,
2022-08-24 04:32:41 +00:00
/// An I/O operation failed.
///
/// ## Resolution
///
/// This is a generic error. Refer to the specific error message for further details.
#[ error( " I/O error " ) ]
#[ diagnostic(code(nu::shell::io_error), url(docsrs)) ]
IOErrorSpanned ( String , #[ label( " {0} " ) ] Span ) ,
/// Permission for an operation was denied.
///
/// ## Resolution
///
/// This is a generic error. Refer to the specific error message for further details.
#[ error( " Permission Denied " ) ]
#[ diagnostic(code(nu::shell::permission_denied), url(docsrs)) ]
PermissionDeniedError ( String , #[ label( " {0} " ) ] Span ) ,
/// Out of memory.
///
/// ## Resolution
///
/// This is a generic error. Refer to the specific error message for further details.
#[ error( " Out of memory " ) ]
#[ diagnostic(code(nu::shell::out_of_memory), url(docsrs)) ]
OutOfMemoryError ( String , #[ label( " {0} " ) ] Span ) ,
2022-04-14 05:08:46 +00:00
/// Tried to `cd` to a path that isn't a directory.
///
/// ## Resolution
///
/// Make sure the path is a directory. It currently exists, but is of some other type, like a file.
2022-01-23 13:02:12 +00:00
#[ error( " Cannot change to directory " ) ]
#[ diagnostic(code(nu::shell::cannot_cd_to_directory), url(docsrs)) ]
NotADirectory ( #[ label( " is not a directory " ) ] Span ) ,
2022-04-14 05:08:46 +00:00
/// Attempted to perform an operation on a directory that doesn't exist.
///
/// ## Resolution
///
/// Make sure the directory in the error message actually exists before trying again.
2021-10-05 03:43:07 +00:00
#[ error( " Directory not found " ) ]
#[ diagnostic(code(nu::shell::directory_not_found), url(docsrs)) ]
2022-04-18 12:34:10 +00:00
DirectoryNotFound ( #[ label( " directory not found " ) ] Span , #[ help ] Option < String > ) ,
2021-10-05 03:43:07 +00:00
2022-04-14 05:08:46 +00:00
/// Attempted to perform an operation on a directory that doesn't exist.
///
/// ## Resolution
///
/// Make sure the directory in the error message actually exists before trying again.
2022-01-05 22:21:26 +00:00
#[ error( " Directory not found " ) ]
#[ diagnostic(code(nu::shell::directory_not_found_custom), url(docsrs)) ]
2021-10-05 21:08:39 +00:00
DirectoryNotFoundCustom ( String , #[ label( " {0} " ) ] Span ) ,
2022-04-14 05:08:46 +00:00
/// The requested move operation cannot be completed. This is typically because both paths exist,
/// but are of different types. For example, you might be trying to overwrite an existing file with
/// a directory.
///
/// ## Resolution
///
/// Make sure the destination path does not exist before moving a directory.
2021-10-05 03:43:07 +00:00
#[ error( " Move not possible " ) ]
#[ diagnostic(code(nu::shell::move_not_possible), url(docsrs)) ]
MoveNotPossible {
source_message : String ,
#[ label( " {source_message} " ) ]
source_span : Span ,
destination_message : String ,
#[ label( " {destination_message} " ) ]
destination_span : Span ,
} ,
2021-10-05 19:54:30 +00:00
2022-04-14 05:08:46 +00:00
/// The requested move operation cannot be completed. This is typically because both paths exist,
/// but are of different types. For example, you might be trying to overwrite an existing file with
/// a directory.
///
/// ## Resolution
///
/// Make sure the destination path does not exist before moving a directory.
2021-10-05 19:54:30 +00:00
#[ error( " Move not possible " ) ]
#[ diagnostic(code(nu::shell::move_not_possible_single), url(docsrs)) ]
2022-04-14 05:08:46 +00:00
// NOTE: Currently not actively used.
2021-10-05 19:54:30 +00:00
MoveNotPossibleSingle ( String , #[ label( " {0} " ) ] Span ) ,
2021-10-07 21:18:03 +00:00
2022-04-14 05:08:46 +00:00
/// Failed to create either a file or directory.
///
/// ## Resolution
///
/// This is a fairly generic error. Refer to the specific error message for further details.
2021-10-07 21:18:03 +00:00
#[ error( " Create not possible " ) ]
2021-10-07 21:20:03 +00:00
#[ diagnostic(code(nu::shell::create_not_possible), url(docsrs)) ]
2021-10-07 21:18:03 +00:00
CreateNotPossible ( String , #[ label( " {0} " ) ] Span ) ,
2021-10-10 04:13:15 +00:00
2022-04-14 05:08:46 +00:00
/// Changing the access time ("atime") of this file is not possible.
///
/// ## Resolution
///
/// This can be for various reasons, such as your platform or permission flags. Refer to the specific error message for more details.
2022-04-07 11:44:05 +00:00
#[ error( " Not possible to change the access time " ) ]
#[ diagnostic(code(nu::shell::change_access_time_not_possible), url(docsrs)) ]
ChangeAccessTimeNotPossible ( String , #[ label( " {0} " ) ] Span ) ,
2022-04-14 05:08:46 +00:00
/// Changing the modification time ("mtime") of this file is not possible.
///
/// ## Resolution
///
/// This can be for various reasons, such as your platform or permission flags. Refer to the specific error message for more details.
2022-04-07 11:44:05 +00:00
#[ error( " Not possible to change the modified time " ) ]
#[ diagnostic(code(nu::shell::change_modified_time_not_possible), url(docsrs)) ]
ChangeModifiedTimeNotPossible ( String , #[ label( " {0} " ) ] Span ) ,
2022-04-14 05:08:46 +00:00
/// Unable to remove this item.
2021-10-10 04:13:15 +00:00
#[ error( " Remove not possible " ) ]
#[ diagnostic(code(nu::shell::remove_not_possible), url(docsrs)) ]
2022-04-14 05:08:46 +00:00
// NOTE: Currently unused. Remove?
2021-10-10 04:13:15 +00:00
RemoveNotPossible ( String , #[ label( " {0} " ) ] Span ) ,
2021-10-14 17:54:51 +00:00
2022-04-14 05:08:46 +00:00
// These three are unused. Remove?
2021-10-14 17:54:51 +00:00
#[ error( " No file to be removed " ) ]
NoFileToBeRemoved ( ) ,
#[ error( " No file to be moved " ) ]
NoFileToBeMoved ( ) ,
#[ error( " No file to be copied " ) ]
NoFileToBeCopied ( ) ,
2021-10-26 19:50:39 +00:00
2022-04-27 10:52:31 +00:00
/// Error while trying to read a file
///
/// ## Resolution
///
/// The error will show the result from a file operation
#[ error( " Error trying to read file " ) ]
#[ diagnostic(code(nu::shell::error_reading_file), url(docsrs)) ]
ReadingFile ( String , #[ label( " {0} " ) ] Span ) ,
2022-04-14 05:08:46 +00:00
/// A name was not found. Did you mean a different name?
///
/// ## Resolution
///
/// The error message will suggest a possible match for what you meant.
2021-11-07 21:48:50 +00:00
#[ error( " Name not found " ) ]
#[ diagnostic(code(nu::shell::name_not_found), url(docsrs)) ]
DidYouMean ( String , #[ label( " did you mean '{0}'? " ) ] Span ) ,
2021-11-15 23:16:06 +00:00
2022-08-13 09:55:06 +00:00
/// A name was not found. Did you mean a different name?
///
/// ## Resolution
///
/// The error message will suggest a possible match for what you meant.
#[ error( " {0} " ) ]
#[ diagnostic(code(nu::shell::did_you_mean_custom), url(docsrs)) ]
DidYouMeanCustom ( String , String , #[ label( " did you mean '{1}'? " ) ] Span ) ,
2022-04-14 05:08:46 +00:00
/// The given input must be valid UTF-8 for further processing.
///
/// ## Resolution
///
/// Check your input's encoding. Are there any funny characters/bytes?
2021-11-23 08:14:40 +00:00
#[ error( " Non-UTF8 string " ) ]
2021-11-15 23:16:06 +00:00
#[ diagnostic(code(nu::parser::non_utf8), url(docsrs)) ]
NonUtf8 ( #[ label = " non-UTF8 string " ] Span ) ,
2021-11-23 08:14:40 +00:00
2022-12-10 17:23:44 +00:00
/// The given input must be valid UTF-8 for further processing.
///
/// ## Resolution
///
/// Check your input's encoding. Are there any funny characters/bytes?
#[ error( " Non-UTF8 string " ) ]
#[ diagnostic(code(nu::parser::non_utf8_custom), url(docsrs)) ]
NonUtf8Custom ( String , #[ label = " {0} " ] Span ) ,
2022-04-14 05:08:46 +00:00
/// A custom value could not be converted to a Dataframe.
///
/// ## Resolution
///
/// Make sure conversion to a Dataframe is possible for this value or convert it to a type that does, first.
2021-11-23 08:14:40 +00:00
#[ error( " Casting error " ) ]
2021-12-05 03:11:19 +00:00
#[ diagnostic(code(nu::shell::downcast_not_possible), url(docsrs)) ]
2021-11-23 08:14:40 +00:00
DowncastNotPossible ( String , #[ label( " {0} " ) ] Span ) ,
2021-11-28 19:35:02 +00:00
2022-04-14 05:08:46 +00:00
/// The value given for this configuration is not supported.
///
/// ## Resolution
///
/// Refer to the specific error message for details and convert values as needed.
2021-12-17 01:04:54 +00:00
#[ error( " Unsupported config value " ) ]
#[ diagnostic(code(nu::shell::unsupported_config_value), url(docsrs)) ]
UnsupportedConfigValue ( String , String , #[ label = " expected {0}, got {1} " ] Span ) ,
2022-04-14 05:08:46 +00:00
/// An expected configuration value is not present.
///
/// ## Resolution
///
/// Refer to the specific error message and add the configuration value to your config file as needed.
2021-12-17 01:04:54 +00:00
#[ error( " Missing config value " ) ]
#[ diagnostic(code(nu::shell::missing_config_value), url(docsrs)) ]
MissingConfigValue ( String , #[ label = " missing {0} " ] Span ) ,
Standardise the use of ShellError::UnsupportedInput and ShellError::TypeMismatch and add spans to every instance of the former (#7217)
# Description
* I was dismayed to discover recently that UnsupportedInput and
TypeMismatch are used *extremely* inconsistently across the codebase.
UnsupportedInput is sometimes used for input type-checks (as per the
name!!), but *also* used for argument type-checks. TypeMismatch is also
used for both.
I thus devised the following standard: input type-checking *only* uses
UnsupportedInput, and argument type-checking *only* uses TypeMismatch.
Moreover, to differentiate them, UnsupportedInput now has *two* error
arrows (spans), one pointing at the command and the other at the input
origin, while TypeMismatch only has the one (because the command should
always be nearby)
* In order to apply that standard, a very large number of
UnsupportedInput uses were changed so that the input's span could be
retrieved and delivered to it.
* Additionally, I noticed many places where **errors are not propagated
correctly**: there are lots of `match` sites which take a Value::Error,
then throw it away and replace it with a new Value::Error with
less/misleading information (such as reporting the error as an
"incorrect type"). I believe that the earliest errors are the most
important, and should always be propagated where possible.
* Also, to standardise one broad subset of UnsupportedInput error
messages, who all used slightly different wordings of "expected
`<type>`, got `<type>`", I created OnlySupportsThisInputType as a
variant of it.
* Finally, a bunch of error sites that had "repeated spans" - i.e. where
an error expected two spans, but `call.head` was given for both - were
fixed to use different spans.
# Example
BEFORE
```
〉20b | str starts-with 'a'
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #31:1:1]
1 │ 20b | str starts-with 'a'
· ┬
· ╰── Input's type is filesize. This command only works with strings.
╰────
〉'a' | math cos
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #33:1:1]
1 │ 'a' | math cos
· ─┬─
· ╰── Only numerical values are supported, input type: String
╰────
〉0x[12] | encode utf8
Error: nu::shell::unsupported_input (link)
× Unsupported input
╭─[entry #38:1:1]
1 │ 0x[12] | encode utf8
· ───┬──
· ╰── non-string input
╰────
```
AFTER
```
〉20b | str starts-with 'a'
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #1:1:1]
1 │ 20b | str starts-with 'a'
· ┬ ───────┬───────
· │ ╰── only string input data is supported
· ╰── input type: filesize
╰────
〉'a' | math cos
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #2:1:1]
1 │ 'a' | math cos
· ─┬─ ────┬───
· │ ╰── only numeric input data is supported
· ╰── input type: string
╰────
〉0x[12] | encode utf8
Error: nu::shell::pipeline_mismatch (link)
× Pipeline mismatch.
╭─[entry #3:1:1]
1 │ 0x[12] | encode utf8
· ───┬── ───┬──
· │ ╰── only string input data is supported
· ╰── input type: binary
╰────
```
# User-Facing Changes
Various error messages suddenly make more sense (i.e. have two arrows
instead of one).
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-12-23 06:48:53 +00:00
/// Negative value passed when positive one is required.
2022-04-14 05:08:46 +00:00
///
/// ## Resolution
///
/// Guard against negative values or check your inputs.
2022-02-20 20:20:41 +00:00
#[ error( " Negative value passed when positive one is required " ) ]
#[ diagnostic(code(nu::shell::needs_positive_value), url(docsrs)) ]
NeedsPositiveValue ( #[ label = " use a positive value " ] Span ) ,
2022-04-14 05:08:46 +00:00
/// This is a generic error type used for different situations.
2021-11-28 19:35:02 +00:00
#[ error( " {0} " ) ]
#[ diagnostic() ]
2022-04-18 12:34:10 +00:00
GenericError (
2022-02-21 03:31:50 +00:00
String ,
String ,
2022-04-18 12:34:10 +00:00
#[ label( " {1} " ) ] Option < Span > ,
#[ help ] Option < String > ,
2022-02-21 03:31:50 +00:00
#[ related ] Vec < ShellError > ,
) ,
2022-04-14 05:08:46 +00:00
/// This is a generic error type used for different situations.
2022-02-21 03:31:50 +00:00
#[ error( " {1} " ) ]
#[ diagnostic() ]
OutsideSpannedLabeledError ( #[ source_code ] String , String , String , #[ label( " {2} " ) ] Span ) ,
2022-04-14 05:08:46 +00:00
/// Attempted to use a deprecated command.
///
/// ## Resolution
///
/// Check the help for the new suggested command and update your script accordingly.
2022-02-10 12:55:19 +00:00
#[ error( " Deprecated command {0} " ) ]
#[ diagnostic(code(nu::shell::deprecated_command), url(docsrs)) ]
DeprecatedCommand (
String ,
String ,
2022-02-10 23:27:51 +00:00
#[ label = " '{0}' is deprecated. Please use '{1}' instead. " ] Span ,
2022-02-10 12:55:19 +00:00
) ,
2022-05-06 12:58:32 +00:00
2022-12-10 17:23:24 +00:00
/// Attempted to use a deprecated parameter.
///
/// ## Resolution
///
/// Check the help for the command and update your script accordingly.
#[ error( " Deprecated parameter {0} " ) ]
#[ diagnostic(code(nu::shell::deprecated_command), url(docsrs)) ]
DeprecatedParameter (
String ,
String ,
#[ label = " Parameter '{0}' is deprecated. Please use '{1}' instead. " ] Span ,
) ,
2022-05-06 12:58:32 +00:00
/// Non-Unicode input received.
///
/// ## Resolution
///
/// Check that your path is UTF-8 compatible.
#[ error( " Non-Unicode input received. " ) ]
#[ diagnostic(code(nu::shell::non_unicode_input), url(docsrs)) ]
NonUnicodeInput ,
/// Unexpected abbr component.
///
/// ## Resolution
///
/// Check the path abbreviation to ensure that it is valid.
#[ error( " Unexpected abbr component `{0}`. " ) ]
#[ diagnostic(code(nu::shell::unexpected_path_abbreviateion), url(docsrs)) ]
UnexpectedAbbrComponent ( String ) ,
2022-08-28 08:40:14 +00:00
// It should be only used by commands accepts block, and accept inputs from pipeline.
/// Failed to eval block with specific pipeline input.
#[ error( " Eval block failed with pipeline input " ) ]
#[ diagnostic(code(nu::shell::eval_block_with_input), url(docsrs)) ]
2022-09-01 10:20:22 +00:00
EvalBlockWithInput ( #[ label( " source value " ) ] Span , #[ related ] Vec < ShellError > ) ,
New commands: `break`, `continue`, `return`, and `loop` (#7230)
# Description
This adds `break`, `continue`, `return`, and `loop`.
* `break` - breaks out a loop
* `continue` - continues a loop at the next iteration
* `return` - early return from a function call
* `loop` - loop forever (until the loop hits a break)
Examples:
```
for i in 1..10 {
if $i == 5 {
continue
}
print $i
}
```
```
for i in 1..10 {
if $i == 5 {
break
}
print $i
}
```
```
def foo [x] {
if true {
return 2
}
$x
}
foo 100
```
```
loop { print "hello, forever" }
```
```
[1, 2, 3, 4, 5] | each {|x|
if $x > 3 { break }
$x
}
```
# User-Facing Changes
Adds the above commands.
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2022-11-24 20:39:16 +00:00
/// Break event, which may become an error if used outside of a loop
#[ error( " Break used outside of loop " ) ]
Break ( #[ label = " used outside of loop " ] Span ) ,
/// Continue event, which may become an error if used outside of a loop
#[ error( " Continue used outside of loop " ) ]
Continue ( #[ label = " used outside of loop " ] Span ) ,
/// Return event, which may become an error if used outside of a function
#[ error( " Return used outside of function " ) ]
Return ( #[ label = " used outside of function " ] Span , Box < Value > ) ,
2023-01-05 02:38:50 +00:00
/// The code being executed called itself too many times.
///
/// ## Resolution
///
/// Adjust your Nu code to
#[ error( " Recursion limit ({recursion_limit}) reached " ) ]
#[ diagnostic(code(nu::shell::recursion_limit_reached), url(docsrs)) ]
RecursionLimitReached {
recursion_limit : u64 ,
#[ label( " This called itself too many times " ) ]
span : Option < Span > ,
} ,
LazyRecord (#7619)
This is an attempt to implement a new `Value::LazyRecord` variant for
performance reasons.
`LazyRecord` is like a regular `Record`, but it's possible to access
individual columns without evaluating other columns. I've implemented
`LazyRecord` for the special `$nu` variable; accessing `$nu` is
relatively slow because of all the information in `scope`, and [`$nu`
accounts for about 2/3 of Nu's startup time on
Linux](https://github.com/nushell/nushell/issues/6677#issuecomment-1364618122).
### Benchmarks
I ran some benchmarks on my desktop (Linux, 12900K) and the results are
very pleasing.
Nu's time to start up and run a command (`cargo build --release;
hyperfine 'target/release/nu -c "echo \"Hello, world!\""' --shell=none
--warmup 10`) goes from **8.8ms to 3.2ms, about 2.8x faster**.
Tests are also much faster! Running `cargo nextest` (with our very slow
`proptest` tests disabled) goes from **7.2s to 4.4s (1.6x faster)**,
because most tests involve launching a new instance of Nu.
### Design (updated)
I've added a new `LazyRecord` trait and added a `Value` variant wrapping
those trait objects, much like `CustomValue`. `LazyRecord`
implementations must implement these 2 functions:
```rust
// All column names
fn column_names(&self) -> Vec<&'static str>;
// Get 1 specific column value
fn get_column_value(&self, column: &str) -> Result<Value, ShellError>;
```
### Serializability
`Value` variants must implement `Serializable` and `Deserializable`, which poses some problems because I want to use unserializable things like `EngineState` in `LazyRecord`s. To work around this, I basically lie to the type system:
1. Add `#[typetag::serde(tag = "type")]` to `LazyRecord` to make it serializable
2. Any unserializable fields in `LazyRecord` implementations get marked with `#[serde(skip)]`
3. At the point where a `LazyRecord` normally would get serialized and sent to a plugin, I instead collect it into a regular `Value::Record` (which can be serialized)
2023-01-19 03:27:26 +00:00
/// An attempt to access a record column failed.
#[ error( " Access failure: {message} " ) ]
#[ diagnostic(code(nu::shell::lazy_record_access_failed), url(docsrs)) ]
LazyRecordAccessFailed {
message : String ,
column_name : String ,
#[ label( " Could not access '{column_name}' on this record " ) ]
span : Span ,
} ,
2021-10-05 19:54:30 +00:00
}
impl From < std ::io ::Error > for ShellError {
fn from ( input : std ::io ::Error ) -> ShellError {
2021-12-02 23:11:25 +00:00
ShellError ::IOError ( format! ( " {:?} " , input ) )
2021-10-05 19:54:30 +00:00
}
}
2021-10-05 21:08:39 +00:00
impl std ::convert ::From < Box < dyn std ::error ::Error > > for ShellError {
fn from ( input : Box < dyn std ::error ::Error > ) -> ShellError {
2021-12-02 23:11:25 +00:00
ShellError ::IOError ( input . to_string ( ) )
2021-10-05 21:08:39 +00:00
}
}
2021-10-05 19:54:30 +00:00
impl From < Box < dyn std ::error ::Error + Send + Sync > > for ShellError {
fn from ( input : Box < dyn std ::error ::Error + Send + Sync > ) -> ShellError {
2021-12-02 23:11:25 +00:00
ShellError ::IOError ( format! ( " {:?} " , input ) )
2021-10-05 19:54:30 +00:00
}
2021-09-02 01:29:43 +00:00
}
2021-11-07 21:48:50 +00:00
2022-06-30 01:01:34 +00:00
pub fn into_code ( err : & ShellError ) -> Option < String > {
err . code ( ) . map ( | code | code . to_string ( ) )
}
LazyRecord (#7619)
This is an attempt to implement a new `Value::LazyRecord` variant for
performance reasons.
`LazyRecord` is like a regular `Record`, but it's possible to access
individual columns without evaluating other columns. I've implemented
`LazyRecord` for the special `$nu` variable; accessing `$nu` is
relatively slow because of all the information in `scope`, and [`$nu`
accounts for about 2/3 of Nu's startup time on
Linux](https://github.com/nushell/nushell/issues/6677#issuecomment-1364618122).
### Benchmarks
I ran some benchmarks on my desktop (Linux, 12900K) and the results are
very pleasing.
Nu's time to start up and run a command (`cargo build --release;
hyperfine 'target/release/nu -c "echo \"Hello, world!\""' --shell=none
--warmup 10`) goes from **8.8ms to 3.2ms, about 2.8x faster**.
Tests are also much faster! Running `cargo nextest` (with our very slow
`proptest` tests disabled) goes from **7.2s to 4.4s (1.6x faster)**,
because most tests involve launching a new instance of Nu.
### Design (updated)
I've added a new `LazyRecord` trait and added a `Value` variant wrapping
those trait objects, much like `CustomValue`. `LazyRecord`
implementations must implement these 2 functions:
```rust
// All column names
fn column_names(&self) -> Vec<&'static str>;
// Get 1 specific column value
fn get_column_value(&self, column: &str) -> Result<Value, ShellError>;
```
### Serializability
`Value` variants must implement `Serializable` and `Deserializable`, which poses some problems because I want to use unserializable things like `EngineState` in `LazyRecord`s. To work around this, I basically lie to the type system:
1. Add `#[typetag::serde(tag = "type")]` to `LazyRecord` to make it serializable
2. Any unserializable fields in `LazyRecord` implementations get marked with `#[serde(skip)]`
3. At the point where a `LazyRecord` normally would get serialized and sent to a plugin, I instead collect it into a regular `Value::Record` (which can be serialized)
2023-01-19 03:27:26 +00:00
pub fn did_you_mean < S : AsRef < str > > ( possibilities : & [ S ] , input : & str ) -> Option < String > {
let possibilities : Vec < & str > = possibilities . iter ( ) . map ( | s | s . as_ref ( ) ) . collect ( ) ;
2022-09-21 00:46:01 +00:00
let suggestion =
crate ::lev_distance ::find_best_match_for_name_with_substrings ( & possibilities , input , None )
. map ( | s | s . to_string ( ) ) ;
if let Some ( suggestion ) = & suggestion {
if suggestion . len ( ) = = 1 & & suggestion . to_lowercase ( ) ! = input . to_lowercase ( ) {
return None ;
}
2021-11-07 21:48:50 +00:00
}
2022-09-21 00:46:01 +00:00
suggestion
2021-11-07 21:48:50 +00:00
}
pub fn levenshtein_distance ( a : & str , b : & str ) -> usize {
2022-09-21 00:46:01 +00:00
crate ::lev_distance ::lev_distance ( a , b , usize ::max_value ( ) )
. expect ( " It is impossible to exceed the supplied limit since all types involved are usize. " )
2021-11-07 21:48:50 +00:00
}
2022-03-27 22:11:56 +00:00
#[ cfg(test) ]
mod tests {
use super ::did_you_mean ;
#[ test ]
2022-09-21 00:46:01 +00:00
fn did_you_mean_examples ( ) {
let all_cases = [
(
vec! [ " a " , " b " ] ,
vec! [
( " a " , Some ( " a " ) , " " ) ,
( " A " , Some ( " a " ) , " " ) ,
(
" c " ,
None ,
" Not helpful to suggest an arbitrary choice when none are close " ,
) ,
( " ccccccccccccccccccccccc " , None , " Not helpful to suggest an arbitrary choice when none are close " ) ,
] ,
) ,
(
vec! [ " OS " , " PWD " , " PWDPWDPWDPWD " ] ,
vec! [
( " pwd " , Some ( " PWD " ) , " Exact case insensitive match yields a match " ) ,
( " pwdpwdpwdpwd " , Some ( " PWDPWDPWDPWD " ) , " Exact case insensitive match yields a match " ) ,
( " PWF " , Some ( " PWD " ) , " One-letter typo yields a match " ) ,
( " pwf " , None , " Case difference plus typo yields no match " ) ,
( " Xwdpwdpwdpwd " , None , " Case difference plus typo yields no match " ) ,
]
) ,
(
vec! [ " foo " , " bar " , " baz " ] ,
vec! [
( " fox " , Some ( " foo " ) , " " ) ,
( " FOO " , Some ( " foo " ) , " " ) ,
( " FOX " , None , " " ) ,
(
" ccc " ,
None ,
" Not helpful to suggest an arbitrary choice when none are close " ,
) ,
(
" zzz " ,
None ,
" 'baz' does share a character, but rustc rule is edit distance must be <= 1/3 of the length of the user input " ,
) ,
] ,
) ,
(
vec! [ " aaaaaa " ] ,
vec! [
( " XXaaaa " , Some ( " aaaaaa " ) , " Distance of 2 out of 6 chars: close enough to meet rustc's rule " ) ,
( " XXXaaa " , None , " Distance of 3 out of 6 chars: not close enough to meet rustc's rule " ) ,
( " XaaaaX " , Some ( " aaaaaa " ) , " Distance of 2 out of 6 chars: close enough to meet rustc's rule " ) ,
( " XXaaaaXX " , None , " Distance of 4 out of 6 chars: not close enough to meet rustc's rule " )
]
) ,
] ;
for ( possibilities , cases ) in all_cases {
for ( input , expected_suggestion , discussion ) in cases {
let suggestion = did_you_mean ( & possibilities , input ) ;
assert_eq! (
suggestion . as_deref ( ) ,
expected_suggestion ,
" Expected the following reasoning to hold but it did not: '{}' " ,
discussion
) ;
}
}
2022-03-27 22:11:56 +00:00
}
}