1use std::fmt::{Display, Write};
2
3use facet::TypeNameOpts;
4use facet_pretty::PrettyPrinter;
5
6use crate::{
7 diff::{Diff, Value},
8 sequences::{ReplaceGroup, Updates, UpdatesGroup},
9};
10
11struct PadAdapter<'a, 'b: 'a> {
12 fmt: &'a mut std::fmt::Formatter<'b>,
13 on_newline: bool,
14}
15
16impl<'a, 'b> Write for PadAdapter<'a, 'b> {
17 fn write_str(&mut self, s: &str) -> std::fmt::Result {
18 for line in s.split_inclusive('\n') {
19 if self.on_newline {
20 self.fmt.write_str(" ")?;
21 }
22
23 self.on_newline = line.ends_with('\n');
24
25 self.fmt.write_str(line)?;
26 }
27
28 Ok(())
29 }
30
31 fn write_char(&mut self, c: char) -> std::fmt::Result {
32 if self.on_newline {
33 self.fmt.write_str(" ")?;
34 }
35
36 self.on_newline = c == '\n';
37 self.fmt.write_char(c)
38 }
39}
40
41impl<'mem, 'facet> Display for Diff<'mem, 'facet> {
42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43 match self {
44 Diff::Equal => f.write_str("equal"),
45 Diff::Replace { from, to } => {
46 let printer = PrettyPrinter::default().with_colors(false);
47
48 if from.shape().id != to.shape().id {
49 f.write_str("\x1b[1m")?;
50 from.type_name(f, TypeNameOpts::infinite())?;
51 f.write_str("\x1b[m => \x1b[1m")?;
52 to.type_name(f, TypeNameOpts::infinite())?;
53 f.write_str(" \x1b[m")?;
54 }
55
56 f.write_str("{\n\x1b[31m")?; let mut indent = PadAdapter {
59 fmt: f,
60 on_newline: true,
61 };
62
63 writeln!(indent, "{}\x1b[32m", printer.format_peek(*from))?;
64 write!(indent, "{}", printer.format_peek(*to))?;
65 f.write_str("\n\x1b[m}") }
67 Diff::User {
68 from,
69 to,
70 variant,
71 value,
72 } => {
73 let printer = PrettyPrinter::default().with_colors(false);
74 let mut indent = PadAdapter {
75 fmt: f,
76 on_newline: false,
77 };
78
79 write!(indent, "\x1b[1m")?;
80 from.write_type_name(indent.fmt, TypeNameOpts::infinite())?;
81
82 if let Some(variant) = variant {
83 write!(indent, "\x1b[m::\x1b[1m{variant}")?;
84 }
85
86 if from.id != to.id {
87 write!(indent, "\x1b[m => \x1b[1m")?;
88 to.write_type_name(indent.fmt, TypeNameOpts::infinite())?;
89
90 if let Some(variant) = variant {
91 write!(indent, "\x1b[m::\x1b[1m{variant}")?;
92 }
93 }
94
95 match value {
96 Value::Struct {
97 updates,
98 deletions,
99 insertions,
100 unchanged: _,
101 } => {
102 writeln!(indent, "\x1b[m {{")?;
103 for (field, update) in updates {
104 writeln!(indent, "{field}: {update}")?;
105 }
106
107 for (field, value) in deletions {
108 writeln!(
109 indent,
110 "\x1b[31m{field}: {}\x1b[m",
111 printer.format_peek(*value)
112 )?;
113 }
114
115 for (field, value) in insertions {
116 writeln!(
117 indent,
118 "\x1b[32m{field}: {}\x1b[m",
119 printer.format_peek(*value)
120 )?;
121 }
122
123 f.write_str("}")
124 }
125 Value::Tuple { updates } => {
126 writeln!(indent, "\x1b[m (")?;
127 write!(indent, "{updates}")?;
128 f.write_str(")")
129 }
130 }
131 }
132 Diff::Sequence { from, to, updates } => {
133 write!(f, "\x1b[1m")?;
134 from.write_type_name(f, TypeNameOpts::infinite())?;
135 write!(f, "\x1b[m")?;
136
137 if from.id != to.id {
138 write!(f, " => \x1b[1m")?;
139 to.write_type_name(f, TypeNameOpts::infinite())?;
140 write!(f, "\x1b[m")?;
141 }
142
143 let mut indent = PadAdapter {
144 fmt: f,
145 on_newline: false,
146 };
147
148 writeln!(indent, " [")?;
149 write!(indent, "{updates}")?;
150 write!(f, "]")
151 }
152 }
153 }
154}
155
156impl<'mem, 'facet> Display for Updates<'mem, 'facet> {
157 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158 if let Some(update) = &self.0.first {
159 update.fmt(f)?;
160 }
161
162 let printer = PrettyPrinter::default().with_colors(false);
163
164 for (values, update) in &self.0.values {
165 for value in values {
166 writeln!(f, "{}", printer.format_peek(*value))?;
167 }
168 update.fmt(f)?;
169 }
170
171 if let Some(values) = &self.0.last {
172 for value in values {
173 writeln!(f, "{}", printer.format_peek(*value))?;
174 }
175 }
176
177 Ok(())
178 }
179}
180
181impl<'mem, 'facet> Display for UpdatesGroup<'mem, 'facet> {
182 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
183 if let Some(update) = &self.0.first {
184 update.fmt(f)?;
185 }
186
187 for (values, update) in &self.0.values {
188 for value in values {
189 writeln!(f, "{value}")?;
190 }
191 update.fmt(f)?;
192 }
193
194 if let Some(values) = &self.0.last {
195 for value in values {
196 writeln!(f, "{value}")?;
197 }
198 }
199
200 Ok(())
201 }
202}
203
204impl<'mem, 'facet> Display for ReplaceGroup<'mem, 'facet> {
205 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
206 let printer = PrettyPrinter::default().with_colors(false);
207
208 for remove in &self.removals {
209 writeln!(f, "\x1b[31m{}\x1b[m", printer.format_peek(*remove))?;
210 }
211
212 for add in &self.additions {
213 writeln!(f, "\x1b[32m{}\x1b[m", printer.format_peek(*add))?;
214 }
215
216 Ok(())
217 }
218}