Mercurial > jhg
comparison src/org/tmatesoft/hg/repo/HgBlameFacility.java @ 562:6fbca6506bb5
Allow HgBlameFacility.Inspector (former BlockInspector) to throw an exception
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Thu, 28 Feb 2013 15:57:04 +0100 |
parents | d3c71498919c |
children | 8ed4f4f4f0a6 |
comparison
equal
deleted
inserted
replaced
561:d3c71498919c | 562:6fbca6506bb5 |
---|---|
21 | 21 |
22 import java.util.BitSet; | 22 import java.util.BitSet; |
23 import java.util.LinkedList; | 23 import java.util.LinkedList; |
24 import java.util.ListIterator; | 24 import java.util.ListIterator; |
25 | 25 |
26 import org.tmatesoft.hg.core.HgCallbackTargetException; | |
26 import org.tmatesoft.hg.core.HgIterateDirection; | 27 import org.tmatesoft.hg.core.HgIterateDirection; |
27 import org.tmatesoft.hg.core.Nodeid; | 28 import org.tmatesoft.hg.core.Nodeid; |
28 import org.tmatesoft.hg.internal.ByteArrayChannel; | 29 import org.tmatesoft.hg.internal.ByteArrayChannel; |
29 import org.tmatesoft.hg.internal.Callback; | 30 import org.tmatesoft.hg.internal.Callback; |
30 import org.tmatesoft.hg.internal.DiffHelper; | 31 import org.tmatesoft.hg.internal.DiffHelper; |
49 public final class HgBlameFacility { | 50 public final class HgBlameFacility { |
50 | 51 |
51 /** | 52 /** |
52 * mimic 'hg diff -r clogRevIndex1 -r clogRevIndex2' | 53 * mimic 'hg diff -r clogRevIndex1 -r clogRevIndex2' |
53 */ | 54 */ |
54 public void diff(HgDataFile df, int clogRevIndex1, int clogRevIndex2, BlockInspector insp) { | 55 public void diff(HgDataFile df, int clogRevIndex1, int clogRevIndex2, Inspector insp) throws HgCallbackTargetException { |
55 int fileRevIndex1 = fileRevIndex(df, clogRevIndex1); | 56 int fileRevIndex1 = fileRevIndex(df, clogRevIndex1); |
56 int fileRevIndex2 = fileRevIndex(df, clogRevIndex2); | 57 int fileRevIndex2 = fileRevIndex(df, clogRevIndex2); |
57 FileLinesCache fileInfoCache = new FileLinesCache(df, 5); | 58 FileLinesCache fileInfoCache = new FileLinesCache(df, 5); |
58 LineSequence c1 = fileInfoCache.lines(fileRevIndex1); | 59 LineSequence c1 = fileInfoCache.lines(fileRevIndex1); |
59 LineSequence c2 = fileInfoCache.lines(fileRevIndex2); | 60 LineSequence c2 = fileInfoCache.lines(fileRevIndex2); |
60 DiffHelper<LineSequence> pg = new DiffHelper<LineSequence>(); | 61 DiffHelper<LineSequence> pg = new DiffHelper<LineSequence>(); |
61 pg.init(c1, c2); | 62 pg.init(c1, c2); |
62 pg.findMatchingBlocks(new BlameBlockInspector(fileRevIndex2, insp, clogRevIndex1, clogRevIndex2)); | 63 BlameBlockInspector bbi = new BlameBlockInspector(fileRevIndex2, insp, clogRevIndex1, clogRevIndex2); |
64 pg.findMatchingBlocks(bbi); | |
65 bbi.checkErrors(); | |
63 } | 66 } |
64 | 67 |
65 /** | 68 /** |
66 * Walk file history up to revision at given changeset and report changes for each revision | 69 * Walk file history up to revision at given changeset and report changes for each revision |
67 */ | 70 */ |
68 public void annotate(HgDataFile df, int changelogRevisionIndex, BlockInspector insp, HgIterateDirection iterateOrder) { | 71 public void annotate(HgDataFile df, int changelogRevisionIndex, Inspector insp, HgIterateDirection iterateOrder) throws HgCallbackTargetException { |
69 if (!df.exists()) { | 72 if (!df.exists()) { |
70 return; | 73 return; |
71 } | 74 } |
72 // Note, changelogRevisionIndex may be TIP, while #implAnnotateChange doesn't tolerate constants | 75 // Note, changelogRevisionIndex may be TIP, while #implAnnotateChange doesn't tolerate constants |
73 // | 76 // |
120 } | 123 } |
121 } | 124 } |
122 | 125 |
123 /** | 126 /** |
124 * Annotates changes of the file against its parent(s). | 127 * Annotates changes of the file against its parent(s). |
125 * Unlike {@link #annotate(HgDataFile, int, BlockInspector, HgIterateDirection)}, doesn't | 128 * Unlike {@link #annotate(HgDataFile, int, Inspector, HgIterateDirection)}, doesn't |
126 * walk file history, looks at the specified revision only. Handles both parents (if merge revision). | 129 * walk file history, looks at the specified revision only. Handles both parents (if merge revision). |
127 */ | 130 */ |
128 public void annotateSingleRevision(HgDataFile df, int changelogRevisionIndex, BlockInspector insp) { | 131 public void annotateSingleRevision(HgDataFile df, int changelogRevisionIndex, Inspector insp) throws HgCallbackTargetException { |
129 // TODO detect if file is text/binary (e.g. looking for chars < ' ' and not \t\r\n\f | 132 // TODO detect if file is text/binary (e.g. looking for chars < ' ' and not \t\r\n\f |
130 int fileRevIndex = fileRevIndex(df, changelogRevisionIndex); | 133 int fileRevIndex = fileRevIndex(df, changelogRevisionIndex); |
131 int[] fileRevParents = new int[2]; | 134 int[] fileRevParents = new int[2]; |
132 df.parents(fileRevIndex, fileRevParents, null, null); | 135 df.parents(fileRevIndex, fileRevParents, null, null); |
133 if (changelogRevisionIndex == TIP) { | 136 if (changelogRevisionIndex == TIP) { |
134 changelogRevisionIndex = df.getChangesetRevisionIndex(fileRevIndex); | 137 changelogRevisionIndex = df.getChangesetRevisionIndex(fileRevIndex); |
135 } | 138 } |
136 implAnnotateChange(new FileLinesCache(df, 5), changelogRevisionIndex, fileRevIndex, fileRevParents, insp); | 139 implAnnotateChange(new FileLinesCache(df, 5), changelogRevisionIndex, fileRevIndex, fileRevParents, insp); |
137 } | 140 } |
138 | 141 |
139 private void implAnnotateChange(FileLinesCache fl, int csetRevIndex, int fileRevIndex, int[] fileParentRevs, BlockInspector insp) { | 142 private void implAnnotateChange(FileLinesCache fl, int csetRevIndex, int fileRevIndex, int[] fileParentRevs, Inspector insp) throws HgCallbackTargetException { |
140 final LineSequence fileRevLines = fl.lines(fileRevIndex); | 143 final LineSequence fileRevLines = fl.lines(fileRevIndex); |
141 if (fileParentRevs[0] != NO_REVISION && fileParentRevs[1] != NO_REVISION) { | 144 if (fileParentRevs[0] != NO_REVISION && fileParentRevs[1] != NO_REVISION) { |
142 LineSequence p1Lines = fl.lines(fileParentRevs[0]); | 145 LineSequence p1Lines = fl.lines(fileParentRevs[0]); |
143 LineSequence p2Lines = fl.lines(fileParentRevs[1]); | 146 LineSequence p2Lines = fl.lines(fileParentRevs[1]); |
144 int p1ClogIndex = fl.getChangesetRevisionIndex(fileParentRevs[0]); | 147 int p1ClogIndex = fl.getChangesetRevisionIndex(fileParentRevs[0]); |
150 // | 153 // |
151 pg.init(p1Lines); | 154 pg.init(p1Lines); |
152 BlameBlockInspector bbi = new BlameBlockInspector(fileRevIndex, insp, p1ClogIndex, csetRevIndex); | 155 BlameBlockInspector bbi = new BlameBlockInspector(fileRevIndex, insp, p1ClogIndex, csetRevIndex); |
153 bbi.setMergeParent2(p2MergeCommon, p2ClogIndex); | 156 bbi.setMergeParent2(p2MergeCommon, p2ClogIndex); |
154 pg.findMatchingBlocks(bbi); | 157 pg.findMatchingBlocks(bbi); |
158 bbi.checkErrors(); | |
155 } else if (fileParentRevs[0] == fileParentRevs[1]) { | 159 } else if (fileParentRevs[0] == fileParentRevs[1]) { |
156 // may be equal iff both are unset | 160 // may be equal iff both are unset |
157 assert fileParentRevs[0] == NO_REVISION; | 161 assert fileParentRevs[0] == NO_REVISION; |
158 // everything added | 162 // everything added |
159 BlameBlockInspector bbi = new BlameBlockInspector(fileRevIndex, insp, NO_REVISION, csetRevIndex); | 163 BlameBlockInspector bbi = new BlameBlockInspector(fileRevIndex, insp, NO_REVISION, csetRevIndex); |
160 bbi.begin(LineSequence.newlines(new byte[0]), fileRevLines); | 164 bbi.begin(LineSequence.newlines(new byte[0]), fileRevLines); |
161 bbi.match(0, fileRevLines.chunkCount()-1, 0); | 165 bbi.match(0, fileRevLines.chunkCount()-1, 0); |
162 bbi.end(); | 166 bbi.end(); |
167 bbi.checkErrors(); | |
163 } else { | 168 } else { |
164 int soleParent = fileParentRevs[0] == NO_REVISION ? fileParentRevs[1] : fileParentRevs[0]; | 169 int soleParent = fileParentRevs[0] == NO_REVISION ? fileParentRevs[1] : fileParentRevs[0]; |
165 assert soleParent != NO_REVISION; | 170 assert soleParent != NO_REVISION; |
166 LineSequence parentLines = fl.lines(soleParent); | 171 LineSequence parentLines = fl.lines(soleParent); |
167 | 172 |
168 int parentChangesetRevIndex = fl.getChangesetRevisionIndex(soleParent); | 173 int parentChangesetRevIndex = fl.getChangesetRevisionIndex(soleParent); |
169 DiffHelper<LineSequence> pg = new DiffHelper<LineSequence>(); | 174 DiffHelper<LineSequence> pg = new DiffHelper<LineSequence>(); |
170 pg.init(parentLines, fileRevLines); | 175 pg.init(parentLines, fileRevLines); |
171 pg.findMatchingBlocks(new BlameBlockInspector(fileRevIndex, insp, parentChangesetRevIndex, csetRevIndex)); | 176 BlameBlockInspector bbi = new BlameBlockInspector(fileRevIndex, insp, parentChangesetRevIndex, csetRevIndex); |
177 pg.findMatchingBlocks(bbi); | |
178 bbi.checkErrors(); | |
172 } | 179 } |
173 } | 180 } |
174 | 181 |
175 private static int fileRevIndex(HgDataFile df, int csetRevIndex) { | 182 private static int fileRevIndex(HgDataFile df, int csetRevIndex) { |
176 Nodeid fileRev = df.getRepo().getManifest().getFileRevision(csetRevIndex, df.getPath()); | 183 Nodeid fileRev = df.getRepo().getManifest().getFileRevision(csetRevIndex, df.getPath()); |
245 * | 252 * |
246 * In case more information about annotated revision is needed, inspector instances may supply | 253 * In case more information about annotated revision is needed, inspector instances may supply |
247 * {@link RevisionDescriptor.Recipient} through {@link Adaptable}. | 254 * {@link RevisionDescriptor.Recipient} through {@link Adaptable}. |
248 */ | 255 */ |
249 @Callback | 256 @Callback |
250 public interface BlockInspector { | 257 public interface Inspector { |
251 void same(EqualBlock block); | 258 void same(EqualBlock block) throws HgCallbackTargetException; |
252 void added(AddBlock block); | 259 void added(AddBlock block) throws HgCallbackTargetException; |
253 void changed(ChangeBlock block); | 260 void changed(ChangeBlock block) throws HgCallbackTargetException; |
254 void deleted(DeleteBlock block); | 261 void deleted(DeleteBlock block) throws HgCallbackTargetException; |
262 } | |
263 | |
264 /** | |
265 * No need to keep "Block" prefix as long as there's only one {@link Inspector} | |
266 */ | |
267 @Deprecated | |
268 public interface BlockInspector extends Inspector { | |
255 } | 269 } |
256 | 270 |
257 /** | 271 /** |
258 * Represents content of a block, either as a sequence of bytes or a | 272 * Represents content of a block, either as a sequence of bytes or a |
259 * sequence of smaller blocks (lines), if appropriate (according to usage context). | 273 * sequence of smaller blocks (lines), if appropriate (according to usage context). |
281 int elementCount(); | 295 int elementCount(); |
282 byte[] asArray(); | 296 byte[] asArray(); |
283 } | 297 } |
284 | 298 |
285 /** | 299 /** |
286 * {@link BlockInspector} may optionally request extra information about revisions | 300 * {@link Inspector} may optionally request extra information about revisions |
287 * being inspected, denoting itself as a {@link RevisionDescriptor.Recipient}. This class | 301 * being inspected, denoting itself as a {@link RevisionDescriptor.Recipient}. This class |
288 * provides complete information about file revision under annotation now. | 302 * provides complete information about file revision under annotation now. |
289 */ | 303 */ |
290 public interface RevisionDescriptor { | 304 public interface RevisionDescriptor { |
291 /** | 305 /** |
328 @Callback | 342 @Callback |
329 public interface Recipient { | 343 public interface Recipient { |
330 /** | 344 /** |
331 * Comes prior to any change {@link Block blocks} | 345 * Comes prior to any change {@link Block blocks} |
332 */ | 346 */ |
333 void start(RevisionDescriptor revisionDescription); | 347 void start(RevisionDescriptor revisionDescription) throws HgCallbackTargetException; |
334 /** | 348 /** |
335 * Comes after all change {@link Block blocks} were dispatched | 349 * Comes after all change {@link Block blocks} were dispatched |
336 */ | 350 */ |
337 void done(RevisionDescriptor revisionDescription); | 351 void done(RevisionDescriptor revisionDescription) throws HgCallbackTargetException; |
338 } | 352 } |
339 } | 353 } |
340 | 354 |
341 /** | 355 /** |
342 * Each change block comes from a single origin, blocks that are result of a merge | 356 * Each change block comes from a single origin, blocks that are result of a merge |
392 } | 406 } |
393 public interface ChangeBlock extends AddBlock, DeleteBlock { | 407 public interface ChangeBlock extends AddBlock, DeleteBlock { |
394 } | 408 } |
395 | 409 |
396 private static class BlameBlockInspector extends DiffHelper.DeltaInspector<LineSequence> { | 410 private static class BlameBlockInspector extends DiffHelper.DeltaInspector<LineSequence> { |
397 private final BlockInspector insp; | 411 private final Inspector insp; |
398 private final int csetOrigin; | 412 private final int csetOrigin; |
399 private final int csetTarget; | 413 private final int csetTarget; |
400 private EqualBlocksCollector p2MergeCommon; | 414 private EqualBlocksCollector p2MergeCommon; |
401 private int csetMergeParent; | 415 private int csetMergeParent; |
402 private IntVector mergeRanges; | 416 private IntVector mergeRanges; |
403 private final AnnotateRev annotatedRevision; | 417 private final AnnotateRev annotatedRevision; |
404 | 418 private HgCallbackTargetException error; |
405 public BlameBlockInspector(int fileRevIndex, BlockInspector inspector, int originCset, int targetCset) { | 419 |
420 public BlameBlockInspector(int fileRevIndex, Inspector inspector, int originCset, int targetCset) { | |
406 assert inspector != null; | 421 assert inspector != null; |
407 insp = inspector; | 422 insp = inspector; |
408 annotatedRevision = new AnnotateRev(); | 423 annotatedRevision = new AnnotateRev(); |
409 annotatedRevision.set(fileRevIndex); | 424 annotatedRevision.set(fileRevIndex); |
410 csetOrigin = originCset; | 425 csetOrigin = originCset; |
418 } | 433 } |
419 | 434 |
420 @Override | 435 @Override |
421 public void begin(LineSequence s1, LineSequence s2) { | 436 public void begin(LineSequence s1, LineSequence s2) { |
422 super.begin(s1, s2); | 437 super.begin(s1, s2); |
438 if (shallStop()) { | |
439 return; | |
440 } | |
423 ContentBlock originContent = new ContentBlock(s1); | 441 ContentBlock originContent = new ContentBlock(s1); |
424 ContentBlock targetContent = new ContentBlock(s2); | 442 ContentBlock targetContent = new ContentBlock(s2); |
425 annotatedRevision.set(originContent, targetContent); | 443 annotatedRevision.set(originContent, targetContent); |
426 annotatedRevision.set(csetOrigin, csetTarget, p2MergeCommon != null ? csetMergeParent : NO_REVISION); | 444 annotatedRevision.set(csetOrigin, csetTarget, p2MergeCommon != null ? csetMergeParent : NO_REVISION); |
427 Recipient curious = Adaptable.Factory.getAdapter(insp, Recipient.class, null); | 445 Recipient curious = Adaptable.Factory.getAdapter(insp, Recipient.class, null); |
428 if (curious != null) { | 446 if (curious != null) { |
429 curious.start(annotatedRevision); | 447 try { |
448 curious.start(annotatedRevision); | |
449 } catch (HgCallbackTargetException ex) { | |
450 error = ex; | |
451 } | |
430 } | 452 } |
431 } | 453 } |
432 | 454 |
433 @Override | 455 @Override |
434 public void end() { | 456 public void end() { |
435 super.end(); | 457 super.end(); |
458 if (shallStop()) { | |
459 return; | |
460 } | |
436 Recipient curious = Adaptable.Factory.getAdapter(insp, Recipient.class, null); | 461 Recipient curious = Adaptable.Factory.getAdapter(insp, Recipient.class, null); |
437 if (curious != null) { | 462 if (curious != null) { |
438 curious.done(annotatedRevision); | 463 try { |
464 curious.done(annotatedRevision); | |
465 } catch (HgCallbackTargetException ex) { | |
466 error = ex; | |
467 } | |
439 } | 468 } |
440 p2MergeCommon = null; | 469 p2MergeCommon = null; |
441 } | 470 } |
442 | 471 |
443 @Override | 472 @Override |
444 protected void changed(int s1From, int s1To, int s2From, int s2To) { | 473 protected void changed(int s1From, int s1To, int s2From, int s2To) { |
445 if (p2MergeCommon != null) { | 474 if (shallStop()) { |
446 mergeRanges.clear(); | 475 return; |
447 p2MergeCommon.combineAndMarkRangesWithTarget(s2From, s2To - s2From, csetOrigin, csetMergeParent, mergeRanges); | 476 } |
448 | 477 try { |
449 /* | 478 if (p2MergeCommon != null) { |
450 * Usecases, how it USED TO BE initially: | 479 mergeRanges.clear(); |
451 * 3 lines changed to 10 lines. range of 10 lines breaks down to 2 from p2, 3 from p1, and 5 from p2. | 480 p2MergeCommon.combineAndMarkRangesWithTarget(s2From, s2To - s2From, csetOrigin, csetMergeParent, mergeRanges); |
452 * We report: 2 lines changed to 2(p2), then 1 line changed with 3(p1) and 5 lines added from p2. | 481 |
453 * | 482 /* |
454 * 10 lines changed to 3 lines, range of 3 lines breaks down to 2 line from p1 and 1 line from p2. | 483 * Usecases, how it USED TO BE initially: |
455 * We report: 2 lines changed to 2(p1) and 8 lines changed to 1(p2) | 484 * 3 lines changed to 10 lines. range of 10 lines breaks down to 2 from p2, 3 from p1, and 5 from p2. |
456 * | 485 * We report: 2 lines changed to 2(p2), then 1 line changed with 3(p1) and 5 lines added from p2. |
457 * NOW, lines from p2 are always reported as pure add (since we need their insertion point to be in p2, not in p1) | 486 * |
458 * and we try to consume p1 changes as soon as we see first p1's range | 487 * 10 lines changed to 3 lines, range of 3 lines breaks down to 2 line from p1 and 1 line from p2. |
459 */ | 488 * We report: 2 lines changed to 2(p1) and 8 lines changed to 1(p2) |
460 int s1TotalLines = s1To - s1From, s1ConsumedLines = 0, s1Start = s1From; | 489 * |
461 | 490 * NOW, lines from p2 are always reported as pure add (since we need their insertion point to be in p2, not in p1) |
462 for (int i = 0; i < mergeRanges.size(); i += 3) { | 491 * and we try to consume p1 changes as soon as we see first p1's range |
463 final int rangeOrigin = mergeRanges.get(i); | 492 */ |
464 final int rangeStart = mergeRanges.get(i+1); | 493 int s1TotalLines = s1To - s1From, s1ConsumedLines = 0, s1Start = s1From; |
465 final int rangeLen = mergeRanges.get(i+2); | 494 |
466 final boolean lastRange = i+3 >= mergeRanges.size(); | 495 for (int i = 0; i < mergeRanges.size(); i += 3) { |
467 final int s1LinesLeft = s1TotalLines - s1ConsumedLines; | 496 final int rangeOrigin = mergeRanges.get(i); |
468 // how many lines we may report as changed (don't use more than in range unless it's the very last range) | 497 final int rangeStart = mergeRanges.get(i+1); |
469 final int s1LinesToBorrow = lastRange ? s1LinesLeft : Math.min(s1LinesLeft, rangeLen); | 498 final int rangeLen = mergeRanges.get(i+2); |
470 if (rangeOrigin != csetMergeParent && s1LinesToBorrow > 0) { | 499 final boolean lastRange = i+3 >= mergeRanges.size(); |
471 ChangeBlockImpl block = getChangeBlock(s1Start, s1LinesToBorrow, rangeStart, rangeLen); | 500 final int s1LinesLeft = s1TotalLines - s1ConsumedLines; |
472 block.setOriginAndTarget(rangeOrigin, csetTarget); | 501 // how many lines we may report as changed (don't use more than in range unless it's the very last range) |
473 insp.changed(block); | 502 final int s1LinesToBorrow = lastRange ? s1LinesLeft : Math.min(s1LinesLeft, rangeLen); |
474 s1ConsumedLines += s1LinesToBorrow; | 503 if (rangeOrigin != csetMergeParent && s1LinesToBorrow > 0) { |
475 s1Start += s1LinesToBorrow; | 504 ChangeBlockImpl block = getChangeBlock(s1Start, s1LinesToBorrow, rangeStart, rangeLen); |
476 } else { | 505 block.setOriginAndTarget(rangeOrigin, csetTarget); |
477 int blockInsPoint = rangeOrigin != csetMergeParent ? s1Start : p2MergeCommon.reverseMapLine(rangeStart); | 506 insp.changed(block); |
478 ChangeBlockImpl block = getAddBlock(rangeStart, rangeLen, blockInsPoint); | 507 s1ConsumedLines += s1LinesToBorrow; |
508 s1Start += s1LinesToBorrow; | |
509 } else { | |
510 int blockInsPoint = rangeOrigin != csetMergeParent ? s1Start : p2MergeCommon.reverseMapLine(rangeStart); | |
511 ChangeBlockImpl block = getAddBlock(rangeStart, rangeLen, blockInsPoint); | |
512 block.setOriginAndTarget(rangeOrigin, csetTarget); | |
513 insp.added(block); | |
514 } | |
515 } | |
516 if (s1ConsumedLines != s1TotalLines) { | |
517 assert s1ConsumedLines < s1TotalLines : String.format("Expected to process %d lines, but actually was %d", s1TotalLines, s1ConsumedLines); | |
518 // either there were no ranges from p1, whole s2From..s2To range came from p2, shall report as deleted | |
519 // or the ranges found were not enough to consume whole s2From..s2To | |
520 // The "deletion point" is shifted to the end of last csetOrigin->csetTarget change | |
521 int s2DeletePoint = s2From + s1ConsumedLines; | |
522 ChangeBlockImpl block = new ChangeBlockImpl(annotatedRevision.origin, null, s1Start, s1To - s1Start, -1, -1, -1, s2DeletePoint); | |
523 block.setOriginAndTarget(csetOrigin, csetTarget); | |
524 insp.deleted(block); | |
525 } | |
526 } else { | |
527 ChangeBlockImpl block = getChangeBlock(s1From, s1To - s1From, s2From, s2To - s2From); | |
528 block.setOriginAndTarget(csetOrigin, csetTarget); | |
529 insp.changed(block); | |
530 } | |
531 } catch (HgCallbackTargetException ex) { | |
532 error = ex; | |
533 } | |
534 } | |
535 | |
536 @Override | |
537 protected void added(int s1InsertPoint, int s2From, int s2To) { | |
538 if (shallStop()) { | |
539 return; | |
540 } | |
541 try { | |
542 if (p2MergeCommon != null) { | |
543 mergeRanges.clear(); | |
544 p2MergeCommon.combineAndMarkRangesWithTarget(s2From, s2To - s2From, csetOrigin, csetMergeParent, mergeRanges); | |
545 int insPoint = s1InsertPoint; // track changes to insertion point | |
546 for (int i = 0; i < mergeRanges.size(); i += 3) { | |
547 int rangeOrigin = mergeRanges.get(i); | |
548 int rangeStart = mergeRanges.get(i+1); | |
549 int rangeLen = mergeRanges.get(i+2); | |
550 ChangeBlockImpl block = getAddBlock(rangeStart, rangeLen, insPoint); | |
479 block.setOriginAndTarget(rangeOrigin, csetTarget); | 551 block.setOriginAndTarget(rangeOrigin, csetTarget); |
480 insp.added(block); | 552 insp.added(block); |
553 // indicate insPoint moved down number of lines we just reported | |
554 insPoint += rangeLen; | |
481 } | 555 } |
556 } else { | |
557 ChangeBlockImpl block = getAddBlock(s2From, s2To - s2From, s1InsertPoint); | |
558 block.setOriginAndTarget(csetOrigin, csetTarget); | |
559 insp.added(block); | |
482 } | 560 } |
483 if (s1ConsumedLines != s1TotalLines) { | 561 } catch (HgCallbackTargetException ex) { |
484 assert s1ConsumedLines < s1TotalLines : String.format("Expected to process %d lines, but actually was %d", s1TotalLines, s1ConsumedLines); | 562 error = ex; |
485 // either there were no ranges from p1, whole s2From..s2To range came from p2, shall report as deleted | |
486 // or the ranges found were not enough to consume whole s2From..s2To | |
487 // The "deletion point" is shifted to the end of last csetOrigin->csetTarget change | |
488 int s2DeletePoint = s2From + s1ConsumedLines; | |
489 ChangeBlockImpl block = new ChangeBlockImpl(annotatedRevision.origin, null, s1Start, s1To - s1Start, -1, -1, -1, s2DeletePoint); | |
490 block.setOriginAndTarget(csetOrigin, csetTarget); | |
491 insp.deleted(block); | |
492 } | |
493 } else { | |
494 ChangeBlockImpl block = getChangeBlock(s1From, s1To - s1From, s2From, s2To - s2From); | |
495 block.setOriginAndTarget(csetOrigin, csetTarget); | |
496 insp.changed(block); | |
497 } | |
498 } | |
499 | |
500 @Override | |
501 protected void added(int s1InsertPoint, int s2From, int s2To) { | |
502 if (p2MergeCommon != null) { | |
503 mergeRanges.clear(); | |
504 p2MergeCommon.combineAndMarkRangesWithTarget(s2From, s2To - s2From, csetOrigin, csetMergeParent, mergeRanges); | |
505 int insPoint = s1InsertPoint; // track changes to insertion point | |
506 for (int i = 0; i < mergeRanges.size(); i += 3) { | |
507 int rangeOrigin = mergeRanges.get(i); | |
508 int rangeStart = mergeRanges.get(i+1); | |
509 int rangeLen = mergeRanges.get(i+2); | |
510 ChangeBlockImpl block = getAddBlock(rangeStart, rangeLen, insPoint); | |
511 block.setOriginAndTarget(rangeOrigin, csetTarget); | |
512 insp.added(block); | |
513 // indicate insPoint moved down number of lines we just reported | |
514 insPoint += rangeLen; | |
515 } | |
516 } else { | |
517 ChangeBlockImpl block = getAddBlock(s2From, s2To - s2From, s1InsertPoint); | |
518 block.setOriginAndTarget(csetOrigin, csetTarget); | |
519 insp.added(block); | |
520 } | 563 } |
521 } | 564 } |
522 | 565 |
523 @Override | 566 @Override |
524 protected void deleted(int s2DeletePoint, int s1From, int s1To) { | 567 protected void deleted(int s2DeletePoint, int s1From, int s1To) { |
525 ChangeBlockImpl block = new ChangeBlockImpl(annotatedRevision.origin, null, s1From, s1To - s1From, -1, -1, -1, s2DeletePoint); | 568 if (shallStop()) { |
526 block.setOriginAndTarget(csetOrigin, csetTarget); | 569 return; |
527 insp.deleted(block); | 570 } |
571 try { | |
572 ChangeBlockImpl block = new ChangeBlockImpl(annotatedRevision.origin, null, s1From, s1To - s1From, -1, -1, -1, s2DeletePoint); | |
573 block.setOriginAndTarget(csetOrigin, csetTarget); | |
574 insp.deleted(block); | |
575 } catch (HgCallbackTargetException ex) { | |
576 error = ex; | |
577 } | |
528 } | 578 } |
529 | 579 |
530 @Override | 580 @Override |
531 protected void unchanged(int s1From, int s2From, int length) { | 581 protected void unchanged(int s1From, int s2From, int length) { |
532 EqualBlockImpl block = new EqualBlockImpl(s1From, s2From, length, annotatedRevision.target); | 582 if (shallStop()) { |
533 block.setOriginAndTarget(csetOrigin, csetTarget); | 583 return; |
534 insp.same(block); | 584 } |
585 try { | |
586 EqualBlockImpl block = new EqualBlockImpl(s1From, s2From, length, annotatedRevision.target); | |
587 block.setOriginAndTarget(csetOrigin, csetTarget); | |
588 insp.same(block); | |
589 } catch (HgCallbackTargetException ex) { | |
590 error = ex; | |
591 } | |
592 } | |
593 | |
594 void checkErrors() throws HgCallbackTargetException { | |
595 if (error != null) { | |
596 throw error; | |
597 } | |
598 } | |
599 | |
600 private boolean shallStop() { | |
601 return error != null; | |
535 } | 602 } |
536 | 603 |
537 private ChangeBlockImpl getAddBlock(int start, int len, int insPoint) { | 604 private ChangeBlockImpl getAddBlock(int start, int len, int insPoint) { |
538 return new ChangeBlockImpl(null, annotatedRevision.target, -1, -1, start, len, insPoint, -1); | 605 return new ChangeBlockImpl(null, annotatedRevision.target, -1, -1, start, len, insPoint, -1); |
539 } | 606 } |