2021-09-20 23:37:26 +02:00
use miette ::Diagnostic ;
2021-10-01 07:11:49 +02:00
use serde ::{ Deserialize , Serialize } ;
2021-09-20 23:37:26 +02:00
use thiserror ::Error ;
2021-09-06 01:16:27 +02:00
use crate ::{ ast ::Operator , Span , Type } ;
2021-09-02 03:29:43 +02:00
2021-11-03 01:26:09 +01: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 07:11:49 +02:00
#[ derive(Debug, Clone, Error, Diagnostic, Serialize, Deserialize) ]
2021-09-02 03:29:43 +02:00
pub enum ShellError {
2022-04-14 07:08:46 +02: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 23:37:26 +02:00
#[ error( " Type mismatch during operation. " ) ]
#[ diagnostic(code(nu::shell::type_mismatch), url(docsrs)) ]
2021-09-02 03:29:43 +02:00
OperatorMismatch {
2021-09-20 23:37:26 +02:00
#[ label = " type mismatch for operator " ]
2021-09-02 03:29:43 +02:00
op_span : Span ,
lhs_ty : Type ,
2021-09-20 23:37:26 +02:00
#[ label( " {lhs_ty} " ) ]
2021-09-02 03:29:43 +02:00
lhs_span : Span ,
rhs_ty : Type ,
2021-09-20 23:37:26 +02:00
#[ label( " {rhs_ty} " ) ]
2021-09-02 03:29:43 +02:00
rhs_span : Span ,
} ,
2021-09-20 23:37:26 +02:00
2022-04-14 07:08:46 +02: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 07:58:25 +02:00
#[ error( " Operator overflow. " ) ]
#[ diagnostic(code(nu::shell::operator_overflow), url(docsrs)) ]
OperatorOverflow ( String , #[ label = " {0} " ] Span ) ,
2022-04-14 07:08:46 +02: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 03:02:01 +02:00
#[ error( " Pipeline mismatch. " ) ]
#[ diagnostic(code(nu::shell::pipeline_mismatch), url(docsrs)) ]
2021-12-03 00:11:25 +01:00
PipelineMismatch (
String ,
#[ label( " expected: {0} " ) ] Span ,
#[ label( " value originates from here " ) ] Span ,
) ,
2022-04-14 07:08:46 +02: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.
2021-12-03 00:11:25 +01:00
#[ error( " Type mismatch " ) ]
#[ diagnostic(code(nu::shell::type_mismatch), url(docsrs)) ]
2022-02-07 20:54:06 +01:00
TypeMismatch ( String , #[ label = " needs {0} " ] Span ) ,
2021-10-09 03:02:01 +02:00
2022-10-25 03:22:57 +02: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.
#[ error( " Type mismatch " ) ]
#[ diagnostic(code(nu::shell::type_mismatch), url(docsrs)) ]
TypeMismatchGenericMessage {
err_message : String ,
#[ label = " {err_message} " ]
span : Span ,
} ,
2022-04-14 07:08:46 +02: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 23:37:26 +02:00
#[ error( " Unsupported operator: {0}. " ) ]
#[ diagnostic(code(nu::shell::unsupported_operator), url(docsrs)) ]
UnsupportedOperator ( Operator , #[ label = " unsupported operator " ] Span ) ,
2022-04-14 07:08:46 +02:00
/// An operator was not recognized during evaluation.
///
/// ## Resolution
///
/// Did you write the correct operator?
#[ error( " Unknown operator: {0}. " ) ]
2021-09-20 23:37:26 +02:00
#[ diagnostic(code(nu::shell::unknown_operator), url(docsrs)) ]
2022-04-14 07:08:46 +02:00
UnknownOperator ( String , #[ label = " unknown operator " ] Span ) ,
2021-09-20 23:37:26 +02:00
2022-04-14 07:08:46 +02:00
/// An expected command parameter is missing.
///
/// ## Resolution
///
/// Add the expected parameter and try again.
2021-10-08 00:20:23 +02:00
#[ error( " Missing parameter: {0}. " ) ]
#[ diagnostic(code(nu::shell::missing_parameter), url(docsrs)) ]
MissingParameter ( String , #[ label = " missing parameter: {0} " ] Span ) ,
2022-04-14 07:08:46 +02: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 06:13:15 +02:00
#[ error( " Incompatible parameters. " ) ]
#[ diagnostic(code(nu::shell::incompatible_parameters), url(docsrs)) ]
IncompatibleParameters {
left_message : String ,
2022-04-14 07:08:46 +02:00
// Be cautious, as flags can share the same span, resulting in a panic (ex: `rm -pt`)
2021-10-10 06:13:15 +02:00
#[ label( " {left_message} " ) ]
left_span : Span ,
right_message : String ,
#[ label( " {right_message} " ) ]
right_span : Span ,
} ,
2022-04-14 07:08:46 +02: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 21:17:37 +01:00
#[ error( " Delimiter error " ) ]
#[ diagnostic(code(nu::shell::delimiter_error), url(docsrs)) ]
DelimiterError ( String , #[ label( " {0} " ) ] Span ) ,
2022-04-14 07:08:46 +02: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 06:13:15 +02:00
#[ error( " Incompatible parameters. " ) ]
#[ diagnostic(code(nu::shell::incompatible_parameters), url(docsrs)) ]
IncompatibleParametersSingle ( String , #[ label = " {0} " ] Span ) ,
2022-04-14 07:08:46 +02: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 06:13:15 +02:00
#[ error( " Feature not enabled. " ) ]
#[ diagnostic(code(nu::shell::feature_not_enabled), url(docsrs)) ]
FeatureNotEnabled ( #[ label = " feature not enabled " ] Span ) ,
2022-04-14 07:08:46 +02: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 22:26:41 +01:00
#[ error( " Running external commands not supported " ) ]
2021-09-20 23:37:26 +02:00
#[ diagnostic(code(nu::shell::external_commands), url(docsrs)) ]
ExternalNotSupported ( #[ label = " external not supported " ] Span ) ,
2022-04-14 07:08:46 +02: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 07:12:19 +01:00
#[ error( " Invalid Probability. " ) ]
#[ diagnostic(code(nu::shell::invalid_probability), url(docsrs)) ]
InvalidProbability ( #[ label = " invalid probability " ] Span ) ,
2022-04-14 07:08:46 +02: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 18:26:12 +01: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 07:08:46 +02: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-03 00:11:25 +01:00
#[ error( " Nushell failed: {0}. " ) ]
#[ diagnostic(code(nu::shell::nushell_failed), url(docsrs)) ]
2022-05-07 21:39:22 +02:00
// Only use this one if Nushell completely falls over and hits a state that isn't possible or isn't recoverable
2021-12-03 00:11:25 +01:00
NushellFailed ( String ) ,
2021-09-20 23:37:26 +02:00
2022-04-14 07:08:46 +02: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 20:43:38 +01:00
#[ error( " Nushell failed: {0}. " ) ]
2022-05-07 21:39:22 +02: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 20:43:38 +01:00
NushellFailedSpanned ( String , String , #[ label = " {1} " ] Span ) ,
2022-05-07 21:39:22 +02: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 07:08:46 +02: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 23:56:12 +01:00
#[ error( " Variable not found " ) ]
2021-09-20 23:37:26 +02:00
#[ diagnostic(code(nu::shell::variable_not_found), url(docsrs)) ]
VariableNotFoundAtRuntime ( #[ label = " variable not found " ] Span ) ,
2022-04-14 07:08:46 +02: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 02:39:25 +01:00
#[ error( " Environment variable '{0}' not found " ) ]
2022-01-04 23:30:34 +01:00
#[ diagnostic(code(nu::shell::env_variable_not_found), url(docsrs)) ]
2022-01-10 02:39:25 +01:00
EnvVarNotFoundAtRuntime ( String , #[ label = " environment variable not found " ] Span ) ,
2021-11-16 00:16:06 +01:00
2022-05-07 21:39:22 +02: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 23:22:17 +02:00
#[ diagnostic(code(nu::shell::module_or_overlay_not_found), url(docsrs)) ]
2022-05-07 21:39:22 +02: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 07:08:46 +02: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-16 00:16:06 +01: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 07:08:46 +02: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 23:37:26 +02:00
#[ error( " Can't convert to {0}. " ) ]
#[ diagnostic(code(nu::shell::cant_convert), url(docsrs)) ]
2022-04-18 14:34:10 +02:00
CantConvert (
2022-03-24 13:04:31 +01:00
String ,
String ,
#[ label( " can't convert {1} to {0} " ) ] Span ,
2022-04-18 14:34:10 +02:00
#[ help ] Option < String > ,
2022-03-24 13:04:31 +01:00
) ,
2022-07-07 12:54:38 +02: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 07:08:46 +02: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 23:18:39 +01: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 22:32:56 +02: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 ) ,
2022-04-14 07:08:46 +02: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 23:37:26 +02:00
#[ error( " Division by zero. " ) ]
#[ diagnostic(code(nu::shell::division_by_zero), url(docsrs)) ]
DivisionByZero ( #[ label( " division by zero " ) ] Span ) ,
2022-04-14 07:08:46 +02: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 23:37:26 +02: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 07:08:46 +02:00
/// You attempted to access an index beyond the available length of a value.
///
/// ## Resolution
///
/// Check your lengths and try again.
2021-09-20 23:37:26 +02:00
#[ error( " Row number too large (max: {0}). " ) ]
#[ diagnostic(code(nu::shell::access_beyond_end), url(docsrs)) ]
2022-03-18 22:12:54 +01:00
AccessBeyondEnd ( usize , #[ label = " index too large (max: {0}) " ] Span ) ,
2021-09-20 23:37:26 +02:00
2022-10-29 19:47:50 +02: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 07:08:46 +02:00
/// You attempted to access an index beyond the available length of a stream.
///
/// ## Resolution
///
/// Check your lengths and try again.
2021-09-20 23:37:26 +02:00
#[ error( " Row number too large. " ) ]
#[ diagnostic(code(nu::shell::access_beyond_end_of_stream), url(docsrs)) ]
2022-03-18 22:12:54 +01:00
AccessBeyondEndOfStream ( #[ label = " index too large " ] Span ) ,
2021-09-20 23:37:26 +02:00
2022-04-14 07:08:46 +02: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 23:37:26 +02: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 07:08:46 +02: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 23:37:26 +02:00
#[ error( " Cannot find column " ) ]
#[ diagnostic(code(nu::shell::column_not_found), url(docsrs)) ]
2021-10-11 21:51:54 +02:00
CantFindColumn (
#[ label = " cannot find column " ] Span ,
#[ label = " value originates here " ] Span ,
) ,
2021-09-20 23:37:26 +02:00
2022-04-14 07:08:46 +02: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 18:55:02 +01:00
#[ error( " Column already exists " ) ]
#[ diagnostic(code(nu::shell::column_already_exists), url(docsrs)) ]
ColumnAlreadyExists (
#[ label = " column already exists " ] Span ,
#[ label = " value originates here " ] Span ,
) ,
2022-04-14 07:08:46 +02: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 04:59:12 +01: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 07:08:46 +02: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 19:34:10 +02:00
#[ error( " External command failed " ) ]
2022-01-22 15:12:34 +01:00
#[ diagnostic(code(nu::shell::external_command), url(docsrs), help( " {1} " )) ]
ExternalCommand ( String , String , #[ label( " {0} " ) ] Span ) ,
2021-09-24 14:03:39 +02:00
2022-04-14 07:08:46 +02: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 14:03:39 +02:00
#[ error( " Unsupported input " ) ]
#[ diagnostic(code(nu::shell::unsupported_input), url(docsrs)) ]
2022-02-28 16:14:33 +01:00
UnsupportedInput ( String , #[ label( " {0} " ) ] Span ) ,
2021-10-01 23:53:13 +02:00
2022-04-14 07:08:46 +02: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 02:21:46 +01: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 07:08:46 +02:00
/// A network operation failed.
///
/// ## Resolution
///
/// It's always DNS.
2022-01-04 03:01:18 +01:00
#[ error( " Network failure " ) ]
#[ diagnostic(code(nu::shell::network_failure), url(docsrs)) ]
NetworkFailure ( String , #[ label( " {0} " ) ] Span ) ,
2022-04-14 07:08:46 +02: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 03:02:01 +02:00
#[ error( " Command not found " ) ]
#[ diagnostic(code(nu::shell::command_not_found), url(docsrs)) ]
CommandNotFound ( #[ label( " command not found " ) ] Span ) ,
2022-04-14 07:08:46 +02:00
/// A flag was not found.
2021-10-01 23:53:13 +02:00
#[ error( " Flag not found " ) ]
#[ diagnostic(code(nu::shell::flag_not_found), url(docsrs)) ]
2022-04-14 07:08:46 +02:00
// NOTE: Seems to be unused. Removable?
2021-10-01 23:53:13 +02:00
FlagNotFound ( String , #[ label( " {0} not found " ) ] Span ) ,
2021-10-05 05:43:07 +02:00
2022-04-14 07:08:46 +02: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 05:43:07 +02:00
#[ error( " File not found " ) ]
#[ diagnostic(code(nu::shell::file_not_found), url(docsrs)) ]
FileNotFound ( #[ label( " file not found " ) ] Span ) ,
2022-04-14 07:08:46 +02: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 23:08:39 +02:00
#[ error( " File not found " ) ]
#[ diagnostic(code(nu::shell::file_not_found), url(docsrs)) ]
FileNotFoundCustom ( String , #[ label( " {0} " ) ] Span ) ,
2022-04-14 07:08:46 +02:00
/// A plugin failed to load.
///
/// ## Resolution
///
2022-08-24 06:32:41 +02:00
/// This is a fairly generic error. Refer to the specific error message for further details.
2021-12-18 16:52:27 +01:00
#[ error( " Plugin failed to load: {0} " ) ]
2021-12-05 04:11:19 +01:00
#[ diagnostic(code(nu::shell::plugin_failed_to_load), url(docsrs)) ]
2021-12-03 00:11:25 +01:00
PluginFailedToLoad ( String ) ,
2022-04-14 07:08:46 +02:00
/// A message from a plugin failed to encode.
///
/// ## Resolution
///
/// This is likely a bug with the plugin itself.
2021-12-18 16:52:27 +01:00
#[ error( " Plugin failed to encode: {0} " ) ]
2021-12-05 04:11:19 +01:00
#[ diagnostic(code(nu::shell::plugin_failed_to_encode), url(docsrs)) ]
PluginFailedToEncode ( String ) ,
2022-04-14 07:08:46 +02: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 16:52:27 +01:00
#[ error( " Plugin failed to decode: {0} " ) ]
2021-12-05 04:11:19 +01:00
#[ diagnostic(code(nu::shell::plugin_failed_to_decode), url(docsrs)) ]
PluginFailedToDecode ( String ) ,
2022-08-24 06:32:41 +02: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 07:08:46 +02:00
/// An I/O operation failed.
///
/// ## Resolution
///
/// This is a generic error. Refer to the specific error message for further details.
2021-12-03 00:11:25 +01:00
#[ error( " I/O error " ) ]
2022-01-04 23:30:34 +01:00
#[ diagnostic(code(nu::shell::io_error), url(docsrs), help( " {0} " )) ]
2021-12-03 00:11:25 +01:00
IOError ( String ) ,
2022-08-24 06:32:41 +02: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 07:08:46 +02: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 14:02:12 +01: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 07:08:46 +02: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 05:43:07 +02:00
#[ error( " Directory not found " ) ]
#[ diagnostic(code(nu::shell::directory_not_found), url(docsrs)) ]
2022-04-18 14:34:10 +02:00
DirectoryNotFound ( #[ label( " directory not found " ) ] Span , #[ help ] Option < String > ) ,
2021-10-05 05:43:07 +02:00
2022-04-14 07:08:46 +02: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 23:21:26 +01:00
#[ error( " Directory not found " ) ]
#[ diagnostic(code(nu::shell::directory_not_found_custom), url(docsrs)) ]
2021-10-05 23:08:39 +02:00
DirectoryNotFoundCustom ( String , #[ label( " {0} " ) ] Span ) ,
2022-04-14 07:08:46 +02: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 05:43:07 +02: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 21:54:30 +02:00
2022-04-14 07:08:46 +02: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 21:54:30 +02:00
#[ error( " Move not possible " ) ]
#[ diagnostic(code(nu::shell::move_not_possible_single), url(docsrs)) ]
2022-04-14 07:08:46 +02:00
// NOTE: Currently not actively used.
2021-10-05 21:54:30 +02:00
MoveNotPossibleSingle ( String , #[ label( " {0} " ) ] Span ) ,
2021-10-07 23:18:03 +02:00
2022-04-14 07:08:46 +02: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 23:18:03 +02:00
#[ error( " Create not possible " ) ]
2021-10-07 23:20:03 +02:00
#[ diagnostic(code(nu::shell::create_not_possible), url(docsrs)) ]
2021-10-07 23:18:03 +02:00
CreateNotPossible ( String , #[ label( " {0} " ) ] Span ) ,
2021-10-10 06:13:15 +02:00
2022-04-14 07:08:46 +02: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 13:44:05 +02: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 07:08:46 +02: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 13:44:05 +02: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 07:08:46 +02:00
/// Unable to remove this item.
2021-10-10 06:13:15 +02:00
#[ error( " Remove not possible " ) ]
#[ diagnostic(code(nu::shell::remove_not_possible), url(docsrs)) ]
2022-04-14 07:08:46 +02:00
// NOTE: Currently unused. Remove?
2021-10-10 06:13:15 +02:00
RemoveNotPossible ( String , #[ label( " {0} " ) ] Span ) ,
2021-10-14 19:54:51 +02:00
2022-04-14 07:08:46 +02:00
// These three are unused. Remove?
2021-10-14 19:54:51 +02: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 21:50:39 +02:00
2022-04-27 12:52:31 +02: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 07:08:46 +02: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 22:48:50 +01:00
#[ error( " Name not found " ) ]
#[ diagnostic(code(nu::shell::name_not_found), url(docsrs)) ]
DidYouMean ( String , #[ label( " did you mean '{0}'? " ) ] Span ) ,
2021-11-16 00:16:06 +01:00
2022-08-13 11:55:06 +02: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 07:08:46 +02: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 09:14:40 +01:00
#[ error( " Non-UTF8 string " ) ]
2021-11-16 00:16:06 +01:00
#[ diagnostic(code(nu::parser::non_utf8), url(docsrs)) ]
NonUtf8 ( #[ label = " non-UTF8 string " ] Span ) ,
2021-11-23 09:14:40 +01:00
2022-04-14 07:08:46 +02: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 09:14:40 +01:00
#[ error( " Casting error " ) ]
2021-12-05 04:11:19 +01:00
#[ diagnostic(code(nu::shell::downcast_not_possible), url(docsrs)) ]
2021-11-23 09:14:40 +01:00
DowncastNotPossible ( String , #[ label( " {0} " ) ] Span ) ,
2021-11-28 20:35:02 +01:00
2022-04-14 07:08:46 +02: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 02:04:54 +01: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 07:08:46 +02: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 02:04:54 +01:00
#[ error( " Missing config value " ) ]
#[ diagnostic(code(nu::shell::missing_config_value), url(docsrs)) ]
MissingConfigValue ( String , #[ label = " missing {0} " ] Span ) ,
2022-04-14 07:08:46 +02:00
/// Negative value passed when positive ons is required.
///
/// ## Resolution
///
/// Guard against negative values or check your inputs.
2022-02-20 21:20:41 +01: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 07:08:46 +02:00
/// This is a generic error type used for different situations.
2021-11-28 20:35:02 +01:00
#[ error( " {0} " ) ]
#[ diagnostic() ]
2022-04-18 14:34:10 +02:00
GenericError (
2022-02-21 04:31:50 +01:00
String ,
String ,
2022-04-18 14:34:10 +02:00
#[ label( " {1} " ) ] Option < Span > ,
#[ help ] Option < String > ,
2022-02-21 04:31:50 +01:00
#[ related ] Vec < ShellError > ,
) ,
2022-04-14 07:08:46 +02:00
/// This is a generic error type used for different situations.
2022-02-21 04:31:50 +01:00
#[ error( " {1} " ) ]
#[ diagnostic() ]
OutsideSpannedLabeledError ( #[ source_code ] String , String , String , #[ label( " {2} " ) ] Span ) ,
2022-04-14 07:08:46 +02:00
/// Attempted to use a deprecated command.
///
/// ## Resolution
///
/// Check the help for the new suggested command and update your script accordingly.
2022-02-10 13:55:19 +01:00
#[ error( " Deprecated command {0} " ) ]
#[ diagnostic(code(nu::shell::deprecated_command), url(docsrs)) ]
DeprecatedCommand (
String ,
String ,
2022-02-11 00:27:51 +01:00
#[ label = " '{0}' is deprecated. Please use '{1}' instead. " ] Span ,
2022-02-10 13:55:19 +01:00
) ,
2022-05-06 14:58:32 +02: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 ,
// /// Path not found.
// #[error("Path not found.")]
// PathNotFound,
/// 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 10:40:14 +02: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 12:20:22 +02:00
EvalBlockWithInput ( #[ label( " source value " ) ] Span , #[ related ] Vec < ShellError > ) ,
2021-10-05 21:54:30 +02:00
}
impl From < std ::io ::Error > for ShellError {
fn from ( input : std ::io ::Error ) -> ShellError {
2021-12-03 00:11:25 +01:00
ShellError ::IOError ( format! ( " {:?} " , input ) )
2021-10-05 21:54:30 +02:00
}
}
2021-10-05 23:08:39 +02:00
impl std ::convert ::From < Box < dyn std ::error ::Error > > for ShellError {
fn from ( input : Box < dyn std ::error ::Error > ) -> ShellError {
2021-12-03 00:11:25 +01:00
ShellError ::IOError ( input . to_string ( ) )
2021-10-05 23:08:39 +02:00
}
}
2021-10-05 21:54:30 +02: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-03 00:11:25 +01:00
ShellError ::IOError ( format! ( " {:?} " , input ) )
2021-10-05 21:54:30 +02:00
}
2021-09-02 03:29:43 +02:00
}
2021-11-07 22:48:50 +01:00
2022-06-30 03:01:34 +02:00
pub fn into_code ( err : & ShellError ) -> Option < String > {
err . code ( ) . map ( | code | code . to_string ( ) )
}
2022-09-21 02:46:01 +02:00
pub fn did_you_mean ( possibilities : & [ String ] , input : & str ) -> Option < String > {
let possibilities : Vec < & str > = possibilities . iter ( ) . map ( | s | s . as_str ( ) ) . collect ( ) ;
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 22:48:50 +01:00
}
2022-09-21 02:46:01 +02:00
suggestion
2021-11-07 22:48:50 +01:00
}
pub fn levenshtein_distance ( a : & str , b : & str ) -> usize {
2022-09-21 02:46:01 +02: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 22:48:50 +01:00
}
2022-03-28 00:11:56 +02:00
#[ cfg(test) ]
mod tests {
use super ::did_you_mean ;
#[ test ]
2022-09-21 02:46:01 +02: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 {
let possibilities : Vec < String > = possibilities . iter ( ) . map ( | s | s . to_string ( ) ) . collect ( ) ;
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-28 00:11:56 +02:00
}
}