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 }