comparison src/org/tmatesoft/hg/internal/AnnotateFacility.java @ 542:a71a05ec11bc

Towards annotate/blame support: general outline of the functionality
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Thu, 14 Feb 2013 16:36:13 +0100
parents
children 1e95f48d9886
comparison
equal deleted inserted replaced
541:946b13196252 542:a71a05ec11bc
1 /*
2 * Copyright (c) 2013 TMate Software Ltd
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * For information on how to redistribute this software under
14 * the terms of a license other than GNU General Public License
15 * contact TMate Software at support@hg4j.com
16 */
17 package org.tmatesoft.hg.internal;
18
19 import static org.tmatesoft.hg.repo.HgRepository.NO_REVISION;
20
21 import org.tmatesoft.hg.core.Nodeid;
22 import org.tmatesoft.hg.internal.PatchGenerator.ChunkSequence;
23 import org.tmatesoft.hg.repo.HgDataFile;
24 import org.tmatesoft.hg.repo.HgInvalidStateException;
25 import org.tmatesoft.hg.repo.HgRepository;
26 import org.tmatesoft.hg.util.CancelledException;
27
28 /**
29 *
30 * @author Artem Tikhomirov
31 * @author TMate Software Ltd.
32 */
33 @Experimental(reason="work in progress")
34 public class AnnotateFacility {
35
36 public void annotate(HgDataFile df, int changestRevisionIndex, Inspector insp) {
37 Nodeid fileRev = df.getRepo().getManifest().getFileRevision(changestRevisionIndex, df.getPath());
38 int fileRevIndex = df.getRevisionIndex(fileRev);
39 int[] fileRevParents = new int[2];
40 df.parents(fileRevIndex, fileRevParents, null, null);
41 if (fileRevParents[0] != NO_REVISION && fileRevParents[1] != NO_REVISION) {
42 // merge
43 } else if (fileRevParents[0] == fileRevParents[1]) {
44 // may be equal iff both are unset
45 assert fileRevParents[0] == NO_REVISION;
46 // everything added
47 insp.added(null);
48 } else {
49 int soleParent = fileRevParents[0] == NO_REVISION ? fileRevParents[1] : fileRevParents[0];
50 assert soleParent != NO_REVISION;
51 try {
52 ByteArrayChannel c1, c2;
53 df.content(soleParent, c1 = new ByteArrayChannel());
54 df.content(fileRevIndex, c2 = new ByteArrayChannel());
55 int parentChangesetRevIndex = df.getChangesetRevisionIndex(soleParent);
56 PatchGenerator pg = new PatchGenerator();
57 pg.init(c1.toArray(), c2.toArray());
58 pg.findMatchingBlocks(new BlameBlockInspector(insp));
59 } catch (CancelledException ex) {
60 // TODO likely it was bad idea to throw cancelled exception from content()
61 // deprecate and provide alternative?
62 HgInvalidStateException ise = new HgInvalidStateException("ByteArrayChannel never throws CancelledException");
63 ise.initCause(ex);
64 throw ise;
65 }
66 }
67 }
68
69 @Callback
70 public interface Inspector {
71 void same(Block block);
72 void added(AddBlock block);
73 void changed(ChangeBlock block);
74 void deleted(DeleteBlock block);
75 }
76
77 public interface Block {
78 // boolean isMergeRevision();
79 // int fileRevisionIndex();
80 // int originFileRevisionIndex();
81 // String[] lines();
82 // byte[] data();
83 }
84
85 public interface AddBlock extends Block {
86 int firstAddedLine();
87 int totalAddedLines();
88 String[] addedLines();
89 }
90 public interface DeleteBlock extends Block {
91 int firstRemovedLine();
92 int totalRemovedLines();
93 String[] removedLines();
94 }
95 public interface ChangeBlock extends AddBlock, DeleteBlock {
96 }
97
98 static class BlameBlockInspector extends PatchGenerator.DeltaInspector {
99 private final Inspector insp;
100
101 public BlameBlockInspector(Inspector inspector) {
102 assert inspector != null;
103 insp = inspector;
104 }
105
106 @Override
107 protected void changed(int s1From, int s1To, int s2From, int s2To) {
108 insp.changed(new BlockImpl2(seq1, seq2, s1From, s1To-s1From, s2From, s2To - s2From));
109 }
110
111 @Override
112 protected void added(int s1InsertPoint, int s2From, int s2To) {
113 insp.added(new BlockImpl2(null, seq2, -1, -1, s2From, s2To - s2From));
114 }
115
116 @Override
117 protected void deleted(int s1From, int s1To) {
118 insp.deleted(new BlockImpl2(seq1, null, s1From, s1To - s1From, -1, -1));
119 }
120
121 @Override
122 protected void unchanged(int s1From, int s2From, int length) {
123 insp.same(new BlockImpl(seq2, s2From, length));
124 }
125 }
126
127 static class BlockImpl implements Block {
128 private final ChunkSequence seq;
129 private final int start;
130 private final int length;
131
132 BlockImpl() {
133 // FIXME delete this cons
134 seq = null;
135 start = length = -1;
136 }
137
138 BlockImpl(ChunkSequence s, int blockStart, int blockLength) {
139 seq = s;
140 start = blockStart;
141 length = blockLength;
142 }
143
144 }
145
146 static class BlockImpl2 implements ChangeBlock {
147
148 private final ChunkSequence oldSeq;
149 private final ChunkSequence newSeq;
150 private final int s1Start;
151 private final int s1Len;
152 private final int s2Start;
153 private final int s2Len;
154
155 public BlockImpl2(ChunkSequence s1, ChunkSequence s2, int s1Start, int s1Len, int s2Start, int s2Len) {
156 oldSeq = s1;
157 newSeq = s2;
158 this.s1Start = s1Start;
159 this.s1Len = s1Len;
160 this.s2Start = s2Start;
161 this.s2Len = s2Len;
162 }
163
164 public int firstAddedLine() {
165 return s2Start;
166 }
167
168 public int totalAddedLines() {
169 return s2Len;
170 }
171
172 public String[] addedLines() {
173 return generateLines(totalAddedLines(), firstAddedLine());
174 }
175
176 public int firstRemovedLine() {
177 return s1Start;
178 }
179
180 public int totalRemovedLines() {
181 return s1Len;
182 }
183
184 public String[] removedLines() {
185 return generateLines(totalRemovedLines(), firstRemovedLine());
186 }
187
188 private String[] generateLines(int count, int startFrom) {
189 String[] rv = new String[count];
190 for (int i = 0; i < count; i++) {
191 rv[i] = String.format("LINE %d", startFrom + i);
192 }
193 return rv;
194 }
195 }
196 }