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 } |
