diff --git a/crates/nu-command/src/filesystem/cp.rs b/crates/nu-command/src/filesystem/cp.rs index 33f512dfe1..1fdd96ddb5 100644 --- a/crates/nu-command/src/filesystem/cp.rs +++ b/crates/nu-command/src/filesystem/cp.rs @@ -348,9 +348,22 @@ fn copy_file(src: PathBuf, dst: PathBuf, span: Span) -> Value { let msg = format!("copied {:} to {:}", src.display(), dst.display()); Value::String { val: msg, span } } - Err(e) => Value::Error { - error: ShellError::FileNotFoundCustom(format!("copy file {src:?} failed: {e}"), span), - }, + Err(e) => { + let message = format!("copy file {src:?} failed: {e}"); + + use std::io::ErrorKind; + let shell_error = match e.kind() { + ErrorKind::NotFound => ShellError::FileNotFoundCustom(message, span), + ErrorKind::PermissionDenied => ShellError::PermissionDeniedError(message, span), + ErrorKind::Interrupted => ShellError::IOInterrupted(message, span), + ErrorKind::OutOfMemory => ShellError::OutOfMemoryError(message, span), + // TODO: handle ExecutableFileBusy etc. when io_error_more is stabilized + // https://github.com/rust-lang/rust/issues/86442 + _ => ShellError::IOErrorSpanned(message, span), + }; + + Value::Error { error: shell_error } + } } } diff --git a/crates/nu-protocol/src/shell_error.rs b/crates/nu-protocol/src/shell_error.rs index 07ed40caf8..cc3b4d6439 100644 --- a/crates/nu-protocol/src/shell_error.rs +++ b/crates/nu-protocol/src/shell_error.rs @@ -478,7 +478,7 @@ Either make sure {0} is a string, or add a 'to_string' entry for it in ENV_CONVE /// /// ## Resolution /// - /// This is a failry generic error. Refer to the specific error message for further details. + /// This is a fairly generic error. Refer to the specific error message for further details. #[error("Plugin failed to load: {0}")] #[diagnostic(code(nu::shell::plugin_failed_to_load), url(docsrs))] PluginFailedToLoad(String), @@ -501,6 +501,15 @@ Either make sure {0} is a string, or add a 'to_string' entry for it in ENV_CONVE #[diagnostic(code(nu::shell::plugin_failed_to_decode), url(docsrs))] PluginFailedToDecode(String), + /// 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), + /// An I/O operation failed. /// /// ## Resolution @@ -510,6 +519,33 @@ Either make sure {0} is a string, or add a 'to_string' entry for it in ENV_CONVE #[diagnostic(code(nu::shell::io_error), url(docsrs), help("{0}"))] IOError(String), + /// 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), + /// Tried to `cd` to a path that isn't a directory. /// /// ## Resolution