Mercurial > hg4j
diff src/org/tmatesoft/hg/internal/AnnotateFacility.java @ 555:e623aa2ca526
Annotate: RevisionDescriptor provides extra knowledge about inspected/annotated revision
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Fri, 22 Feb 2013 19:03:25 +0100 |
parents | a5fd757d1b5d |
children |
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/internal/AnnotateFacility.java Thu Feb 21 21:53:55 2013 +0100 +++ b/src/org/tmatesoft/hg/internal/AnnotateFacility.java Fri Feb 22 19:03:25 2013 +0100 @@ -25,15 +25,18 @@ import org.tmatesoft.hg.core.HgIterateDirection; import org.tmatesoft.hg.core.Nodeid; -import org.tmatesoft.hg.internal.AnnotateFacility.BlockData; +import org.tmatesoft.hg.internal.AnnotateFacility.RevisionDescriptor.Recipient; import org.tmatesoft.hg.internal.DiffHelper.LineSequence; import org.tmatesoft.hg.internal.DiffHelper.LineSequence.ByteChain; import org.tmatesoft.hg.repo.HgDataFile; import org.tmatesoft.hg.repo.HgInvalidStateException; +import org.tmatesoft.hg.repo.HgRepository; +import org.tmatesoft.hg.util.Adaptable; import org.tmatesoft.hg.util.CancelledException; import org.tmatesoft.hg.util.Pair; /** + * Facility with diff/annotate functionality. * * @author Artem Tikhomirov * @author TMate Software Ltd. @@ -55,6 +58,9 @@ pg.findMatchingBlocks(new BlameBlockInspector(insp, clogRevIndex1, clogRevIndex2)); } + /** + * Walk file history up to revision at given changeset and report changes for each revision + */ public void annotate(HgDataFile df, int changelogRevisionIndex, BlockInspector insp, HgIterateDirection iterateOrder) { if (!df.exists()) { return; @@ -107,20 +113,11 @@ } /** - * Annotate file revision, line by line. + * Annotates changes of the file against its parent(s). + * Unlike {@link #annotate(HgDataFile, int, BlockInspector, HgIterateDirection)}, doesn't + * walk file history, looks at the specified revision only. Handles both parents (if merge revision). */ - public void annotate(HgDataFile df, int changelogRevisionIndex, LineInspector insp) { - if (!df.exists()) { - return; - } - FileAnnotation fa = new FileAnnotation(insp); - annotate(df, changelogRevisionIndex, fa, HgIterateDirection.NewToOld); - } - - /** - * Annotates changes of the file against its parent(s) - */ - public void annotateChange(HgDataFile df, int changelogRevisionIndex, BlockInspector insp) { + public void annotateSingleRevision(HgDataFile df, int changelogRevisionIndex, BlockInspector insp) { // TODO detect if file is text/binary (e.g. looking for chars < ' ' and not \t\r\n\f int fileRevIndex = fileRevIndex(df, changelogRevisionIndex); int[] fileRevParents = new int[2]; @@ -233,6 +230,14 @@ } } + /** + * Client's sink for revision differences. + * + * When implemented, clients shall not expect new {@link Block blocks} instances in each call. + * + * In case more information about annotated revision is needed, inspector instances may supply + * {@link RevisionDescriptor.Recipient} through {@link Adaptable}. + */ @Callback public interface BlockInspector { void same(EqualBlock block); @@ -241,13 +246,6 @@ void deleted(DeleteBlock block); } - @Callback - public interface BlockInspectorEx extends BlockInspector { // XXX better name - // XXX perhaps, shall pass object instead of separate values for future extension? - void start(BlockData originContent, BlockData targetContent); - void done(); - } - /** * Represents content of a block, either as a sequence of bytes or a * sequence of smaller blocks (lines), if appropriate (according to usage context). @@ -276,14 +274,65 @@ byte[] asArray(); } + /** + * {@link BlockInspector} may optionally request extra information about revisions + * being inspected, denoting itself as a {@link RevisionDescriptor.Recipient}. This class + * provides complete information about file revision under annotation now. + */ + public interface RevisionDescriptor { + /** + * @return complete source of the diff origin, never <code>null</code> + */ + BlockData origin(); + /** + * @return complete source of the diff target, never <code>null</code> + */ + BlockData target(); + /** + * @return changeset revision index of original file, or {@link HgRepository#NO_REVISION} if it's the very first revision + */ + int originChangesetIndex(); + /** + * @return changeset revision index of the target file + */ + int targetChangesetIndex(); + /** + * @return <code>true</code> if this revision is merge + */ + boolean isMerge(); + /** + * @return changeset revision index of the second, merged parent + */ + int mergeChangesetIndex(); + /** + * @return revision index of the change in file's revlog + */ + int fileRevisionIndex(); + + /** + * Implement to indicate interest in {@link RevisionDescriptor}. + * + * Note, instance of {@link RevisionDescriptor} is the same for + * {@link #start(RevisionDescriptor)} and {@link #done(RevisionDescriptor)} + * methods, and not necessarily a new one (i.e. <code>==</code>) for the next + * revision announced. + */ + @Callback + public interface Recipient { + /** + * Comes prior to any change {@link Block blocks} + */ + void start(RevisionDescriptor revisionDescription); + /** + * Comes after all change {@link Block blocks} were dispatched + */ + void done(RevisionDescriptor revisionDescription); + } + } + public interface Block { int originChangesetIndex(); int targetChangesetIndex(); -// boolean isMergeRevision(); -// int fileRevisionIndex(); -// int originFileRevisionIndex(); -// String[] lines(); -// byte[] data(); } public interface EqualBlock extends Block { @@ -308,32 +357,19 @@ public interface ChangeBlock extends AddBlock, DeleteBlock { } - @Callback - public interface LineInspector { - /** - * Not necessarily invoked sequentially by line numbers - */ - void line(int lineNumber, int changesetRevIndex, LineDescriptor ld); - } - - public interface LineDescriptor { - int totalLines(); - } - - - - static class BlameBlockInspector extends DiffHelper.DeltaInspector<LineSequence> { + private static class BlameBlockInspector extends DiffHelper.DeltaInspector<LineSequence> { private final BlockInspector insp; private final int csetOrigin; private final int csetTarget; private EqualBlocksCollector p2MergeCommon; private int csetMergeParent; private IntVector mergeRanges; - private ContentBlock originContent, targetContent; + private final AnnotateRev annotatedRevision; public BlameBlockInspector(BlockInspector inspector, int originCset, int targetCset) { assert inspector != null; insp = inspector; + annotatedRevision = new AnnotateRev(); csetOrigin = originCset; csetTarget = targetCset; } @@ -347,19 +383,24 @@ @Override public void begin(LineSequence s1, LineSequence s2) { super.begin(s1, s2); - originContent = new ContentBlock(s1); - targetContent = new ContentBlock(s2); - if (insp instanceof BlockInspectorEx) { - ((BlockInspectorEx) insp).start(originContent, targetContent); + ContentBlock originContent = new ContentBlock(s1); + ContentBlock targetContent = new ContentBlock(s2); + annotatedRevision.set(originContent, targetContent); + annotatedRevision.set(csetOrigin, csetTarget, p2MergeCommon != null ? csetMergeParent : NO_REVISION); + Recipient curious = Adaptable.Factory.getAdapter(insp, Recipient.class, null); + if (curious != null) { + curious.start(annotatedRevision); } } @Override public void end() { super.end(); - if(insp instanceof BlockInspectorEx) { - ((BlockInspectorEx) insp).done(); + Recipient curious = Adaptable.Factory.getAdapter(insp, Recipient.class, null); + if (curious != null) { + curious.done(annotatedRevision); } + p2MergeCommon = null; } @Override @@ -387,7 +428,7 @@ // how many lines we may reported as changed (don't use more than in range unless it's the very last range) final int s1LinesToBorrow = lastRange ? s1LinesLeft : Math.min(s1LinesLeft, rangeLen); if (s1LinesToBorrow > 0) { - ChangeBlockImpl block = new ChangeBlockImpl(originContent, targetContent, s1Start, s1LinesToBorrow, rangeStart, rangeLen, s1Start, rangeStart); + ChangeBlockImpl block = getChangeBlock(s1Start, s1LinesToBorrow, rangeStart, rangeLen); block.setOriginAndTarget(rangeOrigin, csetTarget); insp.changed(block); s1ConsumedLines += s1LinesToBorrow; @@ -402,7 +443,7 @@ throw new HgInvalidStateException(String.format("Expected to process %d lines, but actually was %d", s1TotalLines, s1ConsumedLines)); } } else { - ChangeBlockImpl block = new ChangeBlockImpl(originContent, targetContent, s1From, s1To-s1From, s2From, s2To - s2From, s1From, s2From); + ChangeBlockImpl block = getChangeBlock(s1From, s1To-s1From, s2From, s2To - s2From); block.setOriginAndTarget(csetOrigin, csetTarget); insp.changed(block); } @@ -433,24 +474,28 @@ @Override protected void deleted(int s2DeletePoint, int s1From, int s1To) { - ChangeBlockImpl block = new ChangeBlockImpl(originContent, null, s1From, s1To - s1From, -1, -1, -1, s2DeletePoint); + ChangeBlockImpl block = new ChangeBlockImpl(annotatedRevision.origin, null, s1From, s1To - s1From, -1, -1, -1, s2DeletePoint); block.setOriginAndTarget(csetOrigin, csetTarget); insp.deleted(block); } @Override protected void unchanged(int s1From, int s2From, int length) { - EqualBlockImpl block = new EqualBlockImpl(s1From, s2From, length, targetContent); + EqualBlockImpl block = new EqualBlockImpl(s1From, s2From, length, annotatedRevision.target); block.setOriginAndTarget(csetOrigin, csetTarget); insp.same(block); } private ChangeBlockImpl getAddBlock(int start, int len, int insPoint) { - return new ChangeBlockImpl(null, targetContent, -1, -1, start, len, insPoint, -1); + return new ChangeBlockImpl(null, annotatedRevision.target, -1, -1, start, len, insPoint, -1); + } + + private ChangeBlockImpl getChangeBlock(int start1, int end1, int start2, int end2) { + return new ChangeBlockImpl(annotatedRevision.origin, annotatedRevision.target, start1, end1-start1, start2, end2-start2, start1, start2); } } - static class BlockImpl implements Block { + private static class BlockImpl implements Block { private int originCset; private int targetCset; @@ -472,7 +517,7 @@ } } - static class EqualBlockImpl extends BlockImpl implements EqualBlock { + private static class EqualBlockImpl extends BlockImpl implements EqualBlock { private final int start1, start2; private final int length; private final ContentBlock fullContent; @@ -510,7 +555,7 @@ } } - static class ChangeBlockImpl extends BlockImpl implements ChangeBlock { + private static class ChangeBlockImpl extends BlockImpl implements ChangeBlock { private final ContentBlock oldContent; private final ContentBlock newContent; @@ -758,6 +803,49 @@ } } + private static class AnnotateRev implements RevisionDescriptor { + public ContentBlock origin, target; + public int originCset, targetCset, mergeCset, fileRevIndex; + + public void set(ContentBlock o, ContentBlock t) { + origin = o; + target = t; + } + public void set(int o, int t, int m) { + originCset = o; + targetCset = t; + mergeCset = m; + } + + public BlockData origin() { + return origin; + } + + public BlockData target() { + return target; + } + + public int originChangesetIndex() { + return originCset; + } + + public int targetChangesetIndex() { + return targetCset; + } + + public boolean isMerge() { + return mergeCset != NO_REVISION; + } + + public int mergeChangesetIndex() { + return mergeCset; + } + + public int fileRevisionIndex() { + return fileRevIndex; + } + } + public static void main(String[] args) { EqualBlocksCollector bc = new EqualBlocksCollector(); bc.match(-1, 5, 3);