001: /*
002: * ====================================================================
003: * Copyright (c) 2004 TMate Software Ltd. All rights reserved.
004: *
005: * This software is licensed as described in the file COPYING, which
006: * you should have received as part of this distribution. The terms
007: * are also available at http://svnkit.com/license.html
008: * If newer versions of this license are posted there, you may use a
009: * newer version instead, at your option.
010: * ====================================================================
011: */
012:
013: package de.regnis.q.sequence.line.diff;
014:
015: import java.io.*;
016: import java.util.*;
017:
018: import de.regnis.q.sequence.*;
019: import de.regnis.q.sequence.line.*;
020:
021: /**
022: * @author Ian Sullivan
023: * @author TMate Software Ltd.
024: */
025: public final class QDiffNormalGenerator extends QDiffSequenceGenerator
026: implements QDiffGeneratorFactory {
027:
028: // Constants ==============================================================
029:
030: public static final String TYPE = "normal";
031:
032: // Static =================================================================
033:
034: public static void setup() {
035: QDiffManager.registerDiffGeneratorFactory(
036: new QDiffNormalGenerator(), QDiffNormalGenerator.TYPE);
037: }
038:
039: // Fields =================================================================
040:
041: private Map myGeneratorsCache;
042:
043: // Setup ==================================================================
044:
045: private QDiffNormalGenerator(Map properties) {
046: super (properties, null);
047: }
048:
049: private QDiffNormalGenerator() {
050: super (null, null);
051: }
052:
053: // Implemented ============================================================
054:
055: public void generateDiffHeader(String item, String leftInfo,
056: String rightInfo, Writer output) throws IOException {
057: output.write("*** ");
058: output.write(item);
059: output.write(getEOL());
060: }
061:
062: protected void processBlock(QSequenceDifferenceBlock[] segment,
063: QSequenceLineCache sourceLines,
064: QSequenceLineCache targetLines, String encoding,
065: Writer output) throws IOException {
066: for (int i = 0; i < segment.length; i++) {
067: QSequenceDifferenceBlock block = segment[i];
068: processBlock(block.getLeftFrom(), block.getLeftTo(),
069: sourceLines, block.getRightFrom(), block
070: .getRightTo(), targetLines, encoding,
071: output);
072: }
073: }
074:
075: public QDiffGenerator createGenerator(Map properties) {
076: if (myGeneratorsCache == null) {
077: myGeneratorsCache = new HashMap();
078: }
079:
080: QDiffGenerator generator = (QDiffGenerator) myGeneratorsCache
081: .get(properties);
082: if (generator != null) {
083: return generator;
084: }
085: generator = new QDiffNormalGenerator(properties);
086: myGeneratorsCache.put(properties, generator);
087: return generator;
088: }
089:
090: // Accessing ==============================================================
091:
092: protected void processBlock(int sourceStartLine, int sourceEndLine,
093: QSequenceLineCache sourceLines, int targetStartLine,
094: int targetEndLine, QSequenceLineCache targetLines,
095: String encoding, Writer output) throws IOException {
096: if (sourceStartLine > sourceEndLine) {
097: add(sourceStartLine, targetStartLine, targetEndLine,
098: targetLines, encoding, output);
099: } else if (targetStartLine > targetEndLine) {
100: delete(targetStartLine, sourceStartLine, sourceEndLine,
101: sourceLines, encoding, output);
102: } else {
103: change(targetStartLine, targetEndLine, targetLines,
104: sourceStartLine, sourceEndLine, sourceLines,
105: encoding, output);
106: }
107: }
108:
109: protected String displayWhiteSpace(String s) {
110: if (Boolean.TRUE.toString().equals(
111: getProperties().get(
112: QDiffGeneratorFactory.WHITESPACE_PROPERTY))) {
113: s = s.replaceAll("\t", "<tb>");
114: s = s.replaceAll(" ", ".");
115: }
116: return s;
117: }
118:
119: /*
120: * Normal diff output is a series of one or more blocks in the following
121: * format change-command < target-file-line < target-file-line... --- >
122: * source-file-line > source-file-line... There are three types of change
123: * commands. Each consists of a line number or comma-separated range of
124: * lines in the target file, a single character indicating the kind of
125: * change to make, and a line number or comma-separated range of lines in
126: * the source file. All line numbers are the original line numbers in each
127: * file.
128: */
129:
130: /**
131: * Handles a delete of lines from the target.
132: *
133: * @param deleteAt the line where the lines would have appeared in the source (0 based)
134: * @param deleteStart first line deleted from target (0 based).
135: * @param deleteEnd last line deleted from target (0 based).
136: * @param deleteLines all the lines from the target file. Could be accessed with <CODE>deleteStart</CODE> and
137: * <CODE>deleteEnd</CODE> to identify the deleted lines.
138: */
139: protected void delete(int deleteAt, int deleteStart, int deleteEnd,
140: QSequenceLineCache deleteLines, String encoding,
141: Writer output) throws IOException {
142: /*
143: * Change command is in the format `rdl' Delete the lines in range r
144: * from the target file; line l is where they would have appeared in the
145: * source file had they not been deleted. For example, `5,7d3' means
146: * delete lines 5--7 of target file; or, if changing source file into
147: * target file, append lines 5--7 of target file after line 3 of source
148: * file.
149: */
150: // deleteStart and deleteEnd are 0 based, display a 1 based value.
151: int displayStart = deleteStart + 1;
152: int displayEnd = deleteEnd + 1;
153: int displayAt = deleteAt + 1;
154: println(displayStart
155: + ((displayEnd != displayStart) ? ("," + displayEnd)
156: : "") + "d" + displayAt, output);
157: int delLine = deleteStart;
158: while (delLine <= deleteEnd) {
159: print("<"
160: + displayWhiteSpace(printLine(deleteLines
161: .getLine(delLine++), encoding)), output);
162: }
163: }
164:
165: /**
166: * Handles the addition of lines to source.
167: *
168: * @param addAt the line where the new lines would be added to target (0 based)
169: * @param addStart the first line added from source (0 based)
170: * @param addEnd the last line added from source (0 based)
171: * @param addLines all the lines from the source file. Could be accessed with <CODE>addStart</CODE> and
172: * <CODE>addEnd</CODE> to identify the added lines.
173: */
174: protected void add(int addAt, int addStart, int addEnd,
175: QSequenceLineCache addLines, String encoding, Writer output)
176: throws IOException {
177: /*
178: * Change command is in the format `lar' Add the lines in range r of the
179: * source file after line l of the target file. For example, `8a12,15'
180: * means append lines 12--15 of source file after line 8 of target file;
181: * or, if changing source file into target file, delete lines 12--15 of
182: * source file.
183: */
184: int displayStart = addStart + 1;
185: int displayEnd = addEnd + 1;
186: int displayAt = addAt + 1;
187: println(displayAt
188: + "a"
189: + displayStart
190: + ((displayEnd != displayStart) ? ("," + displayEnd)
191: : ""), output);
192: int addLine = addStart;
193: while (addLine <= addEnd) {
194: print(">"
195: + displayWhiteSpace(printLine(addLines
196: .getLine(addLine++), encoding)), output);
197: }
198: }
199:
200: /**
201: * Handles a change of a range of lines in target to a range of lines in source.
202: *
203: * @param replaceStart the first line in target that will be replaced (0 based)
204: * @param replaceEnd the last line in target that will be replaced (0 based)
205: * @param replaceLines all the lines in target
206: * @param replaceWithStart the first line in source to that will replace the lines in target (0 based)
207: * @param replaceWithEnd the last line in source to that will replace the lines in target (0 based)
208: * @param replaceWithLines all the lines in source
209: */
210: protected void change(int replaceStart, int replaceEnd,
211: QSequenceLineCache replaceLines, int replaceWithStart,
212: int replaceWithEnd, QSequenceLineCache replaceWithLines,
213: String encoding, Writer output) throws IOException {
214: /*
215: * Change command is in the format `fct' Replace the lines in range f of
216: * the target file with lines in range t of the source file. This is
217: * like a combined add and delete, but more compact. For example,
218: * `5,7c8,10' means change lines 5--7 of target file to read as lines
219: * 8--10 of source file; or, if changing source file into target file,
220: * change lines 8--10 of source file to read as lines 5--7 of target
221: * file.
222: */
223: int displayStart = replaceStart + 1;
224: int displayEnd = replaceEnd + 1;
225: int displayWithStart = replaceWithStart + 1;
226: int displayWithEnd = replaceWithEnd + 1;
227: println(
228: displayStart
229: + ((displayEnd != displayStart) ? ("," + displayEnd)
230: : "")
231: + "c"
232: + displayWithStart
233: + ((displayWithEnd != displayWithStart) ? ("," + displayWithEnd)
234: : ""), output);
235: int replaceLine = replaceStart;
236: while (replaceLine <= replaceEnd) {
237: print("<"
238: + displayWhiteSpace(printLine(replaceLines
239: .getLine(replaceLine++), encoding)), output);
240: }
241: println("---", output);
242:
243: int replaceWithLine = replaceWithStart;
244: while (replaceWithLine <= replaceWithEnd) {
245: print(">"
246: + displayWhiteSpace(printLine(replaceWithLines
247: .getLine(replaceWithLine++), encoding)),
248: output);
249: }
250: }
251: }
|