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

Code before:
    /// The original [`Location`] is converted to a string to more easily report the error
    /// attributing the location.
    ///
    /// This value is only used if `span` is [`Span::unknown()`] as most of the time we want to
    /// refer to user code than the Rust code.
    pub location: Option<String>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Diagnostic)]
pub enum ErrorKind {
    Std(std::io::ErrorKind),
    // TODO: in Rust 1.83 this can be std::io::ErrorKind::NotADirectory
    NotADirectory,
    NotAFile,
    // TODO: in Rust 1.83 this can be std::io::ErrorKind::IsADirectory
    IsADirectory,
}

#[derive(Debug, Clone, PartialEq, Eq, Diagnostic)]
pub struct AdditionalContext(String);

impl Display for AdditionalContext {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(self.0.as_ref())
    }
}

impl IoError {
    /// Creates a new [`IoError`] with the given kind, span, and optional path.
    ///
    /// This constructor should be used in all cases where the combination of the error kind, span,
    /// and path provides enough information to describe the error clearly.
    /// For example, errors like "File not found" or "Permission denied" are typically
    /// self-explanatory when paired with the file path and the location in user-provided
    /// Nushell code (`span`).
    ///
    /// # Constraints
    /// If `span` is unknown, use:
    /// - `new_internal` if no path is available.
    /// - `new_internal_with_path` if a path is available.
    pub fn new(kind: impl Into<ErrorKind>, span: Span, path: impl Into<Option<PathBuf>>) -> Self {
        let path = path.into();

        if span == Span::unknown() {
            debug_assert!(
                path.is_some(),
                "for unknown spans with paths, use `new_internal_with_path`"
            );
            debug_assert!(
                path.is_none(),
                "for unknown spans without paths, use `new_internal`"

Review comment (bug):
Using `thiserror::Error` can help here:
```suggestion
#[derive(Debug, Clone, PartialEq, Eq, Error, Diagnostic)]
#[error("{0}")]
pub struct AdditionalContext(#[from] String);
```

Code after:
    /// The original [`Location`] is converted to a string to more easily report the error
    /// attributing the location.
    ///
    /// This value is only used if `span` is [`Span::unknown()`] as most of the time we want to
    /// refer to user code than the Rust code.
    pub location: Option<String>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Diagnostic)]
pub enum ErrorKind {
    Std(std::io::ErrorKind),
    // TODO: in Rust 1.83 this can be std::io::ErrorKind::NotADirectory
    NotADirectory,
    NotAFile,
    // TODO: in Rust 1.83 this can be std::io::ErrorKind::IsADirectory
    IsADirectory,
}

#[derive(Debug, Clone, PartialEq, Eq, Error, Diagnostic)]
#[error("{0}")]
pub struct AdditionalContext(String);

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

impl IoError {
    /// Creates a new [`IoError`] with the given kind, span, and optional path.
    ///
    /// This constructor should be used in all cases where the combination of the error kind, span,
    /// and path provides enough information to describe the error clearly.
    /// For example, errors like "File not found" or "Permission denied" are typically
    /// self-explanatory when paired with the file path and the location in user-provided
    /// Nushell code (`span`).
    ///
    /// # Constraints
    /// If `span` is unknown, use:
    /// - `new_internal` if no path is available.
    /// - `new_internal_with_path` if a path is available.
    pub fn new(kind: impl Into<ErrorKind>, span: Span, path: impl Into<Option<PathBuf>>) -> Self {
        let path = path.into();

        if span == Span::unknown() {
            debug_assert!(
                path.is_some(),
                "for unknown spans with paths, use `new_internal_with_path`"
            );
            debug_assert!(
                path.is_none(),