scarb_ui/components/
typed.rs

1use console::Style;
2use serde::{Serialize, Serializer};
3
4use crate::Message;
5
6/// Generic textual message with _type_ prefix.
7///
8/// Use this message type to display any kinds of warnings, errors etc.
9/// The type prefix can be stylized in text mode.
10#[derive(Serialize)]
11pub struct TypedMessage<'a> {
12    r#type: &'a str,
13    message: &'a str,
14
15    #[serde(skip_serializing_if = "Option::is_none")]
16    code: Option<&'a str>,
17
18    #[serde(skip)]
19    type_style: Option<&'a str>,
20    #[serde(skip)]
21    skip_type_for_text: bool,
22}
23
24impl<'a> TypedMessage<'a> {
25    /// Create a message with the given type, its style and the message text proper.
26    pub fn styled(ty: &'a str, type_style: &'a str, message: &'a str) -> Self {
27        Self {
28            r#type: ty,
29            message,
30            type_style: Some(type_style),
31            skip_type_for_text: false,
32            code: None,
33        }
34    }
35
36    /// Create a message that does not print type prefix in text mode.
37    ///
38    /// ## Example
39    /// Scarb uses this for emitting Cairo compiler diagnostics.
40    /// In text mode it prints the diagnostic as-is, while in JSON mode it wraps it as:
41    /// ```json
42    /// {"type":"diagnostic","message":"<diagnostic>"}
43    /// ```
44    pub fn naked_text(ty: &'a str, message: &'a str) -> Self {
45        Self {
46            r#type: ty,
47            message,
48            type_style: None,
49            skip_type_for_text: true,
50            code: None,
51        }
52    }
53
54    /// Sometimes, a message may be associated with a short machine-readable descriptor.
55    /// For example, some compilers associate numerical *codes* with various kinds of errors
56    /// that can be produced.
57    /// The optional `code` field allows carrying this information.
58    /// This will be shown as suffix in text mode, and as a `code` field in structured mode.
59    pub fn with_code(self, code: &'a str) -> Self {
60        Self {
61            code: Some(code),
62            ..self
63        }
64    }
65}
66
67impl Message for TypedMessage<'_> {
68    fn text(self) -> String {
69        if self.skip_type_for_text {
70            self.message.to_string()
71        } else {
72            format!(
73                "{}: {}",
74                self.type_style
75                    .map(Style::from_dotted_str)
76                    .unwrap_or_default()
77                    .apply_to(format!(
78                        "{}{}",
79                        self.r#type,
80                        self.code.map(|c| format!("[{c}]")).unwrap_or_default()
81                    )),
82                self.message
83            )
84        }
85    }
86
87    fn structured<S: Serializer>(self, ser: S) -> Result<S::Ok, S::Error> {
88        self.serialize(ser)
89    }
90}