indent_write/
indentable.rs

1use core::fmt::{self, Display, Formatter, Write};
2
3use crate::fmt::IndentWriter;
4
5/// Methods for adapting [`Display`] objects to indent themselves when printed.
6pub trait Indentable: Sized + Display {
7    /// Wrap this object so that its [`Display`] representation is indented
8    /// with the given `indent`. Each non-empty line of the formatted output
9    /// will be prefixed with the indent.
10    ///
11    /// # Example:
12    ///
13    /// ```
14    /// use indent_write::indentable::Indentable;
15    ///
16    /// let content = "Line 1\nLine 2\n\nLine 3\n";
17    /// let indented = content.indented("    ");
18    /// let result = indented.to_string();
19    ///
20    /// assert_eq!(result, "    Line 1\n    Line 2\n\n    Line 3\n");
21    /// ```
22    #[must_use = "Indentables do nothing unless used"]
23    fn indented(self, indent: &str) -> Indented<'_, Self> {
24        Indented { item: self, indent }
25    }
26
27    /// Wrap this object so that its [`Display`] representation is indented
28    /// with the given `indent`. Each non-empty line *except for the first*
29    /// of the formatted output will be prefixed with the indent.
30    ///
31    /// # Example:
32    ///
33    /// ```
34    /// use indent_write::indentable::Indentable;
35    ///
36    /// let content = "Line 1\nLine 2\n\nLine 3\n";
37    /// let indented = content.indented_skip_initial("    ");
38    /// let result = indented.to_string();
39    ///
40    /// assert_eq!(result, "Line 1\n    Line 2\n\n    Line 3\n");
41    /// ```
42    #[must_use = "Indentables do nothing unless used"]
43    fn indented_skip_initial(self, indent: &str) -> IndentedSkipIntial<'_, Self> {
44        IndentedSkipIntial { item: self, indent }
45    }
46}
47
48impl<T: Display> Indentable for T {}
49
50/// Wrapper struct that indents the [`Display`] representation of an item. When
51/// printed with [`Display`], it will insert [`indent`][Self::indent] before
52/// each non-empty line of the underlying [`item`][Self::item]'s [`Display`]
53/// output.
54///
55/// Created with [`Indentable::indented`]; see its documentation for an example.
56#[derive(Debug, Clone, Copy)]
57pub struct Indented<'i, T: Display> {
58    /// The item to indent.
59    pub item: T,
60
61    /// The indentation to insert before each non-empty line.
62    pub indent: &'i str,
63}
64
65impl<T: Display> Display for Indented<'_, T> {
66    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
67        write!(IndentWriter::new(self.indent, f), "{}", self.item)
68    }
69}
70
71/// Wrapper struct that indents the [`Display`] representation of an item. When
72/// printed with [`Display`], it will insert [`indent`][Self::indent] before
73/// each non-empty line _after the first_ of the underlying
74/// [`item`][Self::item]'s [`Display`] output.
75///
76/// Created with [`Indentable::indented`]; see its documentation for an example.
77#[derive(Debug, Clone, Copy)]
78pub struct IndentedSkipIntial<'i, T: Display> {
79    /// The item to indent.
80    pub item: T,
81
82    /// The indentation to insert before each non-empty line.
83    pub indent: &'i str,
84}
85
86impl<T: Display> Display for IndentedSkipIntial<'_, T> {
87    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
88        write!(
89            IndentWriter::new_skip_initial(self.indent, f),
90            "{}",
91            self.item
92        )
93    }
94}