1use std::fmt::Display;
2
3#[derive(Debug, Clone, Copy, PartialEq)]
4enum State {
5 Context,
6 Left,
7 Common,
8 Right,
9}
10
11pub fn run(file: String) -> anyhow::Result<String> {
12 use std::fmt::Write;
13 let mut output = String::new();
14 let mut state = State::Context;
15 let mut conflict = Conflict::default();
16 for l in file.lines() {
17 if l.len() >= 7 {
18 match &l[..7] {
19 "<<<<<<<" => {
20 if state == State::Context {
21 state = State::Left;
22 continue;
23 }
24 }
25 "|||||||" => {
26 if state == State::Left {
27 state = State::Common;
28 continue;
29 }
30 }
31 "=======" => {
32 if state == State::Common {
33 state = State::Right;
34 continue;
35 }
36 }
37 "+++++++" => match l.split_once(' ') {
38 Some((_, "Contents of side #1")) => {
39 if state == State::Left {
40 state = State::Left;
41 continue;
42 }
43 }
44 Some((_, "Contents of side #2")) => {
45 if state == State::Common {
46 state = State::Right;
47 continue;
48 }
49 }
50 _ => (),
51 },
52 "-------" => match l.split_once(' ') {
53 Some((_, "Contents of base")) => {
54 if state == State::Left {
55 state = State::Common;
56 continue;
57 }
58 }
59 _ => (),
60 },
61 ">>>>>>>" => {
62 if state == State::Right {
63 state = State::Context;
64
65 conflict.minimise();
66 write!(output, "{conflict}")?;
67 conflict.clear();
68
69 continue;
70 }
71 }
72 "%%%%%%%" => {
73 eprintln!(
74 "WARN: jj's \"diff\"-style conflict markers are not \
75 supported. Set conflict-marker-style=\"snapshot\"."
76 );
77 }
78 _ => (),
79 }
80 }
81 match state {
82 State::Left => conflict.left.push(l.to_string()),
83 State::Common => conflict.common.push(l.to_string()),
84 State::Right => conflict.right.push(l.to_string()),
85 State::Context => writeln!(output, "{l}")?,
86 }
87 }
88 match state {
89 State::Context => (),
90 State::Left => {
91 writeln!(output, "<<<<<<<")?;
92 for l in conflict.left {
93 writeln!(output, "{l}")?;
94 }
95 }
96 State::Common => {
97 writeln!(output, "<<<<<<<")?;
98 for l in conflict.left {
99 writeln!(output, "{l}")?;
100 }
101 writeln!(output, "|||||||")?;
102 for l in conflict.common {
103 writeln!(output, "{l}")?;
104 }
105 }
106 State::Right => {
107 writeln!(output, "<<<<<<<")?;
108 for l in conflict.left {
109 writeln!(output, "{l}")?;
110 }
111 writeln!(output, "|||||||")?;
112 for l in conflict.common {
113 writeln!(output, "{l}")?;
114 }
115 writeln!(output, "=======")?;
116 for l in conflict.right {
117 writeln!(output, "{l}")?;
118 }
119 }
120 }
121 if let Some(c) = file.as_bytes().last() {
122 if *c != b'\n' {
123 output.remove(output.len() - 1);
124 }
125 }
126 Ok(output)
127}
128
129#[derive(Default, Debug, Clone)]
130struct Conflict {
131 pre: Vec<String>,
132 left: Vec<String>,
133 common: Vec<String>,
134 right: Vec<String>,
135 post: Vec<String>,
136}
137
138impl Display for Conflict {
139 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
140 for l in &self.pre {
141 writeln!(f, "{l}")?;
142 }
143 if !self.is_resolved() {
144 writeln!(f, "<<<<<<<")?;
145 for l in &self.left {
146 writeln!(f, "{l}")?;
147 }
148 writeln!(f, "|||||||")?;
149 for l in &self.common {
150 writeln!(f, "{l}")?;
151 }
152 writeln!(f, "=======")?;
153 for l in &self.right {
154 writeln!(f, "{l}")?;
155 }
156 writeln!(f, ">>>>>>>")?;
157 }
158 for l in &self.post {
159 writeln!(f, "{l}")?;
160 }
161 Ok(())
162 }
163}
164
165impl Conflict {
166 fn minimise(&mut self) {
167 let mut prefix = 0;
168 for ((l, c), r) in self
169 .left
170 .iter()
171 .zip(self.common.iter())
172 .zip(self.right.iter())
173 {
174 if l == c && c == r {
175 prefix += 1;
176 } else {
177 break;
178 }
179 }
180 self.pre.extend(self.left.drain(..prefix));
181 self.common.drain(..prefix);
182 self.right.drain(..prefix);
183
184 let mut suffix = 0;
185 for ((l, c), r) in self
186 .left
187 .iter()
188 .rev()
189 .zip(self.common.iter().rev())
190 .zip(self.right.iter().rev())
191 {
192 if l == c && c == r {
193 suffix += 1;
194 } else {
195 break;
196 }
197 }
198 self.post
199 .extend(self.left.drain(self.left.len() - suffix..));
200 self.common.drain(self.common.len() - suffix..);
201 self.right.drain(self.right.len() - suffix..);
202
203 if self.left == self.common {
204 self.pre.extend(self.right.drain(..));
205 self.left.clear();
206 self.common.clear();
207 }
208 if self.right == self.common {
209 self.pre.extend(self.left.drain(..));
210 self.right.clear();
211 self.common.clear();
212 }
213 }
214
215 fn is_resolved(&self) -> bool {
216 self.left.is_empty() && self.common.is_empty() && self.right.is_empty()
217 }
218
219 fn clear(&mut self) {
220 self.pre.clear();
221 self.left.clear();
222 self.common.clear();
223 self.right.clear();
224 self.post.clear();
225 }
226}