stylish_core/
formatter.rs

1use crate::{Arguments, Display, Restyle, Result, Style, Write};
2
3#[doc(hidden)] // workaround https://github.com/rust-lang/rust/issues/85522
4#[derive(Clone, Copy, Debug)]
5pub enum Align {
6    Left,
7    Center,
8    Right,
9}
10
11#[doc(hidden)] // workaround https://github.com/rust-lang/rust/issues/85522
12#[derive(Clone, Copy, Debug)]
13pub enum Sign {
14    Plus,
15    Minus,
16}
17
18#[doc(hidden)] // workaround https://github.com/rust-lang/rust/issues/85522
19#[derive(Clone, Copy, Debug)]
20pub enum DebugHex {
21    Lower,
22    Upper,
23}
24
25#[doc(hidden)] // workaround https://github.com/rust-lang/rust/issues/85522
26#[derive(Clone, Copy, Debug, Default)]
27pub struct FormatterArgs<'a> {
28    pub align: Option<Align>,
29    pub sign: Option<Sign>,
30    pub alternate: bool,
31    pub zero: bool,
32    pub width: Option<&'a usize>,
33    pub precision: Option<&'a usize>,
34    pub debug_hex: Option<DebugHex>,
35}
36
37/// A configured output stream.
38///
39/// A `Formatter` wraps a target output stream with a set of configuration
40/// options for formatting of data written to the stream. There is (currently)
41/// no public constructors for `Formatter`, an instance is created and passed to
42/// implementations of [`stylish::Display`] when they are used in
43/// the [`stylish`] macros.
44pub struct Formatter<'a> {
45    style: Style,
46    pub(crate) format: FormatterArgs<'a>,
47    write: &'a mut (dyn Write + 'a),
48}
49
50impl core::fmt::Debug for Formatter<'_> {
51    #[inline]
52    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result {
53        f.debug_struct("Formatter")
54            .field("style", &self.style)
55            .field("format", &self.format)
56            .finish()
57    }
58}
59
60impl<'a> Formatter<'a> {
61    #[inline]
62    pub(crate) fn new(write: &'a mut (dyn Write + 'a)) -> Self {
63        Self {
64            style: Style::default(),
65            format: FormatterArgs::default(),
66            write,
67        }
68    }
69
70    // TODO: All the rest of the std::fmt::Formatter methods
71
72    /// Create a sub-`Formatter` with some styles changed. This may be useful in
73    /// implementations of [`stylish::Display`] to dynamically configure how
74    /// some parts are formatted.
75    ///
76    /// ```rust
77    /// struct Name(&'static str);
78    ///
79    /// impl stylish::Display for Name {
80    ///     fn fmt(&self, f: &mut stylish::Formatter<'_>) -> stylish::Result {
81    ///         let color = match self.0 {
82    ///             "Ferris" => stylish::Color::Red,
83    ///             "Gorris" => stylish::Color::Cyan,
84    ///             _ => stylish::Color::Default,
85    ///         };
86    ///         f.with(stylish::Foreground(color)).write_str(self.0)
87    ///     }
88    /// }
89    ///
90    /// let formatted = stylish::html::format!("Hello {:s} and {:s}", Name("Ferris"), Name("Gorris"));
91    /// assert_eq!(
92    ///     formatted,
93    ///     "Hello <span style=color:red>Ferris</span> and <span style=color:cyan>Gorris</span>"
94    /// );
95    /// ```
96    pub fn with(&mut self, restyle: impl Restyle) -> Formatter<'_> {
97        Formatter {
98            write: &mut *self.write,
99            format: self.format,
100            style: self.style.with(restyle),
101        }
102    }
103
104    #[doc(hidden)]
105    /// pub for macros
106    pub fn with_args<'b>(
107        &'b mut self,
108        format: &FormatterArgs<'b>,
109        restyle: impl Restyle,
110    ) -> Formatter<'b> {
111        Formatter {
112            write: &mut *self.write,
113            format: *format,
114            style: self.style.with(restyle),
115        }
116    }
117
118    /// Writes some data to the underlying output stream, using the current
119    /// style.
120    ///
121    /// ```rust
122    /// struct Name(&'static str);
123    ///
124    /// impl stylish::Display for Name {
125    ///     fn fmt(&self, f: &mut stylish::Formatter<'_>) -> stylish::Result {
126    ///         let color = match self.0 {
127    ///             "Ferris" => stylish::Color::Red,
128    ///             "Gorris" => stylish::Color::Cyan,
129    ///             _ => stylish::Color::Default,
130    ///         };
131    ///         f.with(stylish::Foreground(color)).write_str(self.0)
132    ///     }
133    /// }
134    ///
135    /// let formatted = stylish::html::format!("Hello {:s} and {:s}", Name("Ferris"), Name("Gorris"));
136    /// assert_eq!(
137    ///     formatted,
138    ///     "Hello <span style=color:red>Ferris</span> and <span style=color:cyan>Gorris</span>"
139    /// );
140    /// ```
141    #[inline]
142    pub fn write_str(&mut self, s: &str) -> Result {
143        self.write.write_str(s, self.style)?;
144        Ok(())
145    }
146
147    /// Writes some formatted data into this instance, overriding the current
148    /// style as appropriate.
149    ///
150    /// ```rust
151    /// struct Name(&'static str);
152    ///
153    /// impl stylish::Display for Name {
154    ///     fn fmt(&self, f: &mut stylish::Formatter<'_>) -> stylish::Result {
155    ///         match self.0 {
156    ///             "Ferris" => f.write_fmt(stylish::format_args!("{:(fg=red)}", self.0)),
157    ///             "Gorris" => f.write_fmt(stylish::format_args!("{:(fg=cyan)}", self.0)),
158    ///             _ => f.write_fmt(stylish::format_args!("{}", self.0)),
159    ///         }
160    ///     }
161    /// }
162    ///
163    /// let formatted = stylish::html::format!("Hello {:s} and {:s}", Name("Ferris"), Name("Gorris"));
164    /// assert_eq!(
165    ///     formatted,
166    ///     "Hello <span style=color:red>Ferris</span> and <span style=color:cyan>Gorris</span>"
167    /// );
168    /// ```
169    #[inline]
170    pub fn write_fmt(&mut self, args: Arguments<'_>) -> Result {
171        args.fmt(self)?;
172        Ok(())
173    }
174}
175
176impl<'a> Write for Formatter<'a> {
177    #[inline]
178    fn write_str(&mut self, s: &str, style: Style) -> Result {
179        self.with(style).write_str(s)
180    }
181
182    #[inline]
183    fn write_fmt(&mut self, args: Arguments<'_>) -> Result {
184        self.write_fmt(args)
185    }
186}
187
188impl<'a> core::fmt::Write for Formatter<'a> {
189    #[inline]
190    fn write_str(&mut self, s: &str) -> Result {
191        self.write_str(s)
192    }
193}