|
22 | 22 | import difflib.algorithm.DiffAlgorithm; |
23 | 23 | import difflib.algorithm.DiffException; |
24 | 24 | import difflib.algorithm.myers.MyersDiff; |
25 | | -import difflib.patch.ChangeDelta; |
26 | | -import difflib.patch.Chunk; |
27 | 25 | import difflib.patch.Delta; |
28 | 26 | import difflib.patch.Equalizer; |
29 | 27 | import difflib.patch.Patch; |
30 | 28 | import difflib.patch.PatchFailedException; |
31 | | -import java.util.ArrayList; |
32 | 29 | import java.util.Collections; |
33 | 30 | import java.util.LinkedList; |
34 | 31 | import java.util.List; |
35 | | -import java.util.regex.Matcher; |
36 | | -import java.util.regex.Pattern; |
37 | 32 | import static java.util.stream.Collectors.joining; |
38 | 33 |
|
39 | 34 | /** |
40 | 35 | * Implements the difference and patching engine |
41 | 36 | * |
42 | 37 | * @author <a href="dm.naumenko@gmail.com">Dmitry Naumenko</a> |
43 | 38 | * @version 0.4.1 |
44 | | - * @param T The type of the compared elements in the 'lines'. |
45 | 39 | */ |
46 | 40 | public final class DiffUtils { |
47 | 41 |
|
48 | | - private static final Pattern UNIFIED_DIFF_CHUNK_REGEXP = Pattern |
49 | | - .compile("^@@\\s+-(?:(\\d+)(?:,(\\d+))?)\\s+\\+(?:(\\d+)(?:,(\\d+))?)\\s+@@$"); |
50 | | - |
51 | 42 | /** |
52 | 43 | * Computes the difference between the original and revised list of elements with default diff |
53 | 44 | * algorithm |
@@ -163,281 +154,6 @@ public static <T> List<T> unpatch(List<T> revised, Patch<T> patch) { |
163 | 154 | return patch.restore(revised); |
164 | 155 | } |
165 | 156 |
|
166 | | - /** |
167 | | - * Parse the given text in unified format and creates the list of deltas for it. |
168 | | - * |
169 | | - * @param diff the text in unified format |
170 | | - * @return the patch with deltas. |
171 | | - */ |
172 | | - public static Patch<String> parseUnifiedDiff(List<String> diff) { |
173 | | - boolean inPrelude = true; |
174 | | - List<String[]> rawChunk = new ArrayList<>(); |
175 | | - Patch<String> patch = new Patch<>(); |
176 | | - |
177 | | - int old_ln = 0, new_ln = 0; |
178 | | - String tag; |
179 | | - String rest; |
180 | | - for (String line : diff) { |
181 | | - // Skip leading lines until after we've seen one starting with '+++' |
182 | | - if (inPrelude) { |
183 | | - if (line.startsWith("+++")) { |
184 | | - inPrelude = false; |
185 | | - } |
186 | | - continue; |
187 | | - } |
188 | | - Matcher m = UNIFIED_DIFF_CHUNK_REGEXP.matcher(line); |
189 | | - if (m.find()) { |
190 | | - // Process the lines in the previous chunk |
191 | | - if (!rawChunk.isEmpty()) { |
192 | | - List<String> oldChunkLines = new ArrayList<>(); |
193 | | - List<String> newChunkLines = new ArrayList<>(); |
194 | | - |
195 | | - for (String[] raw_line : rawChunk) { |
196 | | - tag = raw_line[0]; |
197 | | - rest = raw_line[1]; |
198 | | - if (tag.equals(" ") || tag.equals("-")) { |
199 | | - oldChunkLines.add(rest); |
200 | | - } |
201 | | - if (tag.equals(" ") || tag.equals("+")) { |
202 | | - newChunkLines.add(rest); |
203 | | - } |
204 | | - } |
205 | | - patch.addDelta(new ChangeDelta<>(new Chunk<>( |
206 | | - old_ln - 1, oldChunkLines), new Chunk<>( |
207 | | - new_ln - 1, newChunkLines))); |
208 | | - rawChunk.clear(); |
209 | | - } |
210 | | - // Parse the @@ header |
211 | | - old_ln = m.group(1) == null ? 1 : Integer.parseInt(m.group(1)); |
212 | | - new_ln = m.group(3) == null ? 1 : Integer.parseInt(m.group(3)); |
213 | | - |
214 | | - if (old_ln == 0) { |
215 | | - old_ln += 1; |
216 | | - } |
217 | | - if (new_ln == 0) { |
218 | | - new_ln += 1; |
219 | | - } |
220 | | - } else { |
221 | | - if (line.length() > 0) { |
222 | | - tag = line.substring(0, 1); |
223 | | - rest = line.substring(1); |
224 | | - if (tag.equals(" ") || tag.equals("+") || tag.equals("-")) { |
225 | | - rawChunk.add(new String[]{tag, rest}); |
226 | | - } |
227 | | - } else { |
228 | | - rawChunk.add(new String[]{" ", ""}); |
229 | | - } |
230 | | - } |
231 | | - } |
232 | | - |
233 | | - // Process the lines in the last chunk |
234 | | - if (!rawChunk.isEmpty()) { |
235 | | - List<String> oldChunkLines = new ArrayList<>(); |
236 | | - List<String> newChunkLines = new ArrayList<>(); |
237 | | - |
238 | | - for (String[] raw_line : rawChunk) { |
239 | | - tag = raw_line[0]; |
240 | | - rest = raw_line[1]; |
241 | | - if (tag.equals(" ") || tag.equals("-")) { |
242 | | - oldChunkLines.add(rest); |
243 | | - } |
244 | | - if (tag.equals(" ") || tag.equals("+")) { |
245 | | - newChunkLines.add(rest); |
246 | | - } |
247 | | - } |
248 | | - |
249 | | - patch.addDelta(new ChangeDelta<>(new Chunk<>( |
250 | | - old_ln - 1, oldChunkLines), new Chunk<>(new_ln - 1, |
251 | | - newChunkLines))); |
252 | | - rawChunk.clear(); |
253 | | - } |
254 | | - |
255 | | - return patch; |
256 | | - } |
257 | | - |
258 | | - /** |
259 | | - * generateUnifiedDiff takes a Patch and some other arguments, returning the Unified Diff format |
260 | | - * text representing the Patch. |
261 | | - * |
262 | | - * @param original - Filename of the original (unrevised file) |
263 | | - * @param revised - Filename of the revised file |
264 | | - * @param originalLines - Lines of the original file |
265 | | - * @param patch - Patch created by the diff() function |
266 | | - * @param contextSize - number of lines of context output around each difference in the file. |
267 | | - * @return List of strings representing the Unified Diff representation of the Patch argument. |
268 | | - * @author Bill James (tankerbay@gmail.com) |
269 | | - */ |
270 | | - public static List<String> generateUnifiedDiff(String original, |
271 | | - String revised, List<String> originalLines, Patch<String> patch, |
272 | | - int contextSize) { |
273 | | - if (!patch.getDeltas().isEmpty()) { |
274 | | - List<String> ret = new ArrayList<>(); |
275 | | - ret.add("--- " + original); |
276 | | - ret.add("+++ " + revised); |
277 | | - |
278 | | - List<Delta<String>> patchDeltas = new ArrayList<>( |
279 | | - patch.getDeltas()); |
280 | | - |
281 | | - // code outside the if block also works for single-delta issues. |
282 | | - List<Delta<String>> deltas = new ArrayList<>(); // current |
283 | | - // list |
284 | | - // of |
285 | | - // Delta's to |
286 | | - // process |
287 | | - Delta<String> delta = patchDeltas.get(0); |
288 | | - deltas.add(delta); // add the first Delta to the current set |
289 | | - // if there's more than 1 Delta, we may need to output them together |
290 | | - if (patchDeltas.size() > 1) { |
291 | | - for (int i = 1; i < patchDeltas.size(); i++) { |
292 | | - int position = delta.getOriginal().getPosition(); // store |
293 | | - // the |
294 | | - // current |
295 | | - // position |
296 | | - // of |
297 | | - // the first Delta |
298 | | - |
299 | | - // Check if the next Delta is too close to the current |
300 | | - // position. |
301 | | - // And if it is, add it to the current set |
302 | | - Delta<String> nextDelta = patchDeltas.get(i); |
303 | | - if ((position + delta.getOriginal().size() + contextSize) >= (nextDelta |
304 | | - .getOriginal().getPosition() - contextSize)) { |
305 | | - deltas.add(nextDelta); |
306 | | - } else { |
307 | | - // if it isn't, output the current set, |
308 | | - // then create a new set and add the current Delta to |
309 | | - // it. |
310 | | - List<String> curBlock = processDeltas(originalLines, |
311 | | - deltas, contextSize); |
312 | | - ret.addAll(curBlock); |
313 | | - deltas.clear(); |
314 | | - deltas.add(nextDelta); |
315 | | - } |
316 | | - delta = nextDelta; |
317 | | - } |
318 | | - |
319 | | - } |
320 | | - // don't forget to process the last set of Deltas |
321 | | - List<String> curBlock = processDeltas(originalLines, deltas, |
322 | | - contextSize); |
323 | | - ret.addAll(curBlock); |
324 | | - return ret; |
325 | | - } |
326 | | - return new ArrayList<>(); |
327 | | - } |
328 | | - |
329 | | - /** |
330 | | - * processDeltas takes a list of Deltas and outputs them together in a single block of |
331 | | - * Unified-Diff-format text. |
332 | | - * |
333 | | - * @param origLines - the lines of the original file |
334 | | - * @param deltas - the Deltas to be output as a single block |
335 | | - * @param contextSize - the number of lines of context to place around block |
336 | | - * @return |
337 | | - * @author Bill James (tankerbay@gmail.com) |
338 | | - */ |
339 | | - private static List<String> processDeltas(List<String> origLines, |
340 | | - List<Delta<String>> deltas, int contextSize) { |
341 | | - List<String> buffer = new ArrayList<>(); |
342 | | - int origTotal = 0; // counter for total lines output from Original |
343 | | - int revTotal = 0; // counter for total lines output from Original |
344 | | - int line; |
345 | | - |
346 | | - Delta<String> curDelta = deltas.get(0); |
347 | | - |
348 | | - // NOTE: +1 to overcome the 0-offset Position |
349 | | - int origStart = curDelta.getOriginal().getPosition() + 1 - contextSize; |
350 | | - if (origStart < 1) { |
351 | | - origStart = 1; |
352 | | - } |
353 | | - |
354 | | - int revStart = curDelta.getRevised().getPosition() + 1 - contextSize; |
355 | | - if (revStart < 1) { |
356 | | - revStart = 1; |
357 | | - } |
358 | | - |
359 | | - // find the start of the wrapper context code |
360 | | - int contextStart = curDelta.getOriginal().getPosition() - contextSize; |
361 | | - if (contextStart < 0) { |
362 | | - contextStart = 0; // clamp to the start of the file |
363 | | - } |
364 | | - |
365 | | - // output the context before the first Delta |
366 | | - for (line = contextStart; line < curDelta.getOriginal().getPosition(); line++) { // |
367 | | - buffer.add(" " + origLines.get(line)); |
368 | | - origTotal++; |
369 | | - revTotal++; |
370 | | - } |
371 | | - |
372 | | - // output the first Delta |
373 | | - buffer.addAll(getDeltaText(curDelta)); |
374 | | - origTotal += curDelta.getOriginal().getLines().size(); |
375 | | - revTotal += curDelta.getRevised().getLines().size(); |
376 | | - |
377 | | - int deltaIndex = 1; |
378 | | - while (deltaIndex < deltas.size()) { // for each of the other Deltas |
379 | | - Delta<String> nextDelta = deltas.get(deltaIndex); |
380 | | - int intermediateStart = curDelta.getOriginal().getPosition() |
381 | | - + curDelta.getOriginal().getLines().size(); |
382 | | - for (line = intermediateStart; line < nextDelta.getOriginal() |
383 | | - .getPosition(); line++) { |
384 | | - // output the code between the last Delta and this one |
385 | | - buffer.add(" " + origLines.get(line)); |
386 | | - origTotal++; |
387 | | - revTotal++; |
388 | | - } |
389 | | - buffer.addAll(getDeltaText(nextDelta)); // output the Delta |
390 | | - origTotal += nextDelta.getOriginal().getLines().size(); |
391 | | - revTotal += nextDelta.getRevised().getLines().size(); |
392 | | - curDelta = nextDelta; |
393 | | - deltaIndex++; |
394 | | - } |
395 | | - |
396 | | - // Now output the post-Delta context code, clamping the end of the file |
397 | | - contextStart = curDelta.getOriginal().getPosition() |
398 | | - + curDelta.getOriginal().getLines().size(); |
399 | | - for (line = contextStart; (line < (contextStart + contextSize)) |
400 | | - && (line < origLines.size()); line++) { |
401 | | - buffer.add(" " + origLines.get(line)); |
402 | | - origTotal++; |
403 | | - revTotal++; |
404 | | - } |
405 | | - |
406 | | - // Create and insert the block header, conforming to the Unified Diff |
407 | | - // standard |
408 | | - StringBuffer header = new StringBuffer(); |
409 | | - header.append("@@ -"); |
410 | | - header.append(origStart); |
411 | | - header.append(","); |
412 | | - header.append(origTotal); |
413 | | - header.append(" +"); |
414 | | - header.append(revStart); |
415 | | - header.append(","); |
416 | | - header.append(revTotal); |
417 | | - header.append(" @@"); |
418 | | - buffer.add(0, header.toString()); |
419 | | - |
420 | | - return buffer; |
421 | | - } |
422 | | - |
423 | | - /** |
424 | | - * getDeltaText returns the lines to be added to the Unified Diff text from the Delta parameter |
425 | | - * |
426 | | - * @param delta - the Delta to output |
427 | | - * @return list of String lines of code. |
428 | | - * @author Bill James (tankerbay@gmail.com) |
429 | | - */ |
430 | | - private static List<String> getDeltaText(Delta<String> delta) { |
431 | | - List<String> buffer = new ArrayList<>(); |
432 | | - for (String line : delta.getOriginal().getLines()) { |
433 | | - buffer.add("-" + line); |
434 | | - } |
435 | | - for (String line : delta.getRevised().getLines()) { |
436 | | - buffer.add("+" + line); |
437 | | - } |
438 | | - return buffer; |
439 | | - } |
440 | | - |
441 | 157 | private DiffUtils() { |
442 | 158 | } |
443 | 159 | } |
0 commit comments