1use std::fmt;
2
3#[cfg(feature = "serde_derive")]
4use serde::{Deserialize, Serialize};
5
6use super::diff::Diff;
7
8#[derive(Clone, Debug)]
10#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
11pub struct UnifiedDiff {
12 pub content: Vec<UnifiedDiffContent>,
13}
14
15#[derive(Clone, Debug)]
17#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
18pub struct FormattedUnifiedDiff {
19 pub content: Vec<UnifiedDiffContent>,
20}
21
22#[derive(Clone, Debug)]
24#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
25pub struct UnifiedDiffContent {
26 pub old_title: String,
27 pub new_title: String,
28 pub lines: Vec<UnifiedDiffLine>,
29}
30
31#[derive(Clone, Debug)]
33#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
34pub struct UnifiedDiffLine {
35 pub pos: Option<String>,
36 pub old: Option<String>,
37 pub new: Option<String>,
38}
39
40#[derive(Clone, Debug)]
42#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
43pub struct SplitUnifiedDiff {
44 pub old: Vec<SplitUnifiedDiffContent>,
45 pub new: Vec<SplitUnifiedDiffContent>,
46}
47
48#[derive(Clone, Debug)]
50#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
51pub struct SplitUnifiedDiffContent {
52 pub title: String,
53 pub lines: Vec<SplitUnifiedDiffLine>,
54}
55
56#[derive(Clone, Debug)]
58#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
59pub struct SplitUnifiedDiffLine {
60 pub pos: Option<String>,
61 pub text: Option<String>,
62}
63
64impl UnifiedDiff {
65 pub fn format(&self) -> FormattedUnifiedDiff {
67 let content = self
68 .content
69 .iter()
70 .map(|x| {
71 let old_title = format!("--- {}", &x.old_title);
72 let new_title = format!("+++ {}", &x.new_title);
73
74 let lines = x
75 .lines
76 .iter()
77 .map(|x| UnifiedDiffLine {
78 pos: x.pos.as_ref().map(|pos| format!("@@ {} @@", pos)),
79 old: x.old.as_ref().map(|old| format!("- {}", old)),
80 new: x.new.as_ref().map(|new| format!("+ {}", new)),
81 })
82 .collect();
83
84 UnifiedDiffContent { old_title, new_title, lines }
85 })
86 .collect();
87 FormattedUnifiedDiff { content }
88 }
89
90 pub fn split(&self) -> SplitUnifiedDiff {
92 let old = self
93 .content
94 .iter()
95 .map(|x| SplitUnifiedDiffContent {
96 title: x.old_title.clone(),
97 lines: x
98 .lines
99 .iter()
100 .map(|x| SplitUnifiedDiffLine {
101 pos: x.pos.as_ref().map(|p| p.to_owned()),
102 text: x.old.as_ref().map(|t| t.to_owned()),
103 })
104 .collect(),
105 })
106 .collect();
107
108 let new = self
109 .content
110 .iter()
111 .map(|x| SplitUnifiedDiffContent {
112 title: x.new_title.clone(),
113 lines: x
114 .lines
115 .iter()
116 .map(|x| SplitUnifiedDiffLine {
117 pos: x.pos.as_ref().map(|p| p.to_owned()),
118 text: x.new.as_ref().map(|t| t.to_owned()),
119 })
120 .collect(),
121 })
122 .collect();
123
124 SplitUnifiedDiff { old, new }
125 }
126}
127
128impl fmt::Display for FormattedUnifiedDiff {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131 for x in &self.content {
132 writeln!(f, "{}", &x.old_title)?;
133 writeln!(f, "{}", &x.new_title)?;
134 for x in &x.lines {
135 if let Some(pos) = &x.pos {
136 writeln!(f, "{}", pos)?;
137 }
138 if let Some(old) = &x.old {
139 writeln!(f, "{}", old)?;
140 }
141 if let Some(new) = &x.new {
142 writeln!(f, "{}", new)?;
143 }
144 }
145 }
146 Ok(())
147 }
148}
149
150pub fn unified_diff(diff: &Diff) -> UnifiedDiff {
152 let mut ret: Vec<UnifiedDiffContent> = vec![];
153
154 if !diff.sheet_diff.is_empty() {
155 let lines = diff
156 .sheet_diff
157 .iter()
158 .map(|x| UnifiedDiffLine {
159 pos: None,
160 old: x.old.clone(),
161 new: x.new.clone(),
162 })
163 .collect();
164
165 ret.push(UnifiedDiffContent {
166 old_title: format!("{} (sheet names)", diff.old_filepath),
167 new_title: format!("{} (sheet names)", diff.new_filepath),
168 lines,
169 });
170 }
171
172 let cell_diffs_content: Vec<UnifiedDiffContent> = diff
173 .cell_diffs
174 .iter()
175 .map(|x| {
176 let lines = x
177 .cells
178 .iter()
179 .map(|x| UnifiedDiffLine {
180 pos: Some(format!("{}({},{}) {}", x.addr, x.row, x.col, x.kind)),
181 old: x.old.clone(),
182 new: x.new.clone(),
183 })
184 .collect();
185
186 UnifiedDiffContent {
187 old_title: format!("{} [{}]", diff.old_filepath, x.sheet),
188 new_title: format!("{} [{}]", diff.new_filepath, x.sheet),
189 lines,
190 }
191 })
192 .collect();
193
194 ret.extend(cell_diffs_content);
195
196 UnifiedDiff { content: ret }
197}