### Eclipse Workspace Patch 1.0
#P org.eclipse.jdt.core
Index: buildnotes_jdt-core.html
===================================================================
RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/buildnotes_jdt-core.html,v
retrieving revision 1.7344
diff -u -r1.7344 buildnotes_jdt-core.html
--- buildnotes_jdt-core.html 2 Mar 2010 15:58:29 -0000 1.7344
+++ buildnotes_jdt-core.html 2 Mar 2010 18:14:17 -0000
@@ -48,9 +48,168 @@
Project org.eclipse.jdt.core v_A38
(cvs).
+These new preferences are controlled with the options:
+DefaultCodeFormatterConstants.FORMATTER_DISABLING_TAG
+DefaultCodeFormatterConstants.FORMATTER_ENABLING_TAG
++/** + * FORMATTER / Option to define the tag to put in a comment to disable the formatting. + * See the {@link #FORMATTER_ENABLING_TAG} option to re-enable it. + * - option id: "org.eclipse.jdt.core.formatter.disabling_tag" + * - default:+null
+ * + * Note that: + * + * 1. As soon as the formatter encounters the defined disabling tag, it stops to + * format the code from the beginning of the comment including this tag. If it + * was already disabled, the tag has no special effect. + * For example, the second defined enabling tag "disable-formatter" + * in the following snippet is not necessary as the formatter was already disabled + * since the first one: + * class X { + * // disable-formatter + * void foo1() {} + * // disable-formatter + * void foo2() {} + * void bar1() {} + * void bar2() {} + * } + * + * 2. If no enabling tag is found by the formatter after the disabling tag, then + * the end of the snippet won't be formatted. + * For example, when a disabling tag is put at the beginning of the code, then + * the entire content of a compilation unit is not formatted: + * // disable-formatter + * class X { + * void foo1() {} + * void foo2() {} + * void bar1() {} + * void bar2() {} + * } + * + * 3. If a mix of disabling and enabling tags is done in the same comment, then + * the formatter will only take into account the last encountered tag in the + * comment. + * For example, in the following snippet, the formatter will be disabled after + * the comment: + * class X { + * /* + * * This is a comment with a mix of disabling and enabling tags: + * * - disable-formatter + * * - enable-formatter + * * - disable-formatter + * * The formatter will stop to format from the beginning of this comment... + * */ + * void foo() {} + * void bar() {} + * } + * + * 4. The tag cannot include newline characters but it can have white spaces. + * E.g. "format: off" is a valid disabling tag + * + * @since 3.6 + */ + +/** + * FORMATTER / Option to define the tag to put in a comment to re-enable the + * formatting after it has been disabled (see {@link #FORMATTER_DISABLING_TAG}) + * - option id: "org.eclipse.jdt.core.formatter.enabling_tag" + * - default:null
+ * + * Note that: + * + * 1. As soon as the formatter encounters the defined enabling tag, it re-starts + * to format the code just after the comment including this tag. If it was already + * active, i.e. already re-enabled or never disabled, the tag has no special effect. + * For example, the defined enabling tag "enable-formatter" + * in the following snippet is not necessary as the formatter has never been + * disabled: + * class X { + * void foo1() {} + * void foo2() {} + * // enable-formatter + * void bar1() {} + * void bar2() {} + * } + * + * Or, in the following other snippet, the second enabling tag is not necessary as + * the formatting will have been re-enabled by the first one: + * class X { + * // disable-formatter + * void foo1() {} + * void foo2() {} + * // enable-formatter + * void bar1() {} + * // enable-formatter + * void bar2() {} + * } + * + * 2. If a mix of disabling and enabling tags is done in the same comment, then + * the formatter will only take into account the last encountered tag in the + * comment. + * For example, in the following snippet, the formatter will be re-enabled after + * the comment: + * // disable-formatter + * class X { + * /* + * * This is a comment with a mix of disabling and enabling tags: + * * - enable-formatter + * * - disable-formatter + * * - enable-formatter + * * The formatter will restart to format after this comment... + * */ + * void foo() {} + * void bar() {} + * } + * + * 3. The tag cannot include newline characters but it can have white spaces. + * E.g. "format: on" is a valid enabling tag + * + * @since 3.6 + */ +
For example, the following snippet:
++public class Test { +/* disable-formatter */ +void foo( ) { + // unformatted area +} +/* enable-formatter */ +void bar( ) { + // formatted area +} +} ++formatted with disabling tags = "disable-formatter" and enabling tags += "enable-formatter" produces the following output: +
+public class Test { + +/* disable-formatter * +void foo( ) { + // unformatted area +} +/* enable-formatter * + void bar() { + // formatted area + } +} ++See bug 27079 for more details. +
+ * FORMATTER / Option to define the tag to put in a comment to disable the formatting.
+ * See the {@link #FORMATTER_ENABLING_TAG} option to re-enable it.
+ * - option id: "org.eclipse.jdt.core.formatter.disabling_tag"
+ * - default: null
+ *
+ *
+ * + * Note that: + *
+ * For example, the second defined enabling tag "disable-formatter" + * in the following snippet is not necessary as the formatter was already disabled + * since the first one: + *
+ * class X { + * // disable-formatter + * void foo1() {} + * // disable-formatter + * void foo2() {} + * void bar1() {} + * void bar2() {} + * } + *+ *
+ * // disable-formatter + * class X { + * void foo1() {} + * void foo2() {} + * void bar1() {} + * void bar2() {} + * } + *+ *
For example, in the following snippet, the formatter will be disabled after + * the comment:
+ *+ * class X { + * /* + * * This is a comment with a mix of disabling and enabling tags: + * * - disable-formatter + * * - enable-formatter + * * - disable-formatter + * * The formatter will stop to format from the beginning of this comment... + * */ + * void foo() {} + * void bar() {} + * } + *+ *
+ * FORMATTER / Option to define the tag to put in a comment to re-enable the
+ * formatting after it has been disabled (see {@link #FORMATTER_DISABLING_TAG})
+ * - option id: "org.eclipse.jdt.core.formatter.enabling_tag"
+ * - default: null
+ *
+ *
+ * + * Note that: + *
+ * For example, the defined enabling tag "enable-formatter" + * in the following snippet is not necessary as the formatter has never been + * disabled: + *
+ * class X { + * void foo1() {} + * void foo2() {} + * // enable-formatter + * void bar1() {} + * void bar2() {} + * } + *+ * Or, in the following other snippet, the second enabling tag is not necessary as + * the formatting will have been re-enabled by the first one: + *
+ * class X { + * // disable-formatter + * void foo1() {} + * void foo2() {} + * // enable-formatter + * void bar1() {} + * // enable-formatter + * void bar2() {} + * } + *+ *
For example, in the following snippet, the formatter will be re-enabled after + * the comment:
+ *+ * // disable-formatter + * class X { + * /* + * * This is a comment with a mix of disabling and enabling tags: + * * - enable-formatter + * * - disable-formatter + * * - enable-formatter + * * The formatter will restart to format after this comment... + * */ + * void foo() {} + * void bar() {} + * } + *+ *
* FORMATTER / Option to indent body declarations compare to its enclosing annotation declaration header * - option id: "org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" * - possible values: { TRUE, FALSE } Index: formatter/org/eclipse/jdt/internal/formatter/CodeFormatterVisitor.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CodeFormatterVisitor.java,v retrieving revision 1.229 diff -u -r1.229 CodeFormatterVisitor.java --- formatter/org/eclipse/jdt/internal/formatter/CodeFormatterVisitor.java 23 Feb 2010 15:04:52 -0000 1.229 +++ formatter/org/eclipse/jdt/internal/formatter/CodeFormatterVisitor.java 2 Mar 2010 18:14:21 -0000 @@ -756,7 +756,7 @@ final char[] compilationUnitSource = string.toCharArray(); this.localScanner.setSource(compilationUnitSource); - this.scribe.initializeScanner(compilationUnitSource); + this.scribe.resetScanner(compilationUnitSource); if (nodes == null) { return null; @@ -793,7 +793,7 @@ final char[] compilationUnitSource = string.toCharArray(); this.localScanner.setSource(compilationUnitSource); - this.scribe.initializeScanner(compilationUnitSource); + this.scribe.resetScanner(compilationUnitSource); this.lastLocalDeclarationSourceStart = -1; try { @@ -822,7 +822,7 @@ final char[] compilationUnitSource = string.toCharArray(); this.localScanner.setSource(compilationUnitSource); - this.scribe.initializeScanner(compilationUnitSource); + this.scribe.resetScanner(compilationUnitSource); if (constructorDeclaration == null) { return null; @@ -866,7 +866,7 @@ final char[] compilationUnitSource = string.toCharArray(); this.localScanner.setSource(compilationUnitSource); - this.scribe.initializeScanner(compilationUnitSource); + this.scribe.resetScanner(compilationUnitSource); if (expression == null) { return null; Index: formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java,v retrieving revision 1.102 diff -u -r1.102 DefaultCodeFormatterOptions.java --- formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java 1 Mar 2010 17:09:36 -0000 1.102 +++ formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java 2 Mar 2010 18:14:24 -0000 @@ -16,6 +16,7 @@ import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants; import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.internal.compiler.util.Util; import org.eclipse.jdt.internal.formatter.align.Alignment; /** @@ -116,6 +117,9 @@ public boolean comment_insert_new_line_for_parameter; public int comment_line_length; + public char[] disabling_tag; + public char[] enabling_tag; + public boolean indent_statements_compare_to_block; public boolean indent_statements_compare_to_body; public boolean indent_body_declarations_compare_to_annotation_declaration_header; @@ -612,6 +616,8 @@ options.put(DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE, Integer.toString(this.tab_size)); options.put(DefaultCodeFormatterConstants.FORMATTER_USE_TABS_ONLY_FOR_LEADING_INDENTATIONS, this.use_tabs_only_for_leading_indentations ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE); options.put(DefaultCodeFormatterConstants.FORMATTER_WRAP_BEFORE_BINARY_OPERATOR, this.wrap_before_binary_operator ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE); + options.put(DefaultCodeFormatterConstants.FORMATTER_DISABLING_TAG, this.disabling_tag == null ? Util.EMPTY_STRING : new String(this.disabling_tag)); + options.put(DefaultCodeFormatterConstants.FORMATTER_ENABLING_TAG, this.enabling_tag == null ? Util.EMPTY_STRING : new String(this.enabling_tag)); return options; } @@ -1949,6 +1955,28 @@ if (wrapBeforeBinaryOperatorOption != null) { this.wrap_before_binary_operator = DefaultCodeFormatterConstants.TRUE.equals(wrapBeforeBinaryOperatorOption); } + final Object disableTagOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_DISABLING_TAG); + if (disableTagOption != null) { + if (disableTagOption instanceof String) { + String stringValue = (String) disableTagOption; + if (stringValue.trim().length() == 0) { + this.disabling_tag = null; + } else { + this.disabling_tag = stringValue.toCharArray(); + } + } + } + final Object enableTagOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_ENABLING_TAG); + if (enableTagOption != null) { + if (enableTagOption instanceof String) { + String stringValue = (String) enableTagOption; + if (stringValue.trim().length() == 0) { + this.enabling_tag = null; + } else { + this.enabling_tag = stringValue.toCharArray(); + } + } + } } /** Index: formatter/org/eclipse/jdt/internal/formatter/FormatJavadocBlock.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/FormatJavadocBlock.java,v retrieving revision 1.12 diff -u -r1.12 FormatJavadocBlock.java --- formatter/org/eclipse/jdt/internal/formatter/FormatJavadocBlock.java 14 Feb 2010 15:57:25 -0000 1.12 +++ formatter/org/eclipse/jdt/internal/formatter/FormatJavadocBlock.java 2 Mar 2010 18:14:24 -0000 @@ -358,7 +358,11 @@ boolean inlined = (this.flags & INLINED) != 0; if (inlined) buffer.append(" {"); //$NON-NLS-1$ buffer.append('@'); - buffer.append(TAG_NAMES[this.tagValue]); + if (this.tagValue == TAG_OTHERS_VALUE) { + buffer.append("others_tag"); //$NON-NLS-1$ + } else { + buffer.append(TAG_NAMES[this.tagValue]); + } super.toString(buffer); if (this.reference == null) { buffer.append('\n'); Index: formatter/org/eclipse/jdt/internal/formatter/Scribe.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/Scribe.java,v retrieving revision 1.195 diff -u -r1.195 Scribe.java --- formatter/org/eclipse/jdt/internal/formatter/Scribe.java 1 Mar 2010 17:09:35 -0000 1.195 +++ formatter/org/eclipse/jdt/internal/formatter/Scribe.java 2 Mar 2010 18:14:25 -0000 @@ -78,10 +78,14 @@ private int[] lineEnds; private int maxLines; - private String lineSeparator; public Alignment memberAlignment; public boolean needSpace = false; + // Line separator infos + final private String lineSeparator; + final private char firstLS; + final private int lsLength; + public int nlsTagCounter; public int pageWidth; public boolean pendingSpace = false; @@ -100,6 +104,9 @@ private final boolean indentEmptyLines; int blank_lines_between_import_groups = -1; + /** disabling */ + boolean editsEnabled = true; + /* Comments formatting */ private static final int INCLUDE_BLOCK_COMMENTS = CodeFormatter.F_INCLUDE_COMMENTS | CodeFormatter.K_MULTI_LINE_COMMENT; private static final int INCLUDE_JAVA_DOC = CodeFormatter.F_INCLUDE_COMMENTS | CodeFormatter.K_JAVA_DOC; @@ -114,6 +121,7 @@ private int formatComments = 0; private int headerEndPosition = -1; String commentIndentation; // indentation requested in comments (usually in javadoc root tags description) + // Class to store previous line comment information static class LineComment { boolean contiguous = false; @@ -123,12 +131,15 @@ } final LineComment lastLineComment = new LineComment(); - // New way to format javadoc private FormatterCommentParser formatterCommentParser; // specialized parser to format comments + // Disabling and enabling tags + OptimizedReplaceEdit previousDisabledEdit; + private char[] disablingTag, enablingTag; + Scribe(CodeFormatterVisitor formatter, long sourceLevel, IRegion[] regions, CodeSnippetParsingUtil codeSnippetParsingUtil, boolean includeComments) { - this.scanner = new Scanner(true, true, false/*nls*/, sourceLevel/*sourceLevel*/, null/*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/); + initializeScanner(sourceLevel, formatter.preferences); this.formatter = formatter; this.pageWidth = formatter.preferences.page_width; this.tabLength = formatter.preferences.tab_size; @@ -143,6 +154,8 @@ this.indentationSize = this.tabLength; } this.lineSeparator = formatter.preferences.line_separator; + this.firstLS = this.lineSeparator.charAt(0); + this.lsLength = this.lineSeparator.length(); this.indentationLevel = formatter.preferences.initial_indentation_level * this.indentationSize; this.regions= regions; if (codeSnippetParsingUtil != null) { @@ -447,6 +460,18 @@ } private final void addOptimizedReplaceEdit(int offset, int length, String replacement) { + if (!this.editsEnabled) { + if (this.previousDisabledEdit != null && this.previousDisabledEdit.offset == offset) { + replacement = this.previousDisabledEdit.replacement; + } + this.previousDisabledEdit = null; + if (replacement.indexOf(this.lineSeparator) >= 0) { + if (length == 0 || printNewLinesCharacters(offset, length)) { + this.previousDisabledEdit = new OptimizedReplaceEdit(offset, length, replacement); + } + } + return; + } if (this.editsIndex > 0) { // try to merge last two edits final OptimizedReplaceEdit previous = this.edits[this.editsIndex-1]; @@ -1269,18 +1294,16 @@ this.numberOfIndentations++; } - /** - * @param compilationUnitSource - */ - public void initializeScanner(char[] compilationUnitSource) { - this.scanner.setSource(compilationUnitSource); - this.scannerEndPosition = compilationUnitSource.length; - this.scanner.resetTo(0, this.scannerEndPosition - 1); - this.edits = new OptimizedReplaceEdit[INITIAL_SIZE]; - this.maxLines = this.lineEnds == null ? -1 : this.lineEnds.length - 1; - this.scanner.lineEnds = this.lineEnds; - this.scanner.linePtr = this.maxLines; - initFormatterCommentParser(); + private void initializeScanner(long sourceLevel, DefaultCodeFormatterOptions preferences) { + this.disablingTag = preferences.disabling_tag; + this.enablingTag = preferences.enabling_tag; + char[][] taskTags; + if (this.disablingTag == null && this.enablingTag == null) { + taskTags = null; + } else { + taskTags = new char[][] { this.disablingTag, this.enablingTag }; + } + this.scanner = new Scanner(true, true, false/*nls*/, sourceLevel/*sourceLevel*/, taskTags, null/*taskPriorities*/, true/*taskCaseSensitive*/); } private void initFormatterCommentParser() { @@ -2153,7 +2176,9 @@ boolean hasLineComment = false; boolean hasWhitespaces = false; int lines = 0; + int previousFoundTaskCount = this.scanner.foundTaskCount; while ((this.currentToken = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + int foundTaskCount = this.scanner.foundTaskCount; switch(this.currentToken) { case TerminalTokens.TokenNameWHITESPACE : char[] whiteSpaces = this.scanner.getCurrentTokenSource(); @@ -2279,6 +2304,16 @@ currentTokenStartPosition = this.scanner.currentPosition; break; case TerminalTokens.TokenNameCOMMENT_LINE : + if (this.editsEnabled && foundTaskCount > previousFoundTaskCount) { + setEditsEnabled(foundTaskCount, previousFoundTaskCount); + if (!this.editsEnabled && this.editsIndex > 1) { + OptimizedReplaceEdit currentEdit = this.edits[this.editsIndex-1]; + if (this.scanner.startPosition == currentEdit.offset+currentEdit.length) { + printNewLinesBeforeDisablingComment(); + } + } + previousFoundTaskCount = foundTaskCount; + } if (rejectLineComment) break; if (lines >= 1) { if (lines > 1) { @@ -2294,8 +2329,21 @@ currentTokenStartPosition = this.scanner.currentPosition; hasLineComment = true; lines = 0; + if (!this.editsEnabled && foundTaskCount > previousFoundTaskCount) { + setEditsEnabled(foundTaskCount, previousFoundTaskCount); + } break; case TerminalTokens.TokenNameCOMMENT_BLOCK : + if (this.editsEnabled && foundTaskCount > previousFoundTaskCount) { + setEditsEnabled(foundTaskCount, previousFoundTaskCount); + if (!this.editsEnabled && this.editsIndex > 1) { + OptimizedReplaceEdit currentEdit = this.edits[this.editsIndex-1]; + if (this.scanner.startPosition == currentEdit.offset+currentEdit.length) { + printNewLinesBeforeDisablingComment(); + } + } + previousFoundTaskCount = foundTaskCount; + } if (trailing > NO_TRAILING_COMMENT && lines >= 1) { // a block comment on next line means that there's no trailing comment this.scanner.resetTo(this.scanner.getCurrentTokenStartPosition(), this.scannerEndPosition - 1); @@ -2318,8 +2366,15 @@ hasLineComment = false; hasComment = true; lines = 0; + if (!this.editsEnabled && foundTaskCount > previousFoundTaskCount) { + setEditsEnabled(foundTaskCount, previousFoundTaskCount); + } break; case TerminalTokens.TokenNameCOMMENT_JAVADOC : + if (this.editsEnabled && foundTaskCount > previousFoundTaskCount) { + setEditsEnabled(foundTaskCount, previousFoundTaskCount); + previousFoundTaskCount = foundTaskCount; + } if (trailing > NO_TRAILING_COMMENT) { // a javadoc comment should not be considered as a trailing comment this.scanner.resetTo(this.scanner.getCurrentTokenStartPosition(), this.scannerEndPosition - 1); @@ -2342,6 +2397,9 @@ } else { printBlockComment(true); } + if (!this.editsEnabled && foundTaskCount > previousFoundTaskCount) { + setEditsEnabled(foundTaskCount, previousFoundTaskCount); + } printNewLine(); currentTokenStartPosition = this.scanner.currentPosition; hasLineComment = false; @@ -2354,6 +2412,7 @@ this.scanner.resetTo(currentTokenStartPosition, this.scannerEndPosition - 1); return; } + previousFoundTaskCount = foundTaskCount; } } catch (InvalidInputException e) { throw new AbortFormatting(e); @@ -2363,7 +2422,7 @@ void printComment(int kind, String source, int start, int end, int level) { // Set scanner - initializeScanner(source.toCharArray()); + resetScanner(source.toCharArray()); this.scanner.resetTo(start, end); // Put back 3.4RC2 code => comment following line as it has an impact on Linux tests // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=234336 @@ -2677,9 +2736,10 @@ } } - // Delete leading whitespaces if any - if (previousToken != -1 && lastTokenEndPosition != commentStart && spaceEndPosition > lastTokenEndPosition) { - addDeleteEdit(lastTokenEndPosition, spaceEndPosition-1); + // Replace the line separator at the end of the comment if any... + int startReplace = previousToken == SKIP_FIRST_WHITESPACE_TOKEN ? spaceStartPosition : lastTokenEndPosition; + if (this.column == 1 && commentEnd >= startReplace) { + addReplaceEdit(startReplace, commentEnd, this.formatter.preferences.line_separator); } } @@ -4319,6 +4379,135 @@ this.lastLineComment.contiguous = false; } + /* + * Print the indentation of a disabling comment + */ + private void printNewLinesBeforeDisablingComment() { + + // Get the beginning of comment line + int linePtr = Arrays.binarySearch(this.lineEnds, this.scanner.startPosition); + if (linePtr < 0) { + linePtr = -linePtr - 1; + } + int indentation = 0; + int beginningOfLine = getLineEnd(linePtr)+1; + if (beginningOfLine == -1) { + beginningOfLine = 0; + } + + // If the comment is in the middle of the line, then there's nothing to do + OptimizedReplaceEdit currentEdit = this.edits[this.editsIndex-1]; + int offset = currentEdit.offset; + if (offset >= beginningOfLine) return; + + // Compute the comment indentation + int scannerStartPosition = this.scanner.startPosition; + int scannerEofPosition = this.scanner.eofPosition; + int scannerCurrentPosition = this.scanner.currentPosition; + char scannerCurrentChar = this.scanner.currentCharacter; + int length = currentEdit.length; + this.scanner.resetTo(beginningOfLine, offset+length-1); + try { + while (!this.scanner.atEnd()) { + char ch = (char) this.scanner.getNextChar(); + switch (ch) { + case '\t' : + if (this.tabLength != 0) { + int reminder = indentation % this.tabLength; + if (reminder == 0) { + indentation += this.tabLength; + } else { + indentation = ((indentation / this.tabLength) + 1) * this.tabLength; + } + } + break; + case ' ': + indentation++; + break; + default: + // Should not happen as the offset of the edit is before the beginning of line + return; + } + } + + // Split the existing edit to keep the change before the beginning of the last line + // but change the indentation after. Note that at this stage, the add*Edit methods + // cannot be longer used as the edits are disabled + StringBuffer indentationBuffer = new StringBuffer(); + int currentIndentation = getCurrentIndentation(this.scanner.currentPosition); + if (currentIndentation > 0 && this.indentationLevel > 0) { + int col = this.column; + printIndentationIfNecessary(indentationBuffer); + this.column = col; + } + String replacement = currentEdit.replacement; + if (replacement.length() == 0) { + // previous edit was a delete, as we're sure to have a new line before + // the comment, then the edit needs to be either replaced entirely with + // the expected indentation + this.edits[this.editsIndex-1] = new OptimizedReplaceEdit(beginningOfLine, offset+length-beginningOfLine, indentationBuffer.toString()); + } else { + int idx = replacement.lastIndexOf(this.lineSeparator); + if (idx >= 0) { + // replace current edit if it contains a line separator + int start = idx + this.lsLength; + StringBuffer buffer = new StringBuffer(replacement.substring(0, start)); + buffer.append(indentationBuffer); + this.edits[this.editsIndex-1] = new OptimizedReplaceEdit(offset, length, buffer.toString()); + } + } + } + finally { + this.scanner.startPosition = scannerStartPosition; + this.scanner.eofPosition = scannerEofPosition; + this.scanner.currentPosition = scannerCurrentPosition; + this.scanner.currentCharacter = scannerCurrentChar; + } + } + + /* + * Print new lines characters when the edits are disabled. In this case, only + * the line separator is replaced if necessary, the other white spaces are untouched. + */ + private boolean printNewLinesCharacters(int offset, int length) { + boolean foundNewLine = false; + int scannerStartPosition = this.scanner.startPosition; + int scannerEofPosition = this.scanner.eofPosition; + int scannerCurrentPosition = this.scanner.currentPosition; + char scannerCurrentChar = this.scanner.currentCharacter; + this.scanner.resetTo(offset, offset+length-1); + try { + while (!this.scanner.atEnd()) { + int start = this.scanner.currentPosition; + char ch = (char) this.scanner.getNextChar(); + boolean needReplace = ch != this.firstLS; + switch (ch) { + case '\r': + if (this.scanner.atEnd()) break; + ch = (char) this.scanner.getNextChar(); + if (ch != '\n') break; + needReplace = needReplace || this.lsLength != 2; + //$FALL-THROUGH$ + case '\n': + if (needReplace) { + if (this.editsIndex == 0 || this.edits[this.editsIndex-1].offset != start) { + this.edits[this.editsIndex++] = new OptimizedReplaceEdit(start, this.scanner.currentPosition-start, this.lineSeparator); + } + } + foundNewLine = true; + break; + } + } + } + finally { + this.scanner.startPosition = scannerStartPosition; + this.scanner.eofPosition = scannerEofPosition; + this.scanner.currentPosition = scannerCurrentPosition; + this.scanner.currentCharacter = scannerCurrentChar; + } + return foundNewLine; + } + public void printNextToken(int expectedTokenType){ printNextToken(expectedTokenType, false); } @@ -4526,10 +4715,42 @@ this.formatter.lastLocalDeclarationSourceStart = location.lastLocalDeclarationSourceStart; } + /** + * @param compilationUnitSource + */ + public void resetScanner(char[] compilationUnitSource) { + this.scanner.setSource(compilationUnitSource); + this.scannerEndPosition = compilationUnitSource.length; + this.scanner.resetTo(0, this.scannerEndPosition - 1); + this.edits = new OptimizedReplaceEdit[INITIAL_SIZE]; + this.maxLines = this.lineEnds == null ? -1 : this.lineEnds.length - 1; + this.scanner.lineEnds = this.lineEnds; + this.scanner.linePtr = this.maxLines; + initFormatterCommentParser(); + } + private void resize() { System.arraycopy(this.edits, 0, (this.edits = new OptimizedReplaceEdit[this.editsIndex * 2]), 0, this.editsIndex); } + /* + * Look for the tags identified by the scanner to see whether some of them + * may change the status of the edition for the formatter. + * Do not return as soon as a match is found, as there may have several + * disabling/enabling tags in a comment, hence the last one will be the one really + * changing the formatter behavior... + */ + private void setEditsEnabled(int count, int previous) { + for (int i=previous; i