Skip to main content

nu_protocol/errors/
shell_warning.rs

1#![allow(unused_assignments)]
2use crate::Span;
3use miette::Diagnostic;
4use std::hash::Hash;
5use thiserror::Error;
6
7use crate::{ConfigWarning, ReportMode, Reportable};
8
9#[derive(Clone, Debug, Error, Diagnostic)]
10#[diagnostic(severity(Warning))]
11pub enum ShellWarning {
12    /// A parse-time deprecation. Indicates that something will be removed in a future release.
13    ///
14    /// Use [`ParseWarning::Deprecated`](crate::ParseWarning::Deprecated) if this is a deprecation
15    /// which is detectable at parse-time.
16    #[error("{dep_type} deprecated.")]
17    #[diagnostic(code(nu::shell::deprecated))]
18    Deprecated {
19        dep_type: String,
20        label: String,
21        #[label("{label}")]
22        span: Span,
23        #[help]
24        help: Option<String>,
25        report_mode: ReportMode,
26    },
27    /// Warnings reported while updating the config
28    #[error("Encountered {} warnings(s) when updating config", warnings.len())]
29    #[diagnostic(code(nu::shell::invalid_config))]
30    InvalidConfig {
31        #[related]
32        warnings: Vec<ConfigWarning>,
33    },
34    /// The interactive last-result value was truncated to fit `max_last_result_size`.
35    ///
36    /// Once-per-store is controlled by a stack flag; use [`ReportMode::EveryUse`] so the
37    /// engine report log does not permanently suppress later truncations at the same limit.
38    #[error(
39        "Last result was truncated to fit $env.config.max_last_result_size ({limit_bytes} bytes by Value::memory_size)."
40    )]
41    #[diagnostic(code(nu::shell::last_result_truncated))]
42    LastResultTruncated {
43        /// Access site span (not used as a source label — truncation is a state warning).
44        span: Span,
45        limit_bytes: usize,
46        #[help]
47        help: Option<String>,
48        report_mode: ReportMode,
49    },
50}
51
52impl Reportable for ShellWarning {
53    fn report_mode(&self) -> ReportMode {
54        match self {
55            ShellWarning::Deprecated { report_mode, .. }
56            | ShellWarning::LastResultTruncated { report_mode, .. } => *report_mode,
57            ShellWarning::InvalidConfig { .. } => ReportMode::FirstUse,
58        }
59    }
60}
61
62// To keep track of reported warnings
63impl Hash for ShellWarning {
64    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
65        match self {
66            ShellWarning::Deprecated {
67                dep_type, label, ..
68            } => {
69                dep_type.hash(state);
70                label.hash(state);
71            }
72            // Hash the contents so FirstUse dedups per warning batch, not
73            // once for all config warnings in the session.
74            ShellWarning::InvalidConfig { warnings } => warnings.hash(state),
75            // EveryUse — hash unused for suppression; include fields for completeness
76            ShellWarning::LastResultTruncated { limit_bytes, .. } => {
77                limit_bytes.hash(state);
78            }
79        }
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86    use crate::ConfigWarning;
87
88    fn hash_of(warning: &ShellWarning) -> u64 {
89        let mut hasher = std::hash::DefaultHasher::new();
90        warning.hash(&mut hasher);
91        std::hash::Hasher::finish(&hasher)
92    }
93
94    fn shared_name_batch(names: &str) -> ShellWarning {
95        ShellWarning::InvalidConfig {
96            warnings: vec![ConfigWarning::SharedKeybindingName {
97                names: names.into(),
98                span: Span::test_data(),
99            }],
100        }
101    }
102
103    /// `report_mode` is `FirstUse`, which dedups by this hash; a constant hash
104    /// would suppress every config warning after the first batch of a session.
105    #[test]
106    fn different_config_warning_batches_hash_differently() {
107        assert_ne!(
108            hash_of(&shared_name_batch("atuin")),
109            hash_of(&shared_name_batch("other")),
110        );
111    }
112
113    /// The same batch re-reported (e.g. a re-sourced config) stays suppressed.
114    #[test]
115    fn an_identical_config_warning_batch_hashes_the_same() {
116        assert_eq!(
117            hash_of(&shared_name_batch("atuin")),
118            hash_of(&shared_name_batch("atuin")),
119        );
120    }
121}