1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
use core::fmt::{self, Display, Formatter, Write};

use crate::fmt::IndentWriter;

/// Methods for adapting [`Display`] objects to indent themselves when printed.
pub trait Indentable: Sized + Display {
    /// Wrap this object so that its [`Display`] representation is indented
    /// with the given `indent`. Each non-empty line of the formatted output
    /// will be prefixed with the indent.
    ///
    /// # Example:
    ///
    /// ```
    /// use indent_write::indentable::Indentable;
    ///
    /// let content = "Line 1\nLine 2\n\nLine 3\n";
    /// let indented = content.indented("    ");
    /// let result = indented.to_string();
    ///
    /// assert_eq!(result, "    Line 1\n    Line 2\n\n    Line 3\n");
    /// ```
    #[must_use = "Indentables do nothing unless used"]
    fn indented(self, indent: &str) -> Indented<'_, Self> {
        Indented { item: self, indent }
    }

    /// Wrap this object so that its [`Display`] representation is indented
    /// with the given `indent`. Each non-empty line *except for the first*
    /// of the formatted output will be prefixed with the indent.
    ///
    /// # Example:
    ///
    /// ```
    /// use indent_write::indentable::Indentable;
    ///
    /// let content = "Line 1\nLine 2\n\nLine 3\n";
    /// let indented = content.indented_skip_initial("    ");
    /// let result = indented.to_string();
    ///
    /// assert_eq!(result, "Line 1\n    Line 2\n\n    Line 3\n");
    /// ```
    #[must_use = "Indentables do nothing unless used"]
    fn indented_skip_initial(self, indent: &str) -> IndentedSkipIntial<'_, Self> {
        IndentedSkipIntial { item: self, indent }
    }
}

impl<T: Display> Indentable for T {}

/// Wrapper struct that indents the [`Display`] representation of an item. When
/// printed with [`Display`], it will insert [`indent`][Self::indent] before
/// each non-empty line of the underlying [`item`][Self::item]'s [`Display`]
/// output.
///
/// Created with [`Indentable::indented`]; see its documentation for an example.
#[derive(Debug, Clone, Copy)]
pub struct Indented<'i, T: Display> {
    /// The item to indent.
    pub item: T,

    /// The indentation to insert before each non-empty line.
    pub indent: &'i str,
}

impl<T: Display> Display for Indented<'_, T> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(IndentWriter::new(self.indent, f), "{}", self.item)
    }
}

/// Wrapper struct that indents the [`Display`] representation of an item. When
/// printed with [`Display`], it will insert [`indent`][Self::indent] before
/// each non-empty line _after the first_ of the underlying
/// [`item`][Self::item]'s [`Display`] output.
///
/// Created with [`Indentable::indented`]; see its documentation for an example.
#[derive(Debug, Clone, Copy)]
pub struct IndentedSkipIntial<'i, T: Display> {
    /// The item to indent.
    pub item: T,

    /// The indentation to insert before each non-empty line.
    pub indent: &'i str,
}

impl<T: Display> Display for IndentedSkipIntial<'_, T> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(
            IndentWriter::new_skip_initial(self.indent, f),
            "{}",
            self.item
        )
    }
}