Repository: nushell/nushell
File: crates/nu-protocol/src/errors/shell_error/io.rs (Rust)

Code before:
    }
}

impl Display for ErrorKind {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            ErrorKind::Std(error_kind) => {
                let msg = error_kind.to_string();
                let (first, rest) = msg.split_at(1);
                write!(f, "{}{}", first.to_uppercase(), rest)
            }
            ErrorKind::NotADirectory => write!(f, "Not a directory"),
            ErrorKind::NotAFile => write!(f, "Not a file"),
            ErrorKind::IsADirectory => write!(f, "Is a directory"),
        }
    }
}

impl std::error::Error for ErrorKind {}
impl std::error::Error for AdditionalContext {}

impl From<String> for AdditionalContext {
    fn from(value: String) -> Self {
        AdditionalContext(value)
    }
}

impl Diagnostic for IoError {
    fn code<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
        let mut code = String::from("nu::shell::io::");
        match self.kind {
            ErrorKind::Std(error_kind) => match error_kind {
                std::io::ErrorKind::NotFound => code.push_str("not_found"),
                std::io::ErrorKind::PermissionDenied => code.push_str("permission_denied"),
                std::io::ErrorKind::ConnectionRefused => code.push_str("connection_refused"),
                std::io::ErrorKind::ConnectionReset => code.push_str("connection_reset"),
                std::io::ErrorKind::ConnectionAborted => code.push_str("connection_aborted"),
                std::io::ErrorKind::NotConnected => code.push_str("not_connected"),
                std::io::ErrorKind::AddrInUse => code.push_str("addr_in_use"),
                std::io::ErrorKind::AddrNotAvailable => code.push_str("addr_not_available"),
                std::io::ErrorKind::BrokenPipe => code.push_str("broken_pipe"),
                std::io::ErrorKind::AlreadyExists => code.push_str("already_exists"),
                std::io::ErrorKind::WouldBlock => code.push_str("would_block"),
                std::io::ErrorKind::InvalidInput => code.push_str("invalid_input"),
                std::io::ErrorKind::InvalidData => code.push_str("invalid_data"),
                std::io::ErrorKind::TimedOut => code.push_str("timed_out"),
                std::io::ErrorKind::WriteZero => code.push_str("write_zero"),
                std::io::ErrorKind::Interrupted => code.push_str("interrupted"),
                std::io::ErrorKind::Unsupported => code.push_str("unsupported"),
                std::io::ErrorKind::UnexpectedEof => code.push_str("unexpected_eof"),
                std::io::ErrorKind::OutOfMemory => code.push_str("out_of_memory"),

Review comment (refactor):
If you derive the struct with `thiserror::Error` as I stated, you can remove this entirely.
```suggestion
```

Code after:
        move |err: std::io::Error| IoError::new(err.kind(), span, path.map(PathBuf::from))
    }
}

impl Display for ErrorKind {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            ErrorKind::Std(error_kind) => {
                let msg = error_kind.to_string();
                let (first, rest) = msg.split_at(1);
                write!(f, "{}{}", first.to_uppercase(), rest)
            }
            ErrorKind::NotADirectory => write!(f, "Not a directory"),
            ErrorKind::NotAFile => write!(f, "Not a file"),
            ErrorKind::IsADirectory => write!(f, "Is a directory"),
        }
    }
}

impl std::error::Error for ErrorKind {}

impl Diagnostic for IoError {
    fn code<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
        let mut code = String::from("nu::shell::io::");
        match self.kind {
            ErrorKind::Std(error_kind) => match error_kind {
                std::io::ErrorKind::NotFound => code.push_str("not_found"),
                std::io::ErrorKind::PermissionDenied => code.push_str("permission_denied"),
                std::io::ErrorKind::ConnectionRefused => code.push_str("connection_refused"),
                std::io::ErrorKind::ConnectionReset => code.push_str("connection_reset"),
                std::io::ErrorKind::ConnectionAborted => code.push_str("connection_aborted"),
                std::io::ErrorKind::NotConnected => code.push_str("not_connected"),
                std::io::ErrorKind::AddrInUse => code.push_str("addr_in_use"),
                std::io::ErrorKind::AddrNotAvailable => code.push_str("addr_not_available"),
                std::io::ErrorKind::BrokenPipe => code.push_str("broken_pipe"),
                std::io::ErrorKind::AlreadyExists => code.push_str("already_exists"),
                std::io::ErrorKind::WouldBlock => code.push_str("would_block"),
                std::io::ErrorKind::InvalidInput => code.push_str("invalid_input"),
                std::io::ErrorKind::InvalidData => code.push_str("invalid_data"),
                std::io::ErrorKind::TimedOut => code.push_str("timed_out"),
                std::io::ErrorKind::WriteZero => code.push_str("write_zero"),
                std::io::ErrorKind::Interrupted => code.push_str("interrupted"),
                std::io::ErrorKind::Unsupported => code.push_str("unsupported"),
                std::io::ErrorKind::UnexpectedEof => code.push_str("unexpected_eof"),
                std::io::ErrorKind::OutOfMemory => code.push_str("out_of_memory"),
                std::io::ErrorKind::Other => code.push_str("other"),
                kind => code.push_str(&kind.to_string().to_lowercase().replace(" ", "_")),
            },
            ErrorKind::NotADirectory => code.push_str("not_a_directory"),
            ErrorKind::NotAFile => code.push_str("not_a_file"),
            ErrorKind::IsADirectory => code.push_str("is_a_directory"),