Mercurial > jhg
diff src/org/tmatesoft/hg/internal/AnnotateFacility.java @ 545:15b406c7cd9d
First round of annotate file is functional
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Fri, 15 Feb 2013 22:15:13 +0100 |
parents | 7f5998a9619d |
children | cd78e8b9d7bc |
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/internal/AnnotateFacility.java Fri Feb 15 16:48:54 2013 +0100 +++ b/src/org/tmatesoft/hg/internal/AnnotateFacility.java Fri Feb 15 22:15:13 2013 +0100 @@ -19,11 +19,9 @@ import static org.tmatesoft.hg.repo.HgRepository.NO_REVISION; import org.tmatesoft.hg.core.Nodeid; -import org.tmatesoft.hg.internal.PatchGenerator.ChunkSequence; import org.tmatesoft.hg.internal.PatchGenerator.LineSequence; import org.tmatesoft.hg.repo.HgDataFile; import org.tmatesoft.hg.repo.HgInvalidStateException; -import org.tmatesoft.hg.repo.HgRepository; import org.tmatesoft.hg.util.CancelledException; /** @@ -37,48 +35,64 @@ /** * Annotates changes of the file against its parent(s) */ - public void annotateChange(HgDataFile df, int changestRevisionIndex, Inspector insp) { - Nodeid fileRev = df.getRepo().getManifest().getFileRevision(changestRevisionIndex, df.getPath()); + public void annotateChange(HgDataFile df, int changesetRevisionIndex, Inspector insp) { + // TODO detect if file is text/binary (e.g. looking for chars < ' ' and not \t\r\n\f + Nodeid fileRev = df.getRepo().getManifest().getFileRevision(changesetRevisionIndex, df.getPath()); int fileRevIndex = df.getRevisionIndex(fileRev); int[] fileRevParents = new int[2]; df.parents(fileRevIndex, fileRevParents, null, null); - if (fileRevParents[0] != NO_REVISION && fileRevParents[1] != NO_REVISION) { - // merge - } else if (fileRevParents[0] == fileRevParents[1]) { - // may be equal iff both are unset - assert fileRevParents[0] == NO_REVISION; - // everything added - insp.added(null); - } else { - int soleParent = fileRevParents[0] == NO_REVISION ? fileRevParents[1] : fileRevParents[0]; - assert soleParent != NO_REVISION; - try { + try { + if (fileRevParents[0] != NO_REVISION && fileRevParents[1] != NO_REVISION) { + // merge + } else if (fileRevParents[0] == fileRevParents[1]) { + // may be equal iff both are unset + assert fileRevParents[0] == NO_REVISION; + // everything added + ByteArrayChannel c; + df.content(fileRevIndex, c = new ByteArrayChannel()); + BlameBlockInspector bbi = new BlameBlockInspector(insp, NO_REVISION, changesetRevisionIndex); + LineSequence cls = LineSequence.newlines(c.toArray()); + bbi.begin(LineSequence.newlines(new byte[0]), cls); + bbi.match(0, cls.chunkCount()-1, 0); + bbi.end(); + } else { + int soleParent = fileRevParents[0] == NO_REVISION ? fileRevParents[1] : fileRevParents[0]; + assert soleParent != NO_REVISION; ByteArrayChannel c1, c2; df.content(soleParent, c1 = new ByteArrayChannel()); df.content(fileRevIndex, c2 = new ByteArrayChannel()); int parentChangesetRevIndex = df.getChangesetRevisionIndex(soleParent); PatchGenerator<LineSequence> pg = new PatchGenerator<LineSequence>(); pg.init(LineSequence.newlines(c1.toArray()), LineSequence.newlines(c2.toArray())); - pg.findMatchingBlocks(new BlameBlockInspector(insp)); - } catch (CancelledException ex) { - // TODO likely it was bad idea to throw cancelled exception from content() - // deprecate and provide alternative? - HgInvalidStateException ise = new HgInvalidStateException("ByteArrayChannel never throws CancelledException"); - ise.initCause(ex); - throw ise; + pg.findMatchingBlocks(new BlameBlockInspector(insp, parentChangesetRevIndex, changesetRevisionIndex)); } + } catch (CancelledException ex) { + // TODO likely it was bad idea to throw cancelled exception from content() + // deprecate and provide alternative? + HgInvalidStateException ise = new HgInvalidStateException("ByteArrayChannel never throws CancelledException"); + ise.initCause(ex); + throw ise; } } @Callback public interface Inspector { - void same(Block block); + void same(EqualBlock block); void added(AddBlock block); void changed(ChangeBlock block); void deleted(DeleteBlock block); } + @Callback + public interface InspectorEx extends Inspector { // XXX better name + // XXX perhaps, shall pass object instead of separate values for future extension? + void start(int originLineCount, int targetLineCount); + void done(); + } + public interface Block { + int originChangesetIndex(); + int targetChangesetIndex(); // boolean isMergeRevision(); // int fileRevisionIndex(); // int originFileRevisionIndex(); @@ -86,6 +100,12 @@ // byte[] data(); } + public interface EqualBlock extends Block { + int originStart(); + int targetStart(); + int length(); + } + public interface AddBlock extends Block { int insertedAt(); // line index in the old file int firstAddedLine(); @@ -103,56 +123,115 @@ static class BlameBlockInspector extends PatchGenerator.DeltaInspector<LineSequence> { private final Inspector insp; + private final int csetP1; + private final int csetTarget; - public BlameBlockInspector(Inspector inspector) { + public BlameBlockInspector(Inspector inspector, int parentCset1, int targetCset) { assert inspector != null; insp = inspector; + csetP1 = parentCset1; + csetTarget = targetCset; + } + + @Override + public void begin(LineSequence s1, LineSequence s2) { + super.begin(s1, s2); + if (insp instanceof InspectorEx) { + ((InspectorEx) insp).start(s1.chunkCount() - 1, s2.chunkCount() - 1); + } + } + + @Override + public void end() { + super.end(); + if(insp instanceof InspectorEx) { + ((InspectorEx) insp).done(); + } } @Override protected void changed(int s1From, int s1To, int s2From, int s2To) { - insp.changed(new BlockImpl2(seq1, seq2, s1From, s1To-s1From, s2From, s2To - s2From, s1From, s2From)); + BlockImpl2 block = new BlockImpl2(seq1, seq2, s1From, s1To-s1From, s2From, s2To - s2From, s1From, s2From); + block.setOriginAndTarget(csetP1, csetTarget); + insp.changed(block); } @Override protected void added(int s1InsertPoint, int s2From, int s2To) { - insp.added(new BlockImpl2(null, seq2, -1, -1, s2From, s2To - s2From, s1InsertPoint, -1)); + BlockImpl2 block = new BlockImpl2(null, seq2, -1, -1, s2From, s2To - s2From, s1InsertPoint, -1); + block.setOriginAndTarget(csetP1, csetTarget); + insp.added(block); } @Override protected void deleted(int s2DeletePoint, int s1From, int s1To) { - insp.deleted(new BlockImpl2(seq1, null, s1From, s1To - s1From, -1, -1, -1, s2DeletePoint)); + BlockImpl2 block = new BlockImpl2(seq1, null, s1From, s1To - s1From, -1, -1, -1, s2DeletePoint); + block.setOriginAndTarget(csetP1, csetTarget); + insp.deleted(block); } @Override protected void unchanged(int s1From, int s2From, int length) { - insp.same(new BlockImpl(seq2, s2From, length)); + BlockImpl1 block = new BlockImpl1(s1From, s2From, length); + block.setOriginAndTarget(csetP1, csetTarget); + insp.same(block); + } + } + + static class BlockImpl implements Block { + + private int originCset; + private int targetCset; + + void setOriginAndTarget(int originChangesetIndex, int targetChangesetIndex) { + // XXX perhaps, shall be part of Inspector API, rather than Block's + // as they don't change between blocks (although the moment about merged revisions) + // is not yet clear to me + originCset = originChangesetIndex; + targetCset = targetChangesetIndex; + } + + public int originChangesetIndex() { + return originCset; + } + + public int targetChangesetIndex() { + return targetCset; } } - static class BlockImpl implements Block { - private final ChunkSequence seq; - private final int start; + static class BlockImpl1 extends BlockImpl implements EqualBlock { + private final int start1, start2; private final int length; - BlockImpl() { - // FIXME delete this cons - seq = null; - start = length = -1; + BlockImpl1(int blockStartSeq1, int blockStartSeq2, int blockLength) { + start1 = blockStartSeq1; + start2 = blockStartSeq2; + length = blockLength; } - BlockImpl(ChunkSequence s, int blockStart, int blockLength) { - seq = s; - start = blockStart; - length = blockLength; + public int originStart() { + return start1; + } + + public int targetStart() { + return start2; + } + + public int length() { + return length; } + @Override + public String toString() { + return String.format("@@ [%d..%d) == [%d..%d) @@", start1, start1+length, start2, start2+length); + } } - static class BlockImpl2 implements ChangeBlock { + static class BlockImpl2 extends BlockImpl implements ChangeBlock { - private final ChunkSequence oldSeq; - private final ChunkSequence newSeq; + private final LineSequence oldSeq; + private final LineSequence newSeq; private final int s1Start; private final int s1Len; private final int s2Start; @@ -160,7 +239,7 @@ private final int s1InsertPoint; private final int s2DeletePoint; - public BlockImpl2(ChunkSequence s1, ChunkSequence s2, int s1Start, int s1Len, int s2Start, int s2Len, int s1InsertPoint, int s2DeletePoint) { + public BlockImpl2(LineSequence s1, LineSequence s2, int s1Start, int s1Len, int s2Start, int s2Len, int s1InsertPoint, int s2DeletePoint) { oldSeq = s1; newSeq = s2; this.s1Start = s1Start; @@ -210,5 +289,16 @@ } return rv; } + + @Override + public String toString() { + if (s2DeletePoint == -1) { + return String.format("@@ -%d,0 +%d,%d @@", insertedAt(), firstAddedLine(), totalAddedLines()); + } else if (s1InsertPoint == -1) { + // delete only + return String.format("@@ -%d,%d +%d,0 @@", firstRemovedLine(), totalRemovedLines(), removedAt()); + } + return String.format("@@ -%d,%d +%d,%d @@", firstRemovedLine(), totalRemovedLines(), firstAddedLine(), totalAddedLines()); + } } }