View | Details | Raw Unified | Return to bug 305518
Collapse All | Expand All

(-)formatter/org/eclipse/jdt/internal/formatter/Scribe.java (-69 / +102 lines)
Lines 2048-2102 Link Here
2048
			throw new AbortFormatting(e);
2048
			throw new AbortFormatting(e);
2049
		}
2049
		}
2050
	}
2050
	}
2051
2051
	/*
2052
	/*
2052
	 * prints a code snippet
2053
	 * prints a code snippet
2053
	 */
2054
	 */
2054
	private void printCodeSnippet(int startPosition, int endPosition) {
2055
	private void printCodeSnippet(int startPosition, int endPosition, int linesGap) {
2055
		String snippet = new String(this.scanner.source, startPosition, endPosition - startPosition + 1);
2056
		String snippet = new String(this.scanner.source, startPosition, endPosition - startPosition + 1);
2056
2057
	
2057
		// 1 - strip content prefix (@see JavaDocRegion#preprocessCodeSnippet)
2058
		// 1 - strip content prefix (@see JavaDocRegion#preprocessCodeSnippet)
2058
		ILineTracker tracker= new DefaultLineTracker();
2059
		int firstLine = Util.getLineNumber(startPosition, this.lineEnds, 0, this.maxLines) - 1;
2059
		String contentPrefix= IJavaDocTagConstants.JAVADOC_STAR;
2060
		int lastLine = Util.getLineNumber(endPosition, this.lineEnds, firstLine>1 ? firstLine-2 : 0, this.maxLines) - 1;
2060
2061
		StringBuffer inputBuffer= new StringBuffer();
2061
		StringBuffer inputBuffer= new StringBuffer();
2062
		inputBuffer.setLength(0);
2062
		if (firstLine == lastLine && linesGap == 0) {
2063
		inputBuffer.append(snippet);
2063
			inputBuffer.append(snippet);
2064
		tracker.set(snippet);
2064
		} else {
2065
		for (int lines= tracker.getNumberOfLines() - 1; lines > 0; lines--) {
2065
			boolean hasCharsAfterStar = false;
2066
			int lineOffset;
2066
			if (linesGap == 0) {
2067
			try {
2067
				inputBuffer.append(this.scanner.source, startPosition, this.lineEnds[firstLine]+1-startPosition);
2068
				lineOffset= tracker.getLineOffset(lines);
2068
				firstLine++;
2069
			} catch (BadLocationException e) {
2069
			}
2070
				// should not happen
2070
			int initialLength = inputBuffer.length();
2071
				CommentFormatterUtil.log(e);
2071
			for (int currentLine=firstLine; currentLine<=lastLine; currentLine++) {
2072
				return;
2072
				this.scanner.resetTo(this.lineEnds[currentLine-1]+1, this.lineEnds[currentLine]);
2073
			}
2073
				int lineStart = this.scanner.currentPosition;
2074
			int prefixOffset = inputBuffer.indexOf(contentPrefix, lineOffset);
2074
				boolean hasStar = false;
2075
			if (prefixOffset >= 0 && inputBuffer.substring(lineOffset, prefixOffset).trim().length() == 0) {
2075
				loop: while (!this.scanner.atEnd()) {
2076
				int offsetEnd = prefixOffset + 1;
2076
					char ch = (char) this.scanner.getNextChar();
2077
				char ch = inputBuffer.charAt(offsetEnd);
2077
					switch (ch) {
2078
				switch (ch) {
2078
						case ' ':
2079
					case '\n':
2079
						case '\t' :
2080
					case '\r':
2080
						case '\u000c' :
2081
						break;
2081
							break;
2082
					case ' ':
2082
						case '\r' :
2083
					case '\t':
2083
						case '\n' :
2084
					case '\u000c' :    /* FORM FEED               */
2084
							break loop;
2085
						offsetEnd++;
2085
						case '*':
2086
						break;
2086
							hasStar = true;
2087
					default:
2087
							break loop;
2088
						if (ScannerHelper.isWhitespace(ch)) {
2088
						default:
2089
							offsetEnd++;
2089
							if (ScannerHelper.isWhitespace(ch)) {
2090
								break;
2091
							}
2092
							break loop;
2093
					}
2094
				}
2095
				if (hasStar) {
2096
					lineStart = this.scanner.currentPosition;
2097
					if (!hasCharsAfterStar && !this.scanner.atEnd()) {
2098
						char ch = (char) this.scanner.getNextChar();
2099
						boolean atEnd = this.scanner.atEnd();
2100
						switch (ch) {
2101
							case ' ':
2102
							case '\t' :
2103
							case '\u000c' :
2104
								break;
2105
							case '\r' :
2106
							case '\n' :
2107
								atEnd = true;
2108
								break;
2109
							default:
2110
								if (!ScannerHelper.isWhitespace(ch)) {
2111
									if (hasStar) {
2112
										// A non whitespace character is just after the star
2113
										// then we need to restart from the beginning without
2114
										// consuming the space after the star
2115
										hasCharsAfterStar = true;
2116
										currentLine = firstLine-1;
2117
										inputBuffer.setLength(initialLength);
2118
										continue;
2119
									}
2120
								}
2121
								break;
2090
						}
2122
						}
2091
						break;
2123
						if (!hasCharsAfterStar && !atEnd) {
2124
							// Until then, there's always a whitespace after each star
2125
							// of the comment, hence we need to consume it as it will
2126
							// be rewritten while reindenting the snippet lines
2127
							lineStart = this.scanner.currentPosition;
2128
						}
2129
					}
2092
				}
2130
				}
2093
				inputBuffer.delete(lineOffset, offsetEnd);
2131
				int end = currentLine == lastLine ? endPosition : this.lineEnds[currentLine];
2132
				inputBuffer.append(this.scanner.source, lineStart, end+1-lineStart);
2094
			}
2133
			}
2095
		}
2134
		}
2096
2135
	
2097
		// 2 - convert HTML to Java (@see JavaDocRegion#convertHtml2Java)
2136
		// 2 - convert HTML to Java (@see JavaDocRegion#convertHtml2Java)
2098
		HTMLEntity2JavaReader reader= new HTMLEntity2JavaReader(new StringReader(inputBuffer.toString()));
2137
		HTMLEntity2JavaReader reader= new HTMLEntity2JavaReader(new StringReader(inputBuffer.toString()));
2099
		char[] buf= new char[snippet.length()]; // html2text never gets longer, only shorter!
2138
		char[] buf= new char[inputBuffer.length()]; // html2text never gets longer, only shorter!
2100
		String convertedSnippet;
2139
		String convertedSnippet;
2101
		try {
2140
		try {
2102
			int read= reader.read(buf);
2141
			int read= reader.read(buf);
Lines 2106-2112 Link Here
2106
			CommentFormatterUtil.log(e);
2145
			CommentFormatterUtil.log(e);
2107
			return;
2146
			return;
2108
		}
2147
		}
2109
2148
	
2110
		// 3 - format snippet (@see JavaDocRegion#formatCodeSnippet)
2149
		// 3 - format snippet (@see JavaDocRegion#formatCodeSnippet)
2111
		// include comments in case of line comments are present in the snippet
2150
		// include comments in case of line comments are present in the snippet
2112
		String formattedSnippet = convertedSnippet;
2151
		String formattedSnippet = convertedSnippet;
Lines 2122-2128 Link Here
2122
			// 3.b - valid code formatted
2161
			// 3.b - valid code formatted
2123
			// 3.b.i - get the result
2162
			// 3.b.i - get the result
2124
			formattedSnippet = CommentFormatterUtil.evaluateFormatterEdit(convertedSnippet, edit, null);
2163
			formattedSnippet = CommentFormatterUtil.evaluateFormatterEdit(convertedSnippet, edit, null);
2125
2164
	
2126
			// 3.b.ii- convert back to HTML (@see JavaDocRegion#convertJava2Html)
2165
			// 3.b.ii- convert back to HTML (@see JavaDocRegion#convertJava2Html)
2127
			Java2HTMLEntityReader javaReader= new Java2HTMLEntityReader(new StringReader(formattedSnippet));
2166
			Java2HTMLEntityReader javaReader= new Java2HTMLEntityReader(new StringReader(formattedSnippet));
2128
			buf= new char[256];
2167
			buf= new char[256];
Lines 2141-2169 Link Here
2141
				return;
2180
				return;
2142
			}
2181
			}
2143
		}
2182
		}
2144
2183
	
2145
		// 4 - add the content prefix (@see JavaDocRegion#postprocessCodeSnippet)
2184
		// 4 - add the content prefix (@see JavaDocRegion#postprocessCodeSnippet)
2146
		StringBuffer outputBuffer = new StringBuffer();
2185
		StringBuffer outputBuffer = new StringBuffer();
2147
		tracker = new DefaultLineTracker();
2186
		ILineTracker tracker = new DefaultLineTracker();
2148
		this.column = 1;
2187
		this.column = 1;
2149
		printIndentationIfNecessary(outputBuffer); // append indentation
2188
		printIndentationIfNecessary(outputBuffer); // append indentation
2150
		outputBuffer.append(BLOCK_LINE_PREFIX);
2189
		outputBuffer.append(BLOCK_LINE_PREFIX);
2151
		String linePrefix = outputBuffer.toString();
2190
		String linePrefix = outputBuffer.toString();
2152
		outputBuffer.setLength(0);
2191
		outputBuffer.setLength(0);
2153
		outputBuffer.append(formattedSnippet);
2192
		String replacement = formattedSnippet;
2154
		tracker.set(outputBuffer.toString());
2193
		tracker.set(formattedSnippet);
2155
		for (int lines=tracker.getNumberOfLines() - 1; lines > 0; lines--) {
2194
		int numberOfLines = tracker.getNumberOfLines();
2156
			try {
2195
		if (numberOfLines > 1) {
2157
				outputBuffer.insert(tracker.getLineOffset(lines), linePrefix);
2196
			int lastLineOffset = -1;
2158
			} catch (BadLocationException e) {
2197
			for (int i=0; i<numberOfLines-1; i++) {
2159
				// should not happen
2198
				if (i>0) outputBuffer.append(linePrefix);
2160
				CommentFormatterUtil.log(e);
2199
				try {
2161
				return;
2200
					lastLineOffset = tracker.getLineOffset(i+1);
2201
					outputBuffer.append(formattedSnippet.substring(tracker.getLineOffset(i), lastLineOffset));
2202
				} catch (BadLocationException e) {
2203
					// should not happen
2204
					CommentFormatterUtil.log(e);
2205
					return;
2206
				}
2162
			}
2207
			}
2208
			outputBuffer.append(linePrefix);
2209
			outputBuffer.append(formattedSnippet.substring(lastLineOffset));
2210
			replacement = outputBuffer.toString();
2163
		}
2211
		}
2164
2212
	
2165
		// 5 - replace old text with the formatted snippet
2213
		// 5 - replace old text with the formatted snippet
2166
		addReplaceEdit(startPosition, endPosition, outputBuffer.toString());
2214
		addReplaceEdit(startPosition, endPosition, replacement);
2167
	}
2215
	}
2168
2216
2169
	void printComment() {
2217
	void printComment() {
Lines 3905-3911 Link Here
3905
    				if (this.formatter.preferences.comment_format_source) {
3953
    				if (this.formatter.preferences.comment_format_source) {
3906
						if (textStart < end) addReplaceEdit(textStart, end, buffer.toString());
3954
						if (textStart < end) addReplaceEdit(textStart, end, buffer.toString());
3907
						// See whether there's a space before the code
3955
						// See whether there's a space before the code
3908
						boolean needLeadingSpace = false;
3909
						if (linesGap > 0) {
3956
						if (linesGap > 0) {
3910
							int lineStart = this.scanner.getLineStart(startLine);
3957
							int lineStart = this.scanner.getLineStart(startLine);
3911
							if (nextStart > lineStart) { // if code starts at the line, then no leading space is needed
3958
							if (nextStart > lineStart) { // if code starts at the line, then no leading space is needed
Lines 3915-3933 Link Here
3915
									if (token == TerminalTokens.TokenNameWHITESPACE) {
3962
									if (token == TerminalTokens.TokenNameWHITESPACE) {
3916
										// skip indentation
3963
										// skip indentation
3917
										token = this.scanner.getNextToken();
3964
										token = this.scanner.getNextToken();
3918
										needLeadingSpace = false; // there may be no star after
3919
									} else {
3920
										needLeadingSpace = true;
3921
									}
3965
									}
3922
									if (token == TerminalTokens.TokenNameMULTIPLY) {
3966
									if (token == TerminalTokens.TokenNameMULTIPLY) {
3923
										nextStart = this.scanner.currentPosition;
3967
										nextStart = this.scanner.currentPosition;
3924
										// skip javadoc comment star
3925
										token = this.scanner.getNextToken();
3926
										needLeadingSpace = true;
3927
									}
3928
									if (token == TerminalTokens.TokenNameWHITESPACE) {
3929
										needLeadingSpace = false;
3930
										nextStart++;
3931
									}
3968
									}
3932
								}
3969
								}
3933
								catch (InvalidInputException iie) {
3970
								catch (InvalidInputException iie) {
Lines 3938-3951 Link Here
3938
						// Format gap lines before code
3975
						// Format gap lines before code
3939
						int newLines = linesGap;
3976
						int newLines = linesGap;
3940
						if (newLines == 0) newLines=1;
3977
						if (newLines == 0) newLines=1;
3941
						this.needSpace = needLeadingSpace;
3978
						this.needSpace = false;
3942
						printJavadocGapLines(end+1, nextStart-1, newLines, false/* clear first blank lines inside <pre> tag as done by old formatter */, false, null);
3979
						printJavadocGapLines(end+1, nextStart-1, newLines, false/* clear first blank lines inside <pre> tag as done by old formatter */, false, null);
3943
						if (this.needSpace) {
3944
							addInsertEdit(nextStart, " "); //$NON-NLS-1$
3945
							this.needSpace = false;
3946
						}
3947
						// Format the code
3980
						// Format the code
3948
						printCodeSnippet(nextStart, codeEnd);
3981
						printCodeSnippet(nextStart, codeEnd, linesGap);
3949
						// Format the gap lines after the code
3982
						// Format the gap lines after the code
3950
						nextStart = (int) text.separators[max];
3983
						nextStart = (int) text.separators[max];
3951
	    				printJavadocGapLines(codeEnd+1, nextStart-1, 1, false/* clear blank lines inside <pre> tag as done by old formatter */, false, null);
3984
	    				printJavadocGapLines(codeEnd+1, nextStart-1, 1, false/* clear blank lines inside <pre> tag as done by old formatter */, false, null);
(-)src/org/eclipse/jdt/core/tests/formatter/FormatterCommentsBugsTest.java (+119 lines)
Lines 6355-6360 Link Here
6355
}
6355
}
6356
6356
6357
/**
6357
/**
6358
 * @bug 305518: [formatter] Line inside <pre> tag is wrongly indented by one space when starting just after the star
6359
 * @test Verify formatting of a <pre> tag section keep lines right indented
6360
 * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=305518"
6361
 */
6362
public void testBug305518() {
6363
	String source = 
6364
		"public interface Test {\n" + 
6365
		"/**\n" + 
6366
		" * <pre>\n" + 
6367
		" *    A\n" + 
6368
		" *   / \\\n" + 
6369
		" *  B   C\n" + 
6370
		" * / \\ / \\\n" + 
6371
		" *D  E F  G\n" + 
6372
		" * </pre>\n" + 
6373
		" */\n" + 
6374
		"public void foo();\n" + 
6375
	    "}\n";
6376
	formatSource(source,
6377
		"public interface Test {\n" + 
6378
		"	/**\n" + 
6379
		"	 * <pre>\n" + 
6380
		"	 *     A\n" + 
6381
		"	 *    / \\\n" + 
6382
		"	 *   B   C\n" + 
6383
		"	 *  / \\ / \\\n" + 
6384
		"	 * D  E F  G\n" + 
6385
		"	 * </pre>\n" + 
6386
		"	 */\n" + 
6387
		"	public void foo();\n" + 
6388
	    "}\n");
6389
}
6390
public void testBug305518_wksp2_01() {
6391
	String source = 
6392
		"public class X01 {\n" + 
6393
		"/**\n" + 
6394
		"	<P> This is an example of starting and shutting down the Network Server in the example\n" + 
6395
		"	above with the API.\n" + 
6396
		"	<PRE>\n" + 
6397
		"	\n" + 
6398
		"	NetworkServerControl serverControl = new NetworkServerControl(InetAddress.getByName(\"myhost\"),1621)\n" + 
6399
		"\n" + 
6400
		"	serverControl.shutdown();\n" + 
6401
		"	</PRE>\n" + 
6402
		"\n" + 
6403
		"	\n" + 
6404
		"*/\n" + 
6405
		"public void foo() {}\n" + 
6406
	    "}\n";
6407
	formatSource(source,
6408
		"public class X01 {\n" + 
6409
		"	/**\n" + 
6410
		"	 * <P>\n" + 
6411
		"	 * This is an example of starting and shutting down the Network Server in\n" + 
6412
		"	 * the example above with the API.\n" + 
6413
		"	 * \n" + 
6414
		"	 * <PRE>\n" + 
6415
		"	 * \n" + 
6416
		"	 * 	NetworkServerControl serverControl = new NetworkServerControl(InetAddress.getByName(\"myhost\"),1621)\n" + 
6417
		"	 * \n" + 
6418
		"	 * 	serverControl.shutdown();\n" + 
6419
		"	 * </PRE>\n" + 
6420
		"	 */\n" + 
6421
		"	public void foo() {\n" + 
6422
		"	}\n" + 
6423
	    "}\n");
6424
}
6425
public void testBug305518_wksp2_02() {
6426
	String source = 
6427
		"public class X02 {\n" + 
6428
		"/**\n" + 
6429
		" * Represents namespace name:\n" + 
6430
		" * <pre>e.g.<pre>MyNamespace;\n" + 
6431
		" *MyProject\\Sub\\Level;\n" + 
6432
		" *namespace\\MyProject\\Sub\\Level;\n" + 
6433
		" */\n" + 
6434
		"public void foo() {}\n" + 
6435
	    "}\n";
6436
	formatSource(source,
6437
		"public class X02 {\n" + 
6438
		"	/**\n" + 
6439
		"	 * Represents namespace name:\n" + 
6440
		"	 * \n" + 
6441
		"	 * <pre>e.g.\n" + 
6442
		"	 * \n" + 
6443
		"	 * <pre>\n" + 
6444
		"	 * MyNamespace;\n" + 
6445
		"	 * MyProject\\Sub\\Level;\n" + 
6446
		"	 * namespace\\MyProject\\Sub\\Level;\n" + 
6447
		"	 */\n" + 
6448
		"	public void foo() {\n" + 
6449
		"	}\n" + 
6450
	    "}\n");
6451
}
6452
public void testBug305518_wksp2_03() {
6453
	String source = 
6454
		"public class X03 {\n" + 
6455
		"/**\n" + 
6456
		"* <PRE>\n" + 
6457
		"*  String s = ... ; // get string from somewhere\n" + 
6458
		"*  byte [] compressed = UnicodeCompressor.compress(s);\n" + 
6459
		"* </PRE>\n" + 
6460
		" */\n" + 
6461
		"public void foo() {}\n" + 
6462
	    "}\n";
6463
	formatSource(source,
6464
		"public class X03 {\n" + 
6465
		"	/**\n" + 
6466
		"	 * <PRE>\n" + 
6467
		"	 *  String s = ... ; // get string from somewhere\n" + 
6468
		"	 *  byte [] compressed = UnicodeCompressor.compress(s);\n" + 
6469
		"	 * </PRE>\n" + 
6470
		"	 */\n" + 
6471
		"	public void foo() {\n" + 
6472
		"	}\n" + 
6473
	    "}\n");
6474
}
6475
6476
/**
6358
 * @bug 305830: [formatter] Turning off formatting changes comment's formatting
6477
 * @bug 305830: [formatter] Turning off formatting changes comment's formatting
6359
 * @test Verify that turning off formatting in a javadoc does not screw up its indentation
6478
 * @test Verify that turning off formatting in a javadoc does not screw up its indentation
6360
 * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=305830"
6479
 * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=305830"

Return to bug 305518