View Javadoc
1   /*
2    * Copyright (C) 2009, Christian Halstrick <christian.halstrick@sap.com>
3    * Copyright (C) 2014, André de Oliveira <andre.oliveira@liferay.com> and others
4    *
5    * This program and the accompanying materials are made available under the
6    * terms of the Eclipse Distribution License v. 1.0 which is available at
7    * https://www.eclipse.org/org/documents/edl-v10.php.
8    *
9    * SPDX-License-Identifier: BSD-3-Clause
10   */
11  
12  package org.eclipse.jgit.merge;
13  
14  import java.io.IOException;
15  import java.io.OutputStream;
16  import java.nio.charset.Charset;
17  import java.util.List;
18  
19  import org.eclipse.jgit.diff.RawText;
20  import org.eclipse.jgit.merge.MergeChunk.ConflictState;
21  
22  class MergeFormatterPass {
23  
24  	private final EolAwareOutputStream out;
25  
26  	private final MergeResult<RawText> res;
27  
28  	private final List<String> seqName;
29  
30  	private final Charset charset;
31  
32  	private final boolean threeWayMerge;
33  
34  	private String lastConflictingName; // is set to non-null whenever we are in
35  										// a conflict
36  
37  	/**
38  	 * @param out
39  	 *            the {@link java.io.OutputStream} where to write the textual
40  	 *            presentation
41  	 * @param res
42  	 *            the merge result which should be presented
43  	 * @param seqName
44  	 *            When a conflict is reported each conflicting range will get a
45  	 *            name. This name is following the "&lt;&lt;&lt;&lt;&lt;&lt;&lt;
46  	 *            " or "&gt;&gt;&gt;&gt;&gt;&gt;&gt; " conflict markers. The
47  	 *            names for the sequences are given in this list
48  	 * @param charset
49  	 *            the character set used when writing conflict metadata
50  	 */
51  	MergeFormatterPass(OutputStream out, MergeResult<RawText> res,
52  			List<String> seqName, Charset charset) {
53  		this.out = new EolAwareOutputStream(out);
54  		this.res = res;
55  		this.seqName = seqName;
56  		this.charset = charset;
57  		this.threeWayMerge = (res.getSequences().size() == 3);
58  	}
59  
60  	void formatMerge() throws IOException {
61  		boolean missingNewlineAtEnd = false;
62  		for (MergeChunk chunk : res) {
63  			RawText seq = res.getSequences().get(chunk.getSequenceIndex());
64  			writeConflictMetadata(chunk);
65  			// the lines with conflict-metadata are written. Now write the chunk
66  			for (int i = chunk.getBegin(); i < chunk.getEnd(); i++)
67  				writeLine(seq, i);
68  			missingNewlineAtEnd = seq.isMissingNewlineAtEnd();
69  		}
70  		// one possible leftover: if the merge result ended with a conflict we
71  		// have to close the last conflict here
72  		if (lastConflictingName != null)
73  			writeConflictEnd();
74  		if (!missingNewlineAtEnd)
75  			out.beginln();
76  	}
77  
78  	private void writeConflictMetadata(MergeChunk chunk) throws IOException {
79  		if (lastConflictingName != null
80  				&& chunk.getConflictState() != ConflictState.NEXT_CONFLICTING_RANGE) {
81  			// found the end of an conflict
82  			writeConflictEnd();
83  		}
84  		if (chunk.getConflictState() == ConflictState.FIRST_CONFLICTING_RANGE) {
85  			// found the start of an conflict
86  			writeConflictStart(chunk);
87  		} else if (chunk.getConflictState() == ConflictState.NEXT_CONFLICTING_RANGE) {
88  			// found another conflicting chunk
89  			writeConflictChange(chunk);
90  		}
91  	}
92  
93  	private void writeConflictEnd() throws IOException {
94  		writeln(">>>>>>> " + lastConflictingName); //$NON-NLS-1$
95  		lastConflictingName = null;
96  	}
97  
98  	private void writeConflictStart(MergeChunk chunk) throws IOException {
99  		lastConflictingName = seqName.get(chunk.getSequenceIndex());
100 		writeln("<<<<<<< " + lastConflictingName); //$NON-NLS-1$
101 	}
102 
103 	private void writeConflictChange(MergeChunk chunk) throws IOException {
104 		/*
105 		 * In case of a non-three-way merge I'll add the name of the conflicting
106 		 * chunk behind the equal signs. I also append the name of the last
107 		 * conflicting chunk after the ending greater-than signs. If somebody
108 		 * knows a better notation to present non-three-way merges - feel free
109 		 * to correct here.
110 		 */
111 		lastConflictingName = seqName.get(chunk.getSequenceIndex());
112 		writeln(threeWayMerge ? "=======" : "======= " //$NON-NLS-1$ //$NON-NLS-2$
113 				+ lastConflictingName);
114 	}
115 
116 	private void writeln(String s) throws IOException {
117 		out.beginln();
118 		out.write((s + "\n").getBytes(charset)); //$NON-NLS-1$
119 	}
120 
121 	private void writeLine(RawText seq, int i) throws IOException {
122 		out.beginln();
123 		seq.writeLine(out, i);
124 		// still BOL? It was a blank line. But writeLine won't lf, so we do.
125 		if (out.isBeginln())
126 			out.write('\n');
127 	}
128 }