0001: /*******************************************************************************
0002: * Copyright (c) 2000, 2007 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: *******************************************************************************/package org.eclipse.jdt.internal.formatter;
0011:
0012: import java.util.Arrays;
0013:
0014: import org.eclipse.jdt.core.compiler.CharOperation;
0015: import org.eclipse.jdt.core.compiler.InvalidInputException;
0016: import org.eclipse.jdt.internal.compiler.ASTVisitor;
0017: import org.eclipse.jdt.internal.compiler.ast.Annotation;
0018: import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
0019: import org.eclipse.jdt.internal.compiler.parser.Scanner;
0020: import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
0021: import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
0022: import org.eclipse.jdt.internal.compiler.util.Util;
0023: import org.eclipse.jdt.internal.core.util.CodeSnippetParsingUtil;
0024: import org.eclipse.jdt.internal.core.util.RecordedParsingInformation;
0025: import org.eclipse.jdt.internal.formatter.align.Alignment;
0026: import org.eclipse.jdt.internal.formatter.align.AlignmentException;
0027: import org.eclipse.text.edits.MultiTextEdit;
0028: import org.eclipse.text.edits.ReplaceEdit;
0029: import org.eclipse.text.edits.TextEdit;
0030:
0031: /**
0032: * This class is responsible for dumping formatted source
0033: * @since 2.1
0034: */
0035: public class Scribe {
0036: private static final int INITIAL_SIZE = 100;
0037:
0038: private boolean checkLineWrapping;
0039: /** one-based column */
0040: public int column;
0041: private int[][] commentPositions;
0042:
0043: // Most specific alignment.
0044: public Alignment currentAlignment;
0045: public int currentToken;
0046:
0047: // edits management
0048: private OptimizedReplaceEdit[] edits;
0049: public int editsIndex;
0050:
0051: public CodeFormatterVisitor formatter;
0052: public int indentationLevel;
0053: public int lastNumberOfNewLines;
0054: public int line;
0055:
0056: private int[] lineEnds;
0057: private String lineSeparator;
0058: public Alignment memberAlignment;
0059: public boolean needSpace = false;
0060:
0061: public int nlsTagCounter;
0062: public int pageWidth;
0063: public boolean pendingSpace = false;
0064:
0065: public Scanner scanner;
0066: public int scannerEndPosition;
0067: public int tabLength;
0068: public int indentationSize;
0069: private int textRegionEnd;
0070: private int textRegionStart;
0071: public int tabChar;
0072: public int numberOfIndentations;
0073: private boolean useTabsOnlyForLeadingIndents;
0074:
0075: /** indent empty lines*/
0076: private final boolean indentEmptyLines;
0077:
0078: private final boolean formatJavadocComment;
0079: private final boolean formatBlockComment;
0080:
0081: Scribe(CodeFormatterVisitor formatter, long sourceLevel,
0082: int offset, int length,
0083: CodeSnippetParsingUtil codeSnippetParsingUtil) {
0084: this .scanner = new Scanner(true, true, false/*nls*/,
0085: sourceLevel/*sourceLevel*/, null/*taskTags*/,
0086: null/*taskPriorities*/, true/*taskCaseSensitive*/);
0087: this .formatter = formatter;
0088: this .pageWidth = formatter.preferences.page_width;
0089: this .tabLength = formatter.preferences.tab_size;
0090: this .indentationLevel = 0; // initialize properly
0091: this .numberOfIndentations = 0;
0092: this .useTabsOnlyForLeadingIndents = formatter.preferences.use_tabs_only_for_leading_indentations;
0093: this .indentEmptyLines = formatter.preferences.indent_empty_lines;
0094: this .tabChar = formatter.preferences.tab_char;
0095: if (this .tabChar == DefaultCodeFormatterOptions.MIXED) {
0096: this .indentationSize = formatter.preferences.indentation_size;
0097: } else {
0098: this .indentationSize = this .tabLength;
0099: }
0100: this .lineSeparator = formatter.preferences.line_separator;
0101: this .indentationLevel = formatter.preferences.initial_indentation_level
0102: * this .indentationSize;
0103: this .textRegionStart = offset;
0104: this .textRegionEnd = offset + length - 1;
0105: if (codeSnippetParsingUtil != null) {
0106: final RecordedParsingInformation information = codeSnippetParsingUtil.recordedParsingInformation;
0107: if (information != null) {
0108: this .lineEnds = information.lineEnds;
0109: this .commentPositions = information.commentPositions;
0110: }
0111: }
0112: this .formatBlockComment = formatter.preferences.comment_format_block_comment;
0113: this .formatJavadocComment = formatter.preferences.comment_format_javadoc_comment;
0114: reset();
0115: }
0116:
0117: private final void addDeleteEdit(int start, int end) {
0118: if (this .edits.length == this .editsIndex) {
0119: // resize
0120: resize();
0121: }
0122: addOptimizedReplaceEdit(start, end - start + 1,
0123: Util.EMPTY_STRING);
0124: }
0125:
0126: public final void addInsertEdit(int insertPosition,
0127: String insertedString) {
0128: if (this .edits.length == this .editsIndex) {
0129: // resize
0130: resize();
0131: }
0132: addOptimizedReplaceEdit(insertPosition, 0, insertedString);
0133: }
0134:
0135: private final void addOptimizedReplaceEdit(int offset, int length,
0136: String replacement) {
0137: if (this .editsIndex > 0) {
0138: // try to merge last two edits
0139: final OptimizedReplaceEdit previous = this .edits[this .editsIndex - 1];
0140: final int previousOffset = previous.offset;
0141: final int previousLength = previous.length;
0142: final int endOffsetOfPreviousEdit = previousOffset
0143: + previousLength;
0144: final int replacementLength = replacement.length();
0145: final String previousReplacement = previous.replacement;
0146: final int previousReplacementLength = previousReplacement
0147: .length();
0148: if (previousOffset == offset
0149: && previousLength == length
0150: && (replacementLength == 0 || previousReplacementLength == 0)) {
0151: if (this .currentAlignment != null) {
0152: final Location location = this .currentAlignment.location;
0153: if (location.editsIndex == this .editsIndex) {
0154: location.editsIndex--;
0155: location.textEdit = previous;
0156: }
0157: }
0158: this .editsIndex--;
0159: return;
0160: }
0161: if (endOffsetOfPreviousEdit == offset) {
0162: if (length != 0) {
0163: if (replacementLength != 0) {
0164: this .edits[this .editsIndex - 1] = new OptimizedReplaceEdit(
0165: previousOffset,
0166: previousLength + length,
0167: previousReplacement + replacement);
0168: } else if (previousLength + length == previousReplacementLength) {
0169: // check the characters. If they are identical, we can get rid of the previous edit
0170: boolean canBeRemoved = true;
0171: loop: for (int i = previousOffset; i < previousOffset
0172: + previousReplacementLength; i++) {
0173: if (scanner.source[i] != previousReplacement
0174: .charAt(i - previousOffset)) {
0175: this .edits[this .editsIndex - 1] = new OptimizedReplaceEdit(
0176: previousOffset,
0177: previousReplacementLength,
0178: previousReplacement);
0179: canBeRemoved = false;
0180: break loop;
0181: }
0182: }
0183: if (canBeRemoved) {
0184: if (this .currentAlignment != null) {
0185: final Location location = this .currentAlignment.location;
0186: if (location.editsIndex == this .editsIndex) {
0187: location.editsIndex--;
0188: location.textEdit = previous;
0189: }
0190: }
0191: this .editsIndex--;
0192: }
0193: } else {
0194: this .edits[this .editsIndex - 1] = new OptimizedReplaceEdit(
0195: previousOffset,
0196: previousLength + length,
0197: previousReplacement);
0198: }
0199: } else {
0200: if (replacementLength != 0) {
0201: this .edits[this .editsIndex - 1] = new OptimizedReplaceEdit(
0202: previousOffset, previousLength,
0203: previousReplacement + replacement);
0204: }
0205: }
0206: } else if ((offset + length == previousOffset)
0207: && (previousLength + length == replacementLength
0208: + previousReplacementLength)) {
0209: // check if both edits corresponds to the orignal source code
0210: boolean canBeRemoved = true;
0211: String totalReplacement = replacement
0212: + previousReplacement;
0213: loop: for (int i = 0; i < previousLength + length; i++) {
0214: if (scanner.source[i + offset] != totalReplacement
0215: .charAt(i)) {
0216: this .edits[this .editsIndex - 1] = new OptimizedReplaceEdit(
0217: offset, previousLength + length,
0218: totalReplacement);
0219: canBeRemoved = false;
0220: break loop;
0221: }
0222: }
0223: if (canBeRemoved) {
0224: if (this .currentAlignment != null) {
0225: final Location location = this .currentAlignment.location;
0226: if (location.editsIndex == this .editsIndex) {
0227: location.editsIndex--;
0228: location.textEdit = previous;
0229: }
0230: }
0231: this .editsIndex--;
0232: }
0233: } else {
0234: this .edits[this .editsIndex++] = new OptimizedReplaceEdit(
0235: offset, length, replacement);
0236: }
0237: } else {
0238: this .edits[this .editsIndex++] = new OptimizedReplaceEdit(
0239: offset, length, replacement);
0240: }
0241: }
0242:
0243: public final void addReplaceEdit(int start, int end,
0244: String replacement) {
0245: if (this .edits.length == this .editsIndex) {
0246: // resize
0247: resize();
0248: }
0249: addOptimizedReplaceEdit(start, end - start + 1, replacement);
0250: }
0251:
0252: public void alignFragment(Alignment alignment, int fragmentIndex) {
0253: alignment.fragmentIndex = fragmentIndex;
0254: alignment.checkColumn();
0255: alignment.performFragmentEffect();
0256: }
0257:
0258: public void checkNLSTag(int sourceStart) {
0259: if (hasNLSTag(sourceStart)) {
0260: this .nlsTagCounter++;
0261: }
0262: }
0263:
0264: public void consumeNextToken() {
0265: printComment();
0266: try {
0267: this .currentToken = this .scanner.getNextToken();
0268: addDeleteEdit(this .scanner.getCurrentTokenStartPosition(),
0269: this .scanner.getCurrentTokenEndPosition());
0270: } catch (InvalidInputException e) {
0271: throw new AbortFormatting(e);
0272: }
0273: }
0274:
0275: public Alignment createAlignment(String name, int mode, int count,
0276: int sourceRestart) {
0277: return createAlignment(name, mode, Alignment.R_INNERMOST,
0278: count, sourceRestart);
0279: }
0280:
0281: public Alignment createAlignment(String name, int mode, int count,
0282: int sourceRestart, boolean adjust) {
0283: return createAlignment(name, mode, Alignment.R_INNERMOST,
0284: count, sourceRestart, adjust);
0285: }
0286:
0287: public Alignment createAlignment(String name, int mode,
0288: int tieBreakRule, int count, int sourceRestart) {
0289: return createAlignment(name, mode, tieBreakRule, count,
0290: sourceRestart,
0291: this .formatter.preferences.continuation_indentation,
0292: false);
0293: }
0294:
0295: public Alignment createAlignment(String name, int mode, int count,
0296: int sourceRestart, int continuationIndent, boolean adjust) {
0297: return createAlignment(name, mode, Alignment.R_INNERMOST,
0298: count, sourceRestart, continuationIndent, adjust);
0299: }
0300:
0301: public Alignment createAlignment(String name, int mode,
0302: int tieBreakRule, int count, int sourceRestart,
0303: int continuationIndent, boolean adjust) {
0304: Alignment alignment = new Alignment(name, mode, tieBreakRule,
0305: this , count, sourceRestart, continuationIndent);
0306: // adjust break indentation
0307: if (adjust && this .memberAlignment != null) {
0308: Alignment current = this .memberAlignment;
0309: while (current.enclosing != null) {
0310: current = current.enclosing;
0311: }
0312: if ((current.mode & Alignment.M_MULTICOLUMN) != 0) {
0313: final int indentSize = this .indentationSize;
0314: switch (current.chunkKind) {
0315: case Alignment.CHUNK_METHOD:
0316: case Alignment.CHUNK_TYPE:
0317: if ((mode & Alignment.M_INDENT_BY_ONE) != 0) {
0318: alignment.breakIndentationLevel = this .indentationLevel
0319: + indentSize;
0320: } else {
0321: alignment.breakIndentationLevel = this .indentationLevel
0322: + continuationIndent * indentSize;
0323: }
0324: alignment.update();
0325: break;
0326: case Alignment.CHUNK_FIELD:
0327: if ((mode & Alignment.M_INDENT_BY_ONE) != 0) {
0328: alignment.breakIndentationLevel = current.originalIndentationLevel
0329: + indentSize;
0330: } else {
0331: alignment.breakIndentationLevel = current.originalIndentationLevel
0332: + continuationIndent * indentSize;
0333: }
0334: alignment.update();
0335: break;
0336: }
0337: } else {
0338: switch (current.mode & Alignment.SPLIT_MASK) {
0339: case Alignment.M_COMPACT_SPLIT:
0340: case Alignment.M_COMPACT_FIRST_BREAK_SPLIT:
0341: case Alignment.M_NEXT_PER_LINE_SPLIT:
0342: case Alignment.M_NEXT_SHIFTED_SPLIT:
0343: case Alignment.M_ONE_PER_LINE_SPLIT:
0344: final int indentSize = this .indentationSize;
0345: switch (current.chunkKind) {
0346: case Alignment.CHUNK_METHOD:
0347: case Alignment.CHUNK_TYPE:
0348: if ((mode & Alignment.M_INDENT_BY_ONE) != 0) {
0349: alignment.breakIndentationLevel = this .indentationLevel
0350: + indentSize;
0351: } else {
0352: alignment.breakIndentationLevel = this .indentationLevel
0353: + continuationIndent * indentSize;
0354: }
0355: alignment.update();
0356: break;
0357: case Alignment.CHUNK_FIELD:
0358: if ((mode & Alignment.M_INDENT_BY_ONE) != 0) {
0359: alignment.breakIndentationLevel = current.originalIndentationLevel
0360: + indentSize;
0361: } else {
0362: alignment.breakIndentationLevel = current.originalIndentationLevel
0363: + continuationIndent * indentSize;
0364: }
0365: alignment.update();
0366: break;
0367: }
0368: break;
0369: }
0370: }
0371: }
0372: return alignment;
0373: }
0374:
0375: public Alignment createMemberAlignment(String name, int mode,
0376: int count, int sourceRestart) {
0377: Alignment mAlignment = createAlignment(name, mode,
0378: Alignment.R_INNERMOST, count, sourceRestart);
0379: mAlignment.breakIndentationLevel = this .indentationLevel;
0380: return mAlignment;
0381: }
0382:
0383: public void enterAlignment(Alignment alignment) {
0384: alignment.enclosing = this .currentAlignment;
0385: alignment.location.lastLocalDeclarationSourceStart = this .formatter.lastLocalDeclarationSourceStart;
0386: this .currentAlignment = alignment;
0387: }
0388:
0389: public void enterMemberAlignment(Alignment alignment) {
0390: alignment.enclosing = this .memberAlignment;
0391: alignment.location.lastLocalDeclarationSourceStart = this .formatter.lastLocalDeclarationSourceStart;
0392: this .memberAlignment = alignment;
0393: }
0394:
0395: public void exitAlignment(Alignment alignment,
0396: boolean discardAlignment) {
0397: Alignment current = this .currentAlignment;
0398: while (current != null) {
0399: if (current == alignment)
0400: break;
0401: current = current.enclosing;
0402: }
0403: if (current == null) {
0404: throw new AbortFormatting(
0405: "could not find matching alignment: " + alignment); //$NON-NLS-1$
0406: }
0407: this .indentationLevel = alignment.location.outputIndentationLevel;
0408: this .numberOfIndentations = alignment.location.numberOfIndentations;
0409: this .formatter.lastLocalDeclarationSourceStart = alignment.location.lastLocalDeclarationSourceStart;
0410: if (discardAlignment) {
0411: this .currentAlignment = alignment.enclosing;
0412: }
0413: }
0414:
0415: public void exitMemberAlignment(Alignment alignment) {
0416: Alignment current = this .memberAlignment;
0417: while (current != null) {
0418: if (current == alignment)
0419: break;
0420: current = current.enclosing;
0421: }
0422: if (current == null) {
0423: throw new AbortFormatting(
0424: "could not find matching alignment: " + alignment); //$NON-NLS-1$
0425: }
0426: this .indentationLevel = current.location.outputIndentationLevel;
0427: this .numberOfIndentations = current.location.numberOfIndentations;
0428: this .formatter.lastLocalDeclarationSourceStart = alignment.location.lastLocalDeclarationSourceStart;
0429: this .memberAlignment = current.enclosing;
0430: }
0431:
0432: public Alignment getAlignment(String name) {
0433: if (this .currentAlignment != null) {
0434: return this .currentAlignment.getAlignment(name);
0435: }
0436: return null;
0437: }
0438:
0439: /**
0440: * Answer actual indentation level based on true column position
0441: * @return int
0442: */
0443: public int getColumnIndentationLevel() {
0444: return this .column - 1;
0445: }
0446:
0447: public final int getCommentIndex(int position) {
0448: if (this .commentPositions == null)
0449: return -1;
0450: int length = this .commentPositions.length;
0451: if (length == 0) {
0452: return -1;
0453: }
0454: int g = 0, d = length - 1;
0455: int m = 0;
0456: while (g <= d) {
0457: m = g + (d - g) / 2;
0458: int bound = this .commentPositions[m][1];
0459: if (bound < 0) {
0460: bound = -bound;
0461: }
0462: if (bound < position) {
0463: g = m + 1;
0464: } else if (bound > position) {
0465: d = m - 1;
0466: } else {
0467: return m;
0468: }
0469: }
0470: return -(g + 1);
0471: }
0472:
0473: private int getCurrentCommentOffset(int start) {
0474: int linePtr = -Arrays.binarySearch(this .lineEnds, start);
0475: int offset = 0;
0476: int beginningOfLine = this .getLineEnd(linePtr - 1);
0477: if (beginningOfLine == -1) {
0478: beginningOfLine = 0;
0479: }
0480: int currentStartPosition = start;
0481: char[] source = scanner.source;
0482:
0483: // find the position of the beginning of the line containing the comment
0484: while (beginningOfLine > currentStartPosition) {
0485: if (linePtr > 0) {
0486: beginningOfLine = this .getLineEnd(--linePtr);
0487: } else {
0488: beginningOfLine = 0;
0489: break;
0490: }
0491: }
0492: for (int i = currentStartPosition - 1; i >= beginningOfLine; i--) {
0493: char currentCharacter = source[i];
0494: switch (currentCharacter) {
0495: case '\t':
0496: offset += this .tabLength;
0497: break;
0498: case ' ':
0499: offset++;
0500: break;
0501: case '\r':
0502: case '\n':
0503: break;
0504: default:
0505: return offset;
0506: }
0507: }
0508: return offset;
0509: }
0510:
0511: public String getEmptyLines(int linesNumber) {
0512: if (this .nlsTagCounter > 0) {
0513: return Util.EMPTY_STRING;
0514: }
0515: StringBuffer buffer = new StringBuffer();
0516: if (lastNumberOfNewLines == 0) {
0517: linesNumber++; // add an extra line breaks
0518: for (int i = 0; i < linesNumber; i++) {
0519: if (indentEmptyLines)
0520: printIndentationIfNecessary(buffer);
0521: buffer.append(this .lineSeparator);
0522: }
0523: lastNumberOfNewLines += linesNumber;
0524: line += linesNumber;
0525: column = 1;
0526: needSpace = false;
0527: this .pendingSpace = false;
0528: } else if (lastNumberOfNewLines == 1) {
0529: for (int i = 0; i < linesNumber; i++) {
0530: if (indentEmptyLines)
0531: printIndentationIfNecessary(buffer);
0532: buffer.append(this .lineSeparator);
0533: }
0534: lastNumberOfNewLines += linesNumber;
0535: line += linesNumber;
0536: column = 1;
0537: needSpace = false;
0538: this .pendingSpace = false;
0539: } else {
0540: if ((lastNumberOfNewLines - 1) >= linesNumber) {
0541: // there is no need to add new lines
0542: return Util.EMPTY_STRING;
0543: }
0544: final int realNewLineNumber = linesNumber
0545: - lastNumberOfNewLines + 1;
0546: for (int i = 0; i < realNewLineNumber; i++) {
0547: if (indentEmptyLines)
0548: printIndentationIfNecessary(buffer);
0549: buffer.append(this .lineSeparator);
0550: }
0551: lastNumberOfNewLines += realNewLineNumber;
0552: line += realNewLineNumber;
0553: column = 1;
0554: needSpace = false;
0555: this .pendingSpace = false;
0556: }
0557: return String.valueOf(buffer);
0558: }
0559:
0560: public OptimizedReplaceEdit getLastEdit() {
0561: if (this .editsIndex > 0) {
0562: return this .edits[this .editsIndex - 1];
0563: }
0564: return null;
0565: }
0566:
0567: public final int getLineEnd(int lineNumber) {
0568: if (this .lineEnds == null)
0569: return -1;
0570: if (lineNumber >= this .lineEnds.length + 1)
0571: return this .scannerEndPosition;
0572: if (lineNumber <= 0)
0573: return -1;
0574: return this .lineEnds[lineNumber - 1]; // next line start one character behind the lineEnd of the previous line
0575: }
0576:
0577: Alignment getMemberAlignment() {
0578: return this .memberAlignment;
0579: }
0580:
0581: public String getNewLine() {
0582: if (this .nlsTagCounter > 0) {
0583: return Util.EMPTY_STRING;
0584: }
0585: if (lastNumberOfNewLines >= 1) {
0586: column = 1; // ensure that the scribe is at the beginning of a new line
0587: return Util.EMPTY_STRING;
0588: }
0589: line++;
0590: lastNumberOfNewLines = 1;
0591: column = 1;
0592: needSpace = false;
0593: this .pendingSpace = false;
0594: return this .lineSeparator;
0595: }
0596:
0597: /**
0598: * Answer next indentation level based on column estimated position
0599: * (if column is not indented, then use indentationLevel)
0600: */
0601: public int getNextIndentationLevel(int someColumn) {
0602: int indent = someColumn - 1;
0603: if (indent == 0)
0604: return this .indentationLevel;
0605: if (this .tabChar == DefaultCodeFormatterOptions.TAB) {
0606: if (this .useTabsOnlyForLeadingIndents) {
0607: return indent;
0608: }
0609: int rem = indent % this .indentationSize;
0610: int addition = rem == 0 ? 0 : this .indentationSize - rem; // round to superior
0611: return indent + addition;
0612: } else {
0613: return indent;
0614: }
0615: }
0616:
0617: private String getPreserveEmptyLines(int count) {
0618: if (count > 0) {
0619: if (this .formatter.preferences.number_of_empty_lines_to_preserve != 0) {
0620: int linesToPreserve = Math
0621: .min(
0622: count,
0623: this .formatter.preferences.number_of_empty_lines_to_preserve);
0624: return this .getEmptyLines(linesToPreserve);
0625: } else {
0626: return getNewLine();
0627: }
0628: }
0629: return Util.EMPTY_STRING;
0630: }
0631:
0632: public TextEdit getRootEdit() {
0633: MultiTextEdit edit = null;
0634: int length = this .textRegionEnd - this .textRegionStart + 1;
0635: if (this .textRegionStart <= 0) {
0636: if (length <= 0) {
0637: edit = new MultiTextEdit(0, 0);
0638: } else {
0639: edit = new MultiTextEdit(0, this .textRegionEnd + 1);
0640: }
0641: } else {
0642: edit = new MultiTextEdit(this .textRegionStart,
0643: this .textRegionEnd - this .textRegionStart + 1);
0644: }
0645: for (int i = 0, max = this .editsIndex; i < max; i++) {
0646: OptimizedReplaceEdit currentEdit = edits[i];
0647: if (isValidEdit(currentEdit)) {
0648: edit.addChild(new ReplaceEdit(currentEdit.offset,
0649: currentEdit.length, currentEdit.replacement));
0650: }
0651: }
0652: this .edits = null;
0653: return edit;
0654: }
0655:
0656: public void handleLineTooLong() {
0657: // search for closest breakable alignment, using tiebreak rules
0658: // look for outermost breakable one
0659: int relativeDepth = 0, outerMostDepth = -1;
0660: Alignment targetAlignment = this .currentAlignment;
0661: while (targetAlignment != null) {
0662: if (targetAlignment.tieBreakRule == Alignment.R_OUTERMOST
0663: && targetAlignment.couldBreak()) {
0664: outerMostDepth = relativeDepth;
0665: }
0666: targetAlignment = targetAlignment.enclosing;
0667: relativeDepth++;
0668: }
0669: if (outerMostDepth >= 0) {
0670: throw new AlignmentException(
0671: AlignmentException.LINE_TOO_LONG, outerMostDepth);
0672: }
0673: // look for innermost breakable one
0674: relativeDepth = 0;
0675: targetAlignment = this .currentAlignment;
0676: while (targetAlignment != null) {
0677: if (targetAlignment.couldBreak()) {
0678: throw new AlignmentException(
0679: AlignmentException.LINE_TOO_LONG, relativeDepth);
0680: }
0681: targetAlignment = targetAlignment.enclosing;
0682: relativeDepth++;
0683: }
0684: // did not find any breakable location - proceed
0685: }
0686:
0687: /*
0688: * Check if there is a NLS tag on this line. If yes, return true, returns false otherwise.
0689: */
0690: private boolean hasNLSTag(int sourceStart) {
0691: // search the last comment where commentEnd < current lineEnd
0692: if (this .lineEnds == null)
0693: return false;
0694: int index = Arrays.binarySearch(this .lineEnds, sourceStart);
0695: int currentLineEnd = this .getLineEnd(-index);
0696: if (currentLineEnd != -1) {
0697: int commentIndex = getCommentIndex(currentLineEnd);
0698: if (commentIndex < 0) {
0699: commentIndex = -commentIndex - 2;
0700: }
0701: if (commentIndex >= 0
0702: && commentIndex < this .commentPositions.length) {
0703: int start = this .commentPositions[commentIndex][0];
0704: if (start < 0) {
0705: start = -start;
0706: // check that we are on the same line
0707: int lineIndexForComment = Arrays.binarySearch(
0708: this .lineEnds, start);
0709: if (lineIndexForComment == index) {
0710: return CharOperation.indexOf(
0711: Scanner.TAG_PREFIX,
0712: this .scanner.source, true, start,
0713: currentLineEnd) != -1;
0714: }
0715: }
0716: }
0717: }
0718: return false;
0719: }
0720:
0721: public void indent() {
0722: this .indentationLevel += this .indentationSize;
0723: this .numberOfIndentations++;
0724: }
0725:
0726: /**
0727: * @param compilationUnitSource
0728: */
0729: public void initializeScanner(char[] compilationUnitSource) {
0730: this .scanner.setSource(compilationUnitSource);
0731: this .scannerEndPosition = compilationUnitSource.length;
0732: this .scanner.resetTo(0, this .scannerEndPosition - 1);
0733: this .edits = new OptimizedReplaceEdit[INITIAL_SIZE];
0734: }
0735:
0736: private boolean isOnFirstColumn(int start) {
0737: if (this .lineEnds == null)
0738: return start == 0;
0739: int index = Arrays.binarySearch(this .lineEnds, start);
0740: // we want the line end of the previous line
0741: int previousLineEnd = this .getLineEnd(-index - 1);
0742: return previousLineEnd != -1 && previousLineEnd == start - 1;
0743: }
0744:
0745: private boolean isValidEdit(OptimizedReplaceEdit edit) {
0746: final int editLength = edit.length;
0747: final int editReplacementLength = edit.replacement.length();
0748: final int editOffset = edit.offset;
0749: if (editLength != 0) {
0750: if (this .textRegionStart <= editOffset
0751: && (editOffset + editLength - 1) <= this .textRegionEnd) {
0752: if (editReplacementLength != 0
0753: && editLength == editReplacementLength) {
0754: for (int i = editOffset, max = editOffset
0755: + editLength; i < max; i++) {
0756: if (scanner.source[i] != edit.replacement
0757: .charAt(i - editOffset)) {
0758: return true;
0759: }
0760: }
0761: return false;
0762: } else {
0763: return true;
0764: }
0765: } else if (editOffset + editLength == this .textRegionStart) {
0766: int i = editOffset;
0767: for (int max = editOffset + editLength; i < max; i++) {
0768: int replacementStringIndex = i - editOffset;
0769: if (replacementStringIndex >= editReplacementLength
0770: || scanner.source[i] != edit.replacement
0771: .charAt(replacementStringIndex)) {
0772: break;
0773: }
0774: }
0775: if (i - editOffset != editReplacementLength
0776: && i != editOffset + editLength - 1) {
0777: edit.offset = textRegionStart;
0778: edit.length = 0;
0779: edit.replacement = edit.replacement.substring(i
0780: - editOffset);
0781: return true;
0782: }
0783: }
0784: } else if (this .textRegionStart <= editOffset
0785: && editOffset <= this .textRegionEnd) {
0786: return true;
0787: } else if (editOffset == this .scannerEndPosition
0788: && editOffset == this .textRegionEnd + 1) {
0789: return true;
0790: }
0791: return false;
0792: }
0793:
0794: private void preserveEmptyLines(int count, int insertPosition) {
0795: if (count > 0) {
0796: if (this .formatter.preferences.number_of_empty_lines_to_preserve != 0) {
0797: int linesToPreserve = Math
0798: .min(
0799: count,
0800: this .formatter.preferences.number_of_empty_lines_to_preserve);
0801: this .printEmptyLines(linesToPreserve, insertPosition);
0802: } else {
0803: printNewLine(insertPosition);
0804: }
0805: }
0806: }
0807:
0808: private void print(char[] s, boolean considerSpaceIfAny) {
0809: if (checkLineWrapping && s.length + column > this .pageWidth) {
0810: handleLineTooLong();
0811: }
0812: this .lastNumberOfNewLines = 0;
0813: if (this .indentationLevel != 0) {
0814: printIndentationIfNecessary();
0815: }
0816: if (considerSpaceIfAny) {
0817: this .space();
0818: }
0819: if (this .pendingSpace) {
0820: this .addInsertEdit(this .scanner
0821: .getCurrentTokenStartPosition(), " "); //$NON-NLS-1$
0822: }
0823: this .pendingSpace = false;
0824: this .needSpace = false;
0825: column += s.length;
0826: needSpace = true;
0827: }
0828:
0829: private void printBlockComment(char[] s, boolean isJavadoc) {
0830: int currentTokenStartPosition = this .scanner
0831: .getCurrentTokenStartPosition();
0832: int currentTokenEndPosition = this .scanner
0833: .getCurrentTokenEndPosition() + 1;
0834:
0835: this .scanner.resetTo(currentTokenStartPosition,
0836: currentTokenEndPosition - 1);
0837: int currentCharacter;
0838: boolean isNewLine = false;
0839: int start = currentTokenStartPosition;
0840: int nextCharacterStart = currentTokenStartPosition;
0841: int previousStart = currentTokenStartPosition;
0842: boolean onFirstColumn = isOnFirstColumn(start);
0843:
0844: boolean indentComment = false;
0845: if (this .indentationLevel != 0) {
0846: if (isJavadoc
0847: || !this .formatter.preferences.never_indent_block_comments_on_first_column
0848: || !onFirstColumn) {
0849: indentComment = true;
0850: printIndentationIfNecessary();
0851: }
0852: }
0853: if (this .pendingSpace) {
0854: this .addInsertEdit(currentTokenStartPosition, " "); //$NON-NLS-1$
0855: }
0856: this .needSpace = false;
0857: this .pendingSpace = false;
0858:
0859: int currentCommentOffset = onFirstColumn ? 0
0860: : getCurrentCommentOffset(start);
0861: boolean formatComment = (isJavadoc && formatJavadocComment)
0862: || (!isJavadoc && formatBlockComment);
0863:
0864: while (nextCharacterStart <= currentTokenEndPosition
0865: && (currentCharacter = this .scanner.getNextChar()) != -1) {
0866: nextCharacterStart = this .scanner.currentPosition;
0867:
0868: switch (currentCharacter) {
0869: case '\r':
0870: start = previousStart;
0871: isNewLine = true;
0872: if (this .scanner.getNextChar('\n')) {
0873: currentCharacter = '\n';
0874: nextCharacterStart = this .scanner.currentPosition;
0875: }
0876: break;
0877: case '\n':
0878: start = previousStart;
0879: isNewLine = true;
0880: nextCharacterStart = this .scanner.currentPosition;
0881: break;
0882: default:
0883: if (isNewLine) {
0884: this .column = 1;
0885: this .line++;
0886: isNewLine = false;
0887:
0888: StringBuffer buffer = new StringBuffer();
0889: if (onFirstColumn) {
0890: // simply insert indentation if necessary
0891: buffer.append(this .lineSeparator);
0892: if (indentComment) {
0893: printIndentationIfNecessary(buffer);
0894: }
0895: if (formatComment) {
0896: if (ScannerHelper
0897: .isWhitespace((char) currentCharacter)) {
0898: int previousStartPosition = this .scanner.currentPosition;
0899: while (currentCharacter != -1
0900: && currentCharacter != '\r'
0901: && currentCharacter != '\n'
0902: && ScannerHelper
0903: .isWhitespace((char) currentCharacter)) {
0904: previousStart = nextCharacterStart;
0905: previousStartPosition = this .scanner.currentPosition;
0906: currentCharacter = this .scanner
0907: .getNextChar();
0908: nextCharacterStart = this .scanner.currentPosition;
0909: }
0910: if (currentCharacter == '\r'
0911: || currentCharacter == '\n') {
0912: nextCharacterStart = previousStartPosition;
0913: }
0914: }
0915: if (currentCharacter != '\r'
0916: && currentCharacter != '\n') {
0917: buffer.append(' ');
0918: }
0919: }
0920: } else {
0921: if (ScannerHelper
0922: .isWhitespace((char) currentCharacter)) {
0923: int previousStartPosition = this .scanner.currentPosition;
0924: int count = 0;
0925: loop: while (currentCharacter != -1
0926: && currentCharacter != '\r'
0927: && currentCharacter != '\n'
0928: && ScannerHelper
0929: .isWhitespace((char) currentCharacter)) {
0930: if (count >= currentCommentOffset) {
0931: break loop;
0932: }
0933: previousStart = nextCharacterStart;
0934: previousStartPosition = this .scanner.currentPosition;
0935: switch (currentCharacter) {
0936: case '\t':
0937: count += this .tabLength;
0938: break;
0939: default:
0940: count++;
0941: }
0942: currentCharacter = this .scanner
0943: .getNextChar();
0944: nextCharacterStart = this .scanner.currentPosition;
0945: }
0946: if (currentCharacter == '\r'
0947: || currentCharacter == '\n') {
0948: nextCharacterStart = previousStartPosition;
0949: }
0950: }
0951: buffer.append(this .lineSeparator);
0952: if (indentComment) {
0953: printIndentationIfNecessary(buffer);
0954: }
0955: if (formatComment) {
0956: int previousStartTemp = previousStart;
0957: int nextCharacterStartTemp = nextCharacterStart;
0958: while (currentCharacter != -1
0959: && currentCharacter != '\r'
0960: && currentCharacter != '\n'
0961: && ScannerHelper
0962: .isWhitespace((char) currentCharacter)) {
0963: previousStart = nextCharacterStart;
0964: currentCharacter = this .scanner
0965: .getNextChar();
0966: nextCharacterStart = this .scanner.currentPosition;
0967: }
0968: if (currentCharacter == '*') {
0969: buffer.append(' ');
0970: } else {
0971: previousStart = previousStartTemp;
0972: nextCharacterStart = nextCharacterStartTemp;
0973: }
0974: this .scanner.currentPosition = nextCharacterStart;
0975: }
0976: }
0977: addReplaceEdit(start, previousStart - 1, String
0978: .valueOf(buffer));
0979: } else {
0980: this .column += (nextCharacterStart - previousStart);
0981: }
0982: }
0983: previousStart = nextCharacterStart;
0984: this .scanner.currentPosition = nextCharacterStart;
0985: }
0986: this .lastNumberOfNewLines = 0;
0987: needSpace = false;
0988: this .scanner.resetTo(currentTokenEndPosition,
0989: this .scannerEndPosition - 1);
0990: if (isJavadoc) {
0991: printNewLine();
0992: }
0993: }
0994:
0995: public void printEndOfCompilationUnit() {
0996: try {
0997: // if we have a space between two tokens we ensure it will be dumped in the formatted string
0998: int currentTokenStartPosition = this .scanner.currentPosition;
0999: boolean hasComment = false;
1000: boolean hasLineComment = false;
1001: boolean hasWhitespace = false;
1002: int count = 0;
1003: while (true) {
1004: this .currentToken = this .scanner.getNextToken();
1005: switch (this .currentToken) {
1006: case TerminalTokens.TokenNameWHITESPACE:
1007: char[] whiteSpaces = this .scanner
1008: .getCurrentTokenSource();
1009: count = 0;
1010: for (int i = 0, max = whiteSpaces.length; i < max; i++) {
1011: switch (whiteSpaces[i]) {
1012: case '\r':
1013: if ((i + 1) < max) {
1014: if (whiteSpaces[i + 1] == '\n') {
1015: i++;
1016: }
1017: }
1018: count++;
1019: break;
1020: case '\n':
1021: count++;
1022: }
1023: }
1024: if (count == 0) {
1025: hasWhitespace = true;
1026: addDeleteEdit(this .scanner
1027: .getCurrentTokenStartPosition(),
1028: this .scanner
1029: .getCurrentTokenEndPosition());
1030: } else if (hasComment) {
1031: if (count == 1) {
1032: this .printNewLine(this .scanner
1033: .getCurrentTokenStartPosition());
1034: } else {
1035: preserveEmptyLines(count - 1, this .scanner
1036: .getCurrentTokenStartPosition());
1037: }
1038: addDeleteEdit(this .scanner
1039: .getCurrentTokenStartPosition(),
1040: this .scanner
1041: .getCurrentTokenEndPosition());
1042: } else if (hasLineComment) {
1043: this .preserveEmptyLines(count, this .scanner
1044: .getCurrentTokenStartPosition());
1045: addDeleteEdit(this .scanner
1046: .getCurrentTokenStartPosition(),
1047: this .scanner
1048: .getCurrentTokenEndPosition());
1049: } else {
1050: addDeleteEdit(this .scanner
1051: .getCurrentTokenStartPosition(),
1052: this .scanner
1053: .getCurrentTokenEndPosition());
1054: }
1055: currentTokenStartPosition = this .scanner.currentPosition;
1056: break;
1057: case TerminalTokens.TokenNameCOMMENT_LINE:
1058: if (count >= 1) {
1059: if (count > 1) {
1060: preserveEmptyLines(count - 1, this .scanner
1061: .getCurrentTokenStartPosition());
1062: } else if (count == 1) {
1063: printNewLine(this .scanner
1064: .getCurrentTokenStartPosition());
1065: }
1066: } else if (hasWhitespace) {
1067: space();
1068: }
1069: hasWhitespace = false;
1070: this .printLineComment(this .scanner
1071: .getRawTokenSource());
1072: currentTokenStartPosition = this .scanner.currentPosition;
1073: hasLineComment = true;
1074: count = 0;
1075: break;
1076: case TerminalTokens.TokenNameCOMMENT_BLOCK:
1077: if (count >= 1) {
1078: if (count > 1) {
1079: preserveEmptyLines(count - 1, this .scanner
1080: .getCurrentTokenStartPosition());
1081: } else if (count == 1) {
1082: printNewLine(this .scanner
1083: .getCurrentTokenStartPosition());
1084: }
1085: } else if (hasWhitespace) {
1086: space();
1087: }
1088: hasWhitespace = false;
1089: this .printBlockComment(this .scanner
1090: .getRawTokenSource(), false);
1091: currentTokenStartPosition = this .scanner.currentPosition;
1092: hasLineComment = false;
1093: hasComment = true;
1094: count = 0;
1095: break;
1096: case TerminalTokens.TokenNameCOMMENT_JAVADOC:
1097: if (count >= 1) {
1098: if (count > 1) {
1099: preserveEmptyLines(count - 1, this .scanner
1100: .getCurrentTokenStartPosition());
1101: } else if (count == 1) {
1102: printNewLine(this .scanner
1103: .getCurrentTokenStartPosition());
1104: }
1105: } else if (hasWhitespace) {
1106: space();
1107: }
1108: hasWhitespace = false;
1109: this .printBlockComment(this .scanner
1110: .getRawTokenSource(), true);
1111: currentTokenStartPosition = this .scanner.currentPosition;
1112: hasLineComment = false;
1113: hasComment = true;
1114: count = 0;
1115: break;
1116: case TerminalTokens.TokenNameSEMICOLON:
1117: char[] currentTokenSource = this .scanner
1118: .getRawTokenSource();
1119: this
1120: .print(
1121: currentTokenSource,
1122: this .formatter.preferences.insert_space_before_semicolon);
1123: break;
1124: case TerminalTokens.TokenNameEOF:
1125: if (count >= 1
1126: || this .formatter.preferences.insert_new_line_at_end_of_file_if_missing) {
1127: this .printNewLine(this .scannerEndPosition);
1128: }
1129: return;
1130: default:
1131: // step back one token
1132: this .scanner.resetTo(currentTokenStartPosition,
1133: this .scannerEndPosition - 1);
1134: return;
1135: }
1136: }
1137: } catch (InvalidInputException e) {
1138: throw new AbortFormatting(e);
1139: }
1140: }
1141:
1142: public void printComment() {
1143: try {
1144: // if we have a space between two tokens we ensure it will be dumped in the formatted string
1145: int currentTokenStartPosition = this .scanner.currentPosition;
1146: boolean hasComment = false;
1147: boolean hasLineComment = false;
1148: boolean hasWhitespace = false;
1149: int count = 0;
1150: while ((this .currentToken = this .scanner.getNextToken()) != TerminalTokens.TokenNameEOF) {
1151: switch (this .currentToken) {
1152: case TerminalTokens.TokenNameWHITESPACE:
1153: char[] whiteSpaces = this .scanner
1154: .getCurrentTokenSource();
1155: count = 0;
1156: for (int i = 0, max = whiteSpaces.length; i < max; i++) {
1157: switch (whiteSpaces[i]) {
1158: case '\r':
1159: if ((i + 1) < max) {
1160: if (whiteSpaces[i + 1] == '\n') {
1161: i++;
1162: }
1163: }
1164: count++;
1165: break;
1166: case '\n':
1167: count++;
1168: }
1169: }
1170: if (count == 0) {
1171: hasWhitespace = true;
1172: addDeleteEdit(this .scanner
1173: .getCurrentTokenStartPosition(),
1174: this .scanner
1175: .getCurrentTokenEndPosition());
1176: } else if (hasComment) {
1177: if (count == 1) {
1178: this .printNewLine(this .scanner
1179: .getCurrentTokenStartPosition());
1180: } else {
1181: preserveEmptyLines(count - 1, this .scanner
1182: .getCurrentTokenStartPosition());
1183: }
1184: addDeleteEdit(this .scanner
1185: .getCurrentTokenStartPosition(),
1186: this .scanner
1187: .getCurrentTokenEndPosition());
1188: } else if (hasLineComment) {
1189: this .preserveEmptyLines(count, this .scanner
1190: .getCurrentTokenStartPosition());
1191: addDeleteEdit(this .scanner
1192: .getCurrentTokenStartPosition(),
1193: this .scanner
1194: .getCurrentTokenEndPosition());
1195: } else if (count != 0
1196: && this .formatter.preferences.number_of_empty_lines_to_preserve != 0) {
1197: addReplaceEdit(this .scanner
1198: .getCurrentTokenStartPosition(),
1199: this .scanner
1200: .getCurrentTokenEndPosition(),
1201: this .getPreserveEmptyLines(count - 1));
1202: } else {
1203: addDeleteEdit(this .scanner
1204: .getCurrentTokenStartPosition(),
1205: this .scanner
1206: .getCurrentTokenEndPosition());
1207: }
1208: currentTokenStartPosition = this .scanner.currentPosition;
1209: break;
1210: case TerminalTokens.TokenNameCOMMENT_LINE:
1211: if (count >= 1) {
1212: if (count > 1) {
1213: preserveEmptyLines(count - 1, this .scanner
1214: .getCurrentTokenStartPosition());
1215: } else if (count == 1) {
1216: printNewLine(this .scanner
1217: .getCurrentTokenStartPosition());
1218: }
1219: } else if (hasWhitespace) {
1220: space();
1221: }
1222: hasWhitespace = false;
1223: this .printLineComment(this .scanner
1224: .getRawTokenSource());
1225: currentTokenStartPosition = this .scanner.currentPosition;
1226: hasLineComment = true;
1227: count = 0;
1228: break;
1229: case TerminalTokens.TokenNameCOMMENT_BLOCK:
1230: if (count >= 1) {
1231: if (count > 1) {
1232: preserveEmptyLines(count - 1, this .scanner
1233: .getCurrentTokenStartPosition());
1234: } else if (count == 1) {
1235: printNewLine(this .scanner
1236: .getCurrentTokenStartPosition());
1237: }
1238: } else if (hasWhitespace) {
1239: space();
1240: }
1241: hasWhitespace = false;
1242: this .printBlockComment(this .scanner
1243: .getRawTokenSource(), false);
1244: currentTokenStartPosition = this .scanner.currentPosition;
1245: hasLineComment = false;
1246: hasComment = true;
1247: count = 0;
1248: break;
1249: case TerminalTokens.TokenNameCOMMENT_JAVADOC:
1250: if (count >= 1) {
1251: if (count > 1) {
1252: preserveEmptyLines(count - 1, this .scanner
1253: .getCurrentTokenStartPosition());
1254: } else if (count == 1) {
1255: printNewLine(this .scanner
1256: .getCurrentTokenStartPosition());
1257: }
1258: } else if (hasWhitespace) {
1259: space();
1260: }
1261: hasWhitespace = false;
1262: this .printBlockComment(this .scanner
1263: .getRawTokenSource(), true);
1264: currentTokenStartPosition = this .scanner.currentPosition;
1265: hasLineComment = false;
1266: hasComment = true;
1267: count = 0;
1268: break;
1269: default:
1270: // step back one token
1271: this .scanner.resetTo(currentTokenStartPosition,
1272: this .scannerEndPosition - 1);
1273: return;
1274: }
1275: }
1276: } catch (InvalidInputException e) {
1277: throw new AbortFormatting(e);
1278: }
1279: }
1280:
1281: private void printLineComment(char[] s) {
1282: int currentTokenStartPosition = this .scanner
1283: .getCurrentTokenStartPosition();
1284: int currentTokenEndPosition = this .scanner
1285: .getCurrentTokenEndPosition() + 1;
1286: if (CharOperation.indexOf(Scanner.TAG_PREFIX,
1287: this .scanner.source, true, currentTokenStartPosition,
1288: currentTokenEndPosition) != -1) {
1289: this .nlsTagCounter = 0;
1290: }
1291: this .scanner.resetTo(currentTokenStartPosition,
1292: currentTokenEndPosition - 1);
1293: int currentCharacter;
1294: int start = currentTokenStartPosition;
1295: int nextCharacterStart = currentTokenStartPosition;
1296:
1297: if (this .indentationLevel != 0) {
1298: if (!this .formatter.preferences.never_indent_line_comments_on_first_column
1299: || !isOnFirstColumn(start)) {
1300: printIndentationIfNecessary();
1301: }
1302: }
1303: if (this .pendingSpace) {
1304: this .addInsertEdit(currentTokenStartPosition, " "); //$NON-NLS-1$
1305: }
1306: this .needSpace = false;
1307: this .pendingSpace = false;
1308: int previousStart = currentTokenStartPosition;
1309:
1310: loop: while (nextCharacterStart <= currentTokenEndPosition
1311: && (currentCharacter = this .scanner.getNextChar()) != -1) {
1312: nextCharacterStart = this .scanner.currentPosition;
1313:
1314: switch (currentCharacter) {
1315: case '\r':
1316: start = previousStart;
1317: break loop;
1318: case '\n':
1319: start = previousStart;
1320: break loop;
1321: }
1322: previousStart = nextCharacterStart;
1323: }
1324: if (start != currentTokenStartPosition) {
1325: // this means that the line comment doesn't end the file
1326: addReplaceEdit(start, currentTokenEndPosition - 1,
1327: lineSeparator);
1328: this .line++;
1329: this .column = 1;
1330: this .lastNumberOfNewLines = 1;
1331: }
1332: this .needSpace = false;
1333: this .pendingSpace = false;
1334: // realign to the proper value
1335: if (this .currentAlignment != null) {
1336: if (this .memberAlignment != null) {
1337: // select the last alignment
1338: if (this .currentAlignment.location.inputOffset > this .memberAlignment.location.inputOffset) {
1339: if (this .currentAlignment.couldBreak()
1340: && this .currentAlignment.wasSplit) {
1341: this .currentAlignment.performFragmentEffect();
1342: }
1343: } else {
1344: this .indentationLevel = Math.max(
1345: this .indentationLevel,
1346: this .memberAlignment.breakIndentationLevel);
1347: }
1348: } else if (this .currentAlignment.couldBreak()
1349: && this .currentAlignment.wasSplit) {
1350: this .currentAlignment.performFragmentEffect();
1351: }
1352: }
1353: this .scanner.resetTo(currentTokenEndPosition,
1354: this .scannerEndPosition - 1);
1355: }
1356:
1357: public void printEmptyLines(int linesNumber) {
1358: this .printEmptyLines(linesNumber, this .scanner
1359: .getCurrentTokenEndPosition() + 1);
1360: }
1361:
1362: private void printEmptyLines(int linesNumber, int insertPosition) {
1363: final String buffer = getEmptyLines(linesNumber);
1364: if (Util.EMPTY_STRING == buffer)
1365: return;
1366:
1367: addInsertEdit(insertPosition, buffer);
1368: }
1369:
1370: void printIndentationIfNecessary() {
1371: StringBuffer buffer = new StringBuffer();
1372: printIndentationIfNecessary(buffer);
1373: if (buffer.length() > 0) {
1374: addInsertEdit(this .scanner.getCurrentTokenStartPosition(),
1375: buffer.toString());
1376: this .pendingSpace = false;
1377: }
1378: }
1379:
1380: private void printIndentationIfNecessary(StringBuffer buffer) {
1381: switch (this .tabChar) {
1382: case DefaultCodeFormatterOptions.TAB:
1383: boolean useTabsForLeadingIndents = this .useTabsOnlyForLeadingIndents;
1384: int numberOfLeadingIndents = this .numberOfIndentations;
1385: int indentationsAsTab = 0;
1386: if (useTabsForLeadingIndents) {
1387: while (this .column <= this .indentationLevel) {
1388: if (indentationsAsTab < numberOfLeadingIndents) {
1389: buffer.append('\t');
1390: indentationsAsTab++;
1391: int complement = this .tabLength
1392: - ((this .column - 1) % this .tabLength); // amount of space
1393: this .column += complement;
1394: this .needSpace = false;
1395: } else {
1396: buffer.append(' ');
1397: this .column++;
1398: this .needSpace = false;
1399: }
1400: }
1401: } else {
1402: while (this .column <= this .indentationLevel) {
1403: buffer.append('\t');
1404: int complement = this .tabLength
1405: - ((this .column - 1) % this .tabLength); // amount of space
1406: this .column += complement;
1407: this .needSpace = false;
1408: }
1409: }
1410: break;
1411: case DefaultCodeFormatterOptions.SPACE:
1412: while (this .column <= this .indentationLevel) {
1413: buffer.append(' ');
1414: this .column++;
1415: this .needSpace = false;
1416: }
1417: break;
1418: case DefaultCodeFormatterOptions.MIXED:
1419: useTabsForLeadingIndents = this .useTabsOnlyForLeadingIndents;
1420: numberOfLeadingIndents = this .numberOfIndentations;
1421: indentationsAsTab = 0;
1422: if (useTabsForLeadingIndents) {
1423: final int columnForLeadingIndents = numberOfLeadingIndents
1424: * this .indentationSize;
1425: while (this .column <= this .indentationLevel) {
1426: if (this .column <= columnForLeadingIndents) {
1427: if ((this .column - 1 + this .tabLength) <= this .indentationLevel) {
1428: buffer.append('\t');
1429: this .column += this .tabLength;
1430: } else if ((this .column - 1 + this .indentationSize) <= this .indentationLevel) {
1431: // print one indentation
1432: for (int i = 0, max = this .indentationSize; i < max; i++) {
1433: buffer.append(' ');
1434: this .column++;
1435: }
1436: } else {
1437: buffer.append(' ');
1438: this .column++;
1439: }
1440: } else {
1441: for (int i = this .column, max = this .indentationLevel; i <= max; i++) {
1442: buffer.append(' ');
1443: this .column++;
1444: }
1445: }
1446: this .needSpace = false;
1447: }
1448: } else {
1449: while (this .column <= this .indentationLevel) {
1450: if ((this .column - 1 + this .tabLength) <= this .indentationLevel) {
1451: buffer.append('\t');
1452: this .column += this .tabLength;
1453: } else if ((this .column - 1 + this .indentationSize) <= this .indentationLevel) {
1454: // print one indentation
1455: for (int i = 0, max = this .indentationSize; i < max; i++) {
1456: buffer.append(' ');
1457: this .column++;
1458: }
1459: } else {
1460: buffer.append(' ');
1461: this .column++;
1462: }
1463: this .needSpace = false;
1464: }
1465: }
1466: break;
1467: }
1468: }
1469:
1470: public void printModifiers(Annotation[] annotations,
1471: ASTVisitor visitor) {
1472: try {
1473: int annotationsLength = annotations != null ? annotations.length
1474: : 0;
1475: int annotationsIndex = 0;
1476: boolean isFirstModifier = true;
1477: int currentTokenStartPosition = this .scanner.currentPosition;
1478: boolean hasComment = false;
1479: boolean hasModifiers = false;
1480: while ((this .currentToken = this .scanner.getNextToken()) != TerminalTokens.TokenNameEOF) {
1481: switch (this .currentToken) {
1482: case TerminalTokens.TokenNamepublic:
1483: case TerminalTokens.TokenNameprotected:
1484: case TerminalTokens.TokenNameprivate:
1485: case TerminalTokens.TokenNamestatic:
1486: case TerminalTokens.TokenNameabstract:
1487: case TerminalTokens.TokenNamefinal:
1488: case TerminalTokens.TokenNamenative:
1489: case TerminalTokens.TokenNamesynchronized:
1490: case TerminalTokens.TokenNametransient:
1491: case TerminalTokens.TokenNamevolatile:
1492: case TerminalTokens.TokenNamestrictfp:
1493: hasModifiers = true;
1494: this .print(this .scanner.getRawTokenSource(),
1495: !isFirstModifier);
1496: isFirstModifier = false;
1497: currentTokenStartPosition = this .scanner.currentPosition;
1498: break;
1499: case TerminalTokens.TokenNameAT:
1500: hasModifiers = true;
1501: if (!isFirstModifier) {
1502: this .space();
1503: }
1504: this .scanner.resetTo(this .scanner
1505: .getCurrentTokenStartPosition(),
1506: this .scannerEndPosition - 1);
1507: if (annotationsIndex < annotationsLength) {
1508: annotations[annotationsIndex++].traverse(
1509: visitor, (BlockScope) null);
1510: if (this .formatter.preferences.insert_new_line_after_annotation) {
1511: this .printNewLine();
1512: }
1513: } else {
1514: return;
1515: }
1516: isFirstModifier = false;
1517: currentTokenStartPosition = this .scanner.currentPosition;
1518: break;
1519: case TerminalTokens.TokenNameCOMMENT_BLOCK:
1520: this .printBlockComment(this .scanner
1521: .getRawTokenSource(), false);
1522: currentTokenStartPosition = this .scanner.currentPosition;
1523: hasComment = true;
1524: break;
1525: case TerminalTokens.TokenNameCOMMENT_JAVADOC:
1526: this .printBlockComment(this .scanner
1527: .getRawTokenSource(), true);
1528: currentTokenStartPosition = this .scanner.currentPosition;
1529: hasComment = true;
1530: break;
1531: case TerminalTokens.TokenNameCOMMENT_LINE:
1532: this .printLineComment(this .scanner
1533: .getRawTokenSource());
1534: currentTokenStartPosition = this .scanner.currentPosition;
1535: break;
1536: case TerminalTokens.TokenNameWHITESPACE:
1537: addDeleteEdit(this .scanner
1538: .getCurrentTokenStartPosition(),
1539: this .scanner.getCurrentTokenEndPosition());
1540: int count = 0;
1541: char[] whiteSpaces = this .scanner
1542: .getCurrentTokenSource();
1543: for (int i = 0, max = whiteSpaces.length; i < max; i++) {
1544: switch (whiteSpaces[i]) {
1545: case '\r':
1546: if ((i + 1) < max) {
1547: if (whiteSpaces[i + 1] == '\n') {
1548: i++;
1549: }
1550: }
1551: count++;
1552: break;
1553: case '\n':
1554: count++;
1555: }
1556: }
1557: if (count >= 1 && hasComment) {
1558: printNewLine();
1559: }
1560: currentTokenStartPosition = this .scanner.currentPosition;
1561: hasComment = false;
1562: break;
1563: default:
1564: if (hasModifiers) {
1565: this .space();
1566: }
1567: // step back one token
1568: this .scanner.resetTo(currentTokenStartPosition,
1569: this .scannerEndPosition - 1);
1570: return;
1571: }
1572: }
1573: } catch (InvalidInputException e) {
1574: throw new AbortFormatting(e);
1575: }
1576: }
1577:
1578: public void printNewLine() {
1579: if (this .nlsTagCounter > 0) {
1580: return;
1581: }
1582: if (lastNumberOfNewLines >= 1) {
1583: column = 1; // ensure that the scribe is at the beginning of a new line
1584: return;
1585: }
1586: addInsertEdit(this .scanner.getCurrentTokenEndPosition() + 1,
1587: this .lineSeparator);
1588: line++;
1589: lastNumberOfNewLines = 1;
1590: column = 1;
1591: needSpace = false;
1592: this .pendingSpace = false;
1593: }
1594:
1595: public void printNewLine(int insertPosition) {
1596: if (this .nlsTagCounter > 0) {
1597: return;
1598: }
1599: if (lastNumberOfNewLines >= 1) {
1600: column = 1; // ensure that the scribe is at the beginning of a new line
1601: return;
1602: }
1603: addInsertEdit(insertPosition, this .lineSeparator);
1604: line++;
1605: lastNumberOfNewLines = 1;
1606: column = 1;
1607: needSpace = false;
1608: this .pendingSpace = false;
1609: }
1610:
1611: public void printNextToken(int expectedTokenType) {
1612: printNextToken(expectedTokenType, false);
1613: }
1614:
1615: public void printNextToken(int expectedTokenType,
1616: boolean considerSpaceIfAny) {
1617: printComment();
1618: try {
1619: this .currentToken = this .scanner.getNextToken();
1620: char[] currentTokenSource = this .scanner
1621: .getRawTokenSource();
1622: if (expectedTokenType != this .currentToken) {
1623: throw new AbortFormatting(
1624: "unexpected token type, expecting:" + expectedTokenType + ", actual:" + this .currentToken);//$NON-NLS-1$//$NON-NLS-2$
1625: }
1626: this .print(currentTokenSource, considerSpaceIfAny);
1627: } catch (InvalidInputException e) {
1628: throw new AbortFormatting(e);
1629: }
1630: }
1631:
1632: public void printNextToken(int[] expectedTokenTypes) {
1633: printNextToken(expectedTokenTypes, false);
1634: }
1635:
1636: public void printNextToken(int[] expectedTokenTypes,
1637: boolean considerSpaceIfAny) {
1638: printComment();
1639: try {
1640: this .currentToken = this .scanner.getNextToken();
1641: char[] currentTokenSource = this .scanner
1642: .getRawTokenSource();
1643: if (Arrays.binarySearch(expectedTokenTypes,
1644: this .currentToken) < 0) {
1645: StringBuffer expectations = new StringBuffer(5);
1646: for (int i = 0; i < expectedTokenTypes.length; i++) {
1647: if (i > 0) {
1648: expectations.append(',');
1649: }
1650: expectations.append(expectedTokenTypes[i]);
1651: }
1652: throw new AbortFormatting(
1653: "unexpected token type, expecting:[" + expectations.toString() + "], actual:" + this .currentToken);//$NON-NLS-1$//$NON-NLS-2$
1654: }
1655: this .print(currentTokenSource, considerSpaceIfAny);
1656: } catch (InvalidInputException e) {
1657: throw new AbortFormatting(e);
1658: }
1659: }
1660:
1661: public void printArrayQualifiedReference(int numberOfTokens,
1662: int sourceEnd) {
1663: int currentTokenStartPosition = this .scanner.currentPosition;
1664: int numberOfIdentifiers = 0;
1665: try {
1666: do {
1667: this .printComment();
1668: switch (this .currentToken = this .scanner.getNextToken()) {
1669: case TerminalTokens.TokenNameEOF:
1670: return;
1671: case TerminalTokens.TokenNameWHITESPACE:
1672: addDeleteEdit(this .scanner
1673: .getCurrentTokenStartPosition(),
1674: this .scanner.getCurrentTokenEndPosition());
1675: currentTokenStartPosition = this .scanner.currentPosition;
1676: break;
1677: case TerminalTokens.TokenNameCOMMENT_BLOCK:
1678: case TerminalTokens.TokenNameCOMMENT_JAVADOC:
1679: this .printBlockComment(this .scanner
1680: .getRawTokenSource(), false);
1681: currentTokenStartPosition = this .scanner.currentPosition;
1682: break;
1683: case TerminalTokens.TokenNameCOMMENT_LINE:
1684: this .printLineComment(this .scanner
1685: .getRawTokenSource());
1686: currentTokenStartPosition = this .scanner.currentPosition;
1687: break;
1688: case TerminalTokens.TokenNameIdentifier:
1689: this .print(this .scanner.getRawTokenSource(), false);
1690: currentTokenStartPosition = this .scanner.currentPosition;
1691: if (++numberOfIdentifiers == numberOfTokens) {
1692: this .scanner.resetTo(currentTokenStartPosition,
1693: this .scannerEndPosition - 1);
1694: return;
1695: }
1696: break;
1697: case TerminalTokens.TokenNameDOT:
1698: this .print(this .scanner.getRawTokenSource(), false);
1699: currentTokenStartPosition = this .scanner.currentPosition;
1700: break;
1701: default:
1702: this .scanner.resetTo(currentTokenStartPosition,
1703: this .scannerEndPosition - 1);
1704: return;
1705: }
1706: } while (this .scanner.currentPosition <= sourceEnd);
1707: } catch (InvalidInputException e) {
1708: throw new AbortFormatting(e);
1709: }
1710: }
1711:
1712: public void printQualifiedReference(int sourceEnd) {
1713: int currentTokenStartPosition = this .scanner.currentPosition;
1714: try {
1715: do {
1716: this .printComment();
1717: switch (this .currentToken = this .scanner.getNextToken()) {
1718: case TerminalTokens.TokenNameEOF:
1719: return;
1720: case TerminalTokens.TokenNameWHITESPACE:
1721: addDeleteEdit(this .scanner
1722: .getCurrentTokenStartPosition(),
1723: this .scanner.getCurrentTokenEndPosition());
1724: currentTokenStartPosition = this .scanner.currentPosition;
1725: break;
1726: case TerminalTokens.TokenNameCOMMENT_BLOCK:
1727: case TerminalTokens.TokenNameCOMMENT_JAVADOC:
1728: this .printBlockComment(this .scanner
1729: .getRawTokenSource(), false);
1730: currentTokenStartPosition = this .scanner.currentPosition;
1731: break;
1732: case TerminalTokens.TokenNameCOMMENT_LINE:
1733: this .printLineComment(this .scanner
1734: .getRawTokenSource());
1735: currentTokenStartPosition = this .scanner.currentPosition;
1736: break;
1737: case TerminalTokens.TokenNameIdentifier:
1738: case TerminalTokens.TokenNameDOT:
1739: this .print(this .scanner.getRawTokenSource(), false);
1740: currentTokenStartPosition = this .scanner.currentPosition;
1741: break;
1742: default:
1743: this .scanner.resetTo(currentTokenStartPosition,
1744: this .scannerEndPosition - 1);
1745: return;
1746: }
1747: } while (this .scanner.currentPosition <= sourceEnd);
1748: } catch (InvalidInputException e) {
1749: throw new AbortFormatting(e);
1750: }
1751: }
1752:
1753: private void printRule(StringBuffer stringBuffer) {
1754: for (int i = 0; i < this .pageWidth; i++) {
1755: if ((i % this .tabLength) == 0) {
1756: stringBuffer.append('+');
1757: } else {
1758: stringBuffer.append('-');
1759: }
1760: }
1761: stringBuffer.append(this .lineSeparator);
1762:
1763: for (int i = 0; i < (pageWidth / tabLength); i++) {
1764: stringBuffer.append(i);
1765: stringBuffer.append('\t');
1766: }
1767: }
1768:
1769: public void printTrailingComment(int numberOfNewLinesToInsert) {
1770: try {
1771: // if we have a space between two tokens we ensure it will be dumped in the formatted string
1772: int currentTokenStartPosition = this .scanner.currentPosition;
1773: boolean hasWhitespaces = false;
1774: boolean hasLineComment = false;
1775: while ((this .currentToken = this .scanner.getNextToken()) != TerminalTokens.TokenNameEOF) {
1776: switch (this .currentToken) {
1777: case TerminalTokens.TokenNameWHITESPACE:
1778: int count = 0;
1779: char[] whiteSpaces = this .scanner
1780: .getCurrentTokenSource();
1781: for (int i = 0, max = whiteSpaces.length; i < max; i++) {
1782: switch (whiteSpaces[i]) {
1783: case '\r':
1784: if ((i + 1) < max) {
1785: if (whiteSpaces[i + 1] == '\n') {
1786: i++;
1787: }
1788: }
1789: count++;
1790: break;
1791: case '\n':
1792: count++;
1793: }
1794: }
1795: if (hasLineComment) {
1796: if (count >= 1) {
1797: currentTokenStartPosition = this .scanner
1798: .getCurrentTokenStartPosition();
1799: this .preserveEmptyLines(
1800: numberOfNewLinesToInsert,
1801: currentTokenStartPosition);
1802: addDeleteEdit(
1803: currentTokenStartPosition,
1804: this .scanner
1805: .getCurrentTokenEndPosition());
1806: this .scanner.resetTo(
1807: this .scanner.currentPosition,
1808: this .scannerEndPosition - 1);
1809: return;
1810: } else {
1811: this .scanner.resetTo(
1812: currentTokenStartPosition,
1813: this .scannerEndPosition - 1);
1814: return;
1815: }
1816: } else if (count > 1) {
1817: this
1818: .printEmptyLines(
1819: numberOfNewLinesToInsert,
1820: this .scanner
1821: .getCurrentTokenStartPosition());
1822: this .scanner.resetTo(currentTokenStartPosition,
1823: this .scannerEndPosition - 1);
1824: return;
1825: } else {
1826: hasWhitespaces = true;
1827: currentTokenStartPosition = this .scanner.currentPosition;
1828: addDeleteEdit(this .scanner
1829: .getCurrentTokenStartPosition(),
1830: this .scanner
1831: .getCurrentTokenEndPosition());
1832: }
1833: break;
1834: case TerminalTokens.TokenNameCOMMENT_LINE:
1835: if (hasWhitespaces) {
1836: space();
1837: }
1838: this .printLineComment(this .scanner
1839: .getRawTokenSource());
1840: currentTokenStartPosition = this .scanner.currentPosition;
1841: hasLineComment = true;
1842: break;
1843: case TerminalTokens.TokenNameCOMMENT_BLOCK:
1844: if (hasWhitespaces) {
1845: space();
1846: }
1847: this .printBlockComment(this .scanner
1848: .getRawTokenSource(), false);
1849: currentTokenStartPosition = this .scanner.currentPosition;
1850: break;
1851: default:
1852: // step back one token
1853: this .scanner.resetTo(currentTokenStartPosition,
1854: this .scannerEndPosition - 1);
1855: return;
1856: }
1857: }
1858: } catch (InvalidInputException e) {
1859: throw new AbortFormatting(e);
1860: }
1861: }
1862:
1863: public void printTrailingComment() {
1864: try {
1865: // if we have a space between two tokens we ensure it will be dumped in the formatted string
1866: int currentTokenStartPosition = this .scanner.currentPosition;
1867: boolean hasWhitespaces = false;
1868: boolean hasComment = false;
1869: boolean hasLineComment = false;
1870: while ((this .currentToken = this .scanner.getNextToken()) != TerminalTokens.TokenNameEOF) {
1871: switch (this .currentToken) {
1872: case TerminalTokens.TokenNameWHITESPACE:
1873: int count = 0;
1874: char[] whiteSpaces = this .scanner
1875: .getCurrentTokenSource();
1876: for (int i = 0, max = whiteSpaces.length; i < max; i++) {
1877: switch (whiteSpaces[i]) {
1878: case '\r':
1879: if ((i + 1) < max) {
1880: if (whiteSpaces[i + 1] == '\n') {
1881: i++;
1882: }
1883: }
1884: count++;
1885: break;
1886: case '\n':
1887: count++;
1888: }
1889: }
1890: if (hasLineComment) {
1891: if (count >= 1) {
1892: currentTokenStartPosition = this .scanner
1893: .getCurrentTokenStartPosition();
1894: this .preserveEmptyLines(count,
1895: currentTokenStartPosition);
1896: addDeleteEdit(
1897: currentTokenStartPosition,
1898: this .scanner
1899: .getCurrentTokenEndPosition());
1900: this .scanner.resetTo(
1901: this .scanner.currentPosition,
1902: this .scannerEndPosition - 1);
1903: return;
1904: } else {
1905: this .scanner.resetTo(
1906: currentTokenStartPosition,
1907: this .scannerEndPosition - 1);
1908: return;
1909: }
1910: } else if (count >= 1) {
1911: if (hasComment) {
1912: this .printNewLine(this .scanner
1913: .getCurrentTokenStartPosition());
1914: }
1915: this .scanner.resetTo(currentTokenStartPosition,
1916: this .scannerEndPosition - 1);
1917: return;
1918: } else {
1919: hasWhitespaces = true;
1920: currentTokenStartPosition = this .scanner.currentPosition;
1921: addDeleteEdit(this .scanner
1922: .getCurrentTokenStartPosition(),
1923: this .scanner
1924: .getCurrentTokenEndPosition());
1925: }
1926: break;
1927: case TerminalTokens.TokenNameCOMMENT_LINE:
1928: if (hasWhitespaces) {
1929: space();
1930: }
1931: this .printLineComment(this .scanner
1932: .getRawTokenSource());
1933: currentTokenStartPosition = this .scanner.currentPosition;
1934: hasLineComment = true;
1935: break;
1936: case TerminalTokens.TokenNameCOMMENT_BLOCK:
1937: if (hasWhitespaces) {
1938: space();
1939: }
1940: this .printBlockComment(this .scanner
1941: .getRawTokenSource(), false);
1942: currentTokenStartPosition = this .scanner.currentPosition;
1943: hasComment = true;
1944: break;
1945: default:
1946: // step back one token
1947: this .scanner.resetTo(currentTokenStartPosition,
1948: this .scannerEndPosition - 1);
1949: return;
1950: }
1951: }
1952: } catch (InvalidInputException e) {
1953: throw new AbortFormatting(e);
1954: }
1955: }
1956:
1957: void redoAlignment(AlignmentException e) {
1958: if (e.relativeDepth > 0) { // if exception targets a distinct context
1959: e.relativeDepth--; // record fact that current context got traversed
1960: this .currentAlignment = this .currentAlignment.enclosing; // pop currentLocation
1961: throw e; // rethrow
1962: }
1963: // reset scribe/scanner to restart at this given location
1964: this .resetAt(this .currentAlignment.location);
1965: this .scanner.resetTo(
1966: this .currentAlignment.location.inputOffset,
1967: this .scanner.eofPosition);
1968: // clean alignment chunkKind so it will think it is a new chunk again
1969: this .currentAlignment.chunkKind = 0;
1970: }
1971:
1972: void redoMemberAlignment(AlignmentException e) {
1973: // reset scribe/scanner to restart at this given location
1974: this .resetAt(this .memberAlignment.location);
1975: this .scanner.resetTo(this .memberAlignment.location.inputOffset,
1976: this .scanner.eofPosition);
1977: // clean alignment chunkKind so it will think it is a new chunk again
1978: this .memberAlignment.chunkKind = 0;
1979: }
1980:
1981: public void reset() {
1982: this .checkLineWrapping = true;
1983: this .line = 0;
1984: this .column = 1;
1985: this .editsIndex = 0;
1986: this .nlsTagCounter = 0;
1987: }
1988:
1989: private void resetAt(Location location) {
1990: this .line = location.outputLine;
1991: this .column = location.outputColumn;
1992: this .indentationLevel = location.outputIndentationLevel;
1993: this .numberOfIndentations = location.numberOfIndentations;
1994: this .lastNumberOfNewLines = location.lastNumberOfNewLines;
1995: this .needSpace = location.needSpace;
1996: this .pendingSpace = location.pendingSpace;
1997: this .editsIndex = location.editsIndex;
1998: this .nlsTagCounter = location.nlsTagCounter;
1999: if (this .editsIndex > 0) {
2000: this .edits[this .editsIndex - 1] = location.textEdit;
2001: }
2002: this .formatter.lastLocalDeclarationSourceStart = location.lastLocalDeclarationSourceStart;
2003: }
2004:
2005: private void resize() {
2006: System
2007: .arraycopy(
2008: this .edits,
2009: 0,
2010: (this .edits = new OptimizedReplaceEdit[this .editsIndex * 2]),
2011: 0, this .editsIndex);
2012: }
2013:
2014: public void space() {
2015: if (!this .needSpace)
2016: return;
2017: this .lastNumberOfNewLines = 0;
2018: this .pendingSpace = true;
2019: this .column++;
2020: this .needSpace = false;
2021: }
2022:
2023: public String toString() {
2024: StringBuffer stringBuffer = new StringBuffer();
2025: stringBuffer
2026: .append("(page width = " + this .pageWidth + ") - (tabChar = ");//$NON-NLS-1$//$NON-NLS-2$
2027: switch (this .tabChar) {
2028: case DefaultCodeFormatterOptions.TAB:
2029: stringBuffer.append("TAB");//$NON-NLS-1$
2030: break;
2031: case DefaultCodeFormatterOptions.SPACE:
2032: stringBuffer.append("SPACE");//$NON-NLS-1$
2033: break;
2034: default:
2035: stringBuffer.append("MIXED");//$NON-NLS-1$
2036: }
2037: stringBuffer
2038: .append(") - (tabSize = " + this .tabLength + ")")//$NON-NLS-1$//$NON-NLS-2$
2039: .append(this .lineSeparator)
2040: .append(
2041: "(line = " + this .line + ") - (column = " + this .column + ") - (identationLevel = " + this .indentationLevel + ")") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
2042: .append(this .lineSeparator)
2043: .append(
2044: "(needSpace = " + this .needSpace + ") - (lastNumberOfNewLines = " + this .lastNumberOfNewLines + ") - (checkLineWrapping = " + this .checkLineWrapping + ")") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
2045: .append(this .lineSeparator)
2046: .append(
2047: "==================================================================================") //$NON-NLS-1$
2048: .append(this .lineSeparator);
2049: printRule(stringBuffer);
2050: return stringBuffer.toString();
2051: }
2052:
2053: public void unIndent() {
2054: this.indentationLevel -= this.indentationSize;
2055: this.numberOfIndentations--;
2056: }
2057: }
|