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
95
96
97
98
99
100
101
102
103
104
// Copyright (C) 2023 Benjamin Stürz
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
use std::fmt::{self, Display, Formatter};
use super::*;

const INDENT: usize = 4;

struct IndentedXml<'a>(&'a Xml, usize);
struct IndentedTag<'a>(&'a Tag, usize);
struct IndentedContent<'a>(&'a Content, usize);

impl Display for IndentedXml<'_> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let Self(x, ind) = self;
        let ind2 = ind + INDENT;
        x.0.iter().try_for_each(|x| write!(f, "{}", IndentedContent(x, ind2)))
    }
}

impl Display for IndentedTag<'_> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let Self(tag, ind) = self;
        let ind2 = ind + INDENT;
        let n = &tag.name;
        write!(f, "{:ind$}<{n}", "")?;
        tag.args.iter().try_for_each(|a| write!(f, " {a}"))?;
        match tag.inner.as_ref().map_or(&[] as &[Content], |x| &x.0[..]) {
            &[] => write!(f, " />"),
            &[ref x] => {
                let sep = match x {
                    Content::Tag(_)     => true,
                    Content::Nested(_)  => true,
                    Content::Word(_)    => false,
                };

                if sep {
                    writeln!(f ,">")?;
                    writeln!(f, "{}", IndentedContent(x, ind2))?;
                    write!(f, "{:ind$}</{n}>", "")
                } else {
                    write!(f, ">{x}</{n}>")
                }
            },
            data => {
                writeln!(f, ">")?;
                data.iter().try_for_each(|x| writeln!(f, "{}", IndentedContent(x, ind2)))?;
                write!(f, "{:ind$}</{n}>", "")
            }
        }
    }
}

impl Display for IndentedContent<'_> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        let Self(x, ind) = self;
        match x {
            Content::Tag(t)     => write!(f, "{}", IndentedTag(t, *ind)),
            Content::Word(w)    => write!(f, "{:ind$}{}", "", w),
            Content::Nested(x)  => write!(f, "{}", IndentedXml(x, *ind - INDENT)),
        }
    }
}


impl Display for Xml {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.0.iter().try_for_each(|x| write!(f, "{x}"))
    }
}

impl Display for Tag {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{}", IndentedTag(self, 0))
    }
}

impl Display for Arg {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{}=\"{}\"", self.name, self.value)
    }
}

impl Display for Content {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match self {
            Self::Tag(t)    => write!(f, "{t}"),
            Self::Word(w)   => write!(f, "{w}"),
            Self::Nested(x) => write!(f, "{}", IndentedXml(x, 0)),
        }
    }
}