sheets_diff/core/
unified_format.rs

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