/******************************************************************************* * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v0.5 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v05.html * * Contributors: * IBM Corporation - initial API and implementation ******************************************************************************/ package net.sourceforge.phpdt.internal.formatter; import java.io.BufferedReader; import java.io.IOException; import java.io.StringReader; import java.util.Hashtable; import java.util.Locale; import java.util.Map; import net.sourceforge.phpdt.core.ICodeFormatter; import net.sourceforge.phpdt.core.compiler.CharOperation; import net.sourceforge.phpdt.core.compiler.ITerminalSymbols; import net.sourceforge.phpdt.core.compiler.InvalidInputException; import net.sourceforge.phpdt.internal.compiler.ConfigurableOption; import net.sourceforge.phpdt.internal.compiler.parser.Scanner; import net.sourceforge.phpdt.internal.corext.codemanipulation.StubUtility; import net.sourceforge.phpdt.internal.corext.util.Strings; import net.sourceforge.phpdt.internal.formatter.impl.FormatterOptions; import net.sourceforge.phpdt.internal.formatter.impl.SplitLine; import net.sourceforge.phpdt.internal.ui.preferences.CodeFormatterPreferencePage; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.formatter.IContentFormatterExtension; import org.eclipse.jface.text.formatter.IFormattingContext; /** *

How to format a piece of code ?

* */ public class CodeFormatter implements ITerminalSymbols, ICodeFormatter { // IContentFormatterExtension { public FormatterOptions options; /** * Represents a block in the constructions stack. */ public static final int BLOCK = ITerminalSymbols.TokenNameLBRACE; /** * Represents a block following a control statement in the constructions stack. */ public static final int NONINDENT_BLOCK = -100; /** * Contains the formatted output. */ StringBuffer formattedSource; /** * Contains the current line.
* Will be dumped at the next "newline" */ StringBuffer currentLineBuffer; /** * Used during the formatting to get each token. */ Scanner scanner; /** * Contains the tokens responsible for the current indentation level and the blocks not closed yet. */ private int[] constructions; /** * Index in the constructions array. */ private int constructionsCount; /** * Level of indentation of the current token (number of tab char put in front of it). */ private int indentationLevel; /** * Regular level of indentation of all the lines */ private int initialIndentationLevel; /** * Used to split a line. */ Scanner splitScanner; /** * To remember the offset between the beginning of the line and the beginning of the comment. */ int currentCommentOffset; int currentLineIndentationLevel; int maxLineSize = 30; private boolean containsOpenCloseBraces; private int indentationLevelForOpenCloseBraces; /** * Collections of positions to map */ private int[] positionsToMap; /** * Collections of mapped positions */ private int[] mappedPositions; private int indexToMap; private int indexInMap; private int globalDelta; private int lineDelta; private int splitDelta; private int beginningOfLineIndex; private int multipleLineCommentCounter; /** * Creates a new instance of Code Formatter using the given settings. * * @deprecated backport 1.0 internal functionality */ public CodeFormatter(ConfigurableOption[] settings) { this(convertConfigurableOptions(settings)); } /** * Creates a new instance of Code Formatter using the FormattingOptions object given as argument * * @deprecated Use CodeFormatter(ConfigurableOption[]) instead */ public CodeFormatter() { this((Map) null); } /** * Creates a new instance of Code Formatter using the given settings. */ public CodeFormatter(Map settings) { // initialize internal state constructionsCount = 0; constructions = new int[10]; currentLineIndentationLevel = indentationLevel = initialIndentationLevel; currentCommentOffset = -1; // initialize primary and secondary scanners scanner = new Scanner(true /* comment */ , true /* whitespace */ , false /* nls */ , false /* assert */ , true, /* tokenizeStrings */ null, null); // regular scanner for forming lines scanner.recordLineSeparator = true; // to remind of the position of the beginning of the line. splitScanner = new Scanner(true /* comment */ , true /* whitespace */ , false /* nls */ , false /* assert */ , true, /* tokenizeStrings */ null, null); // secondary scanner to split long lines formed by primary scanning // initialize current line buffer currentLineBuffer = new StringBuffer(); this.options = new FormatterOptions(settings); } /** * Returns true if a lineSeparator has to be inserted before operator false otherwise. */ private static boolean breakLineBeforeOperator(int operator) { switch (operator) { case TokenNameCOMMA: case TokenNameSEMICOLON: case TokenNameEQUAL: return false; default: return true; } } /** * @deprecated backport 1.0 internal functionality */ private static Map convertConfigurableOptions(ConfigurableOption[] settings) { Hashtable options = new Hashtable(10); for (int i = 0; i < settings.length; i++) { if (settings[i].getComponentName().equals(CodeFormatter.class.getName())) { String optionName = settings[i].getOptionName(); int valueIndex = settings[i].getCurrentValueIndex(); if (optionName.equals("newline.openingBrace")) { //$NON-NLS-1$ options.put("net.sourceforge.phpdt.core.formatter.newline.openingBrace", valueIndex == 0 ? "insert" : "do not insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } else if (optionName.equals("newline.controlStatement")) { //$NON-NLS-1$ options .put("net.sourceforge.phpdt.core.formatter.newline.controlStatement", valueIndex == 0 ? "insert" : "do not insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } else if (optionName.equals("newline.clearAll")) { //$NON-NLS-1$ options.put("net.sourceforge.phpdt.core.formatter.newline.clearAll", valueIndex == 0 ? "clear all" : "preserve one"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } else if (optionName.equals("newline.elseIf")) { //$NON-NLS-1$ options.put("net.sourceforge.phpdt.core.formatter.newline.elseIf", valueIndex == 0 ? "do not insert" : "insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } else if (optionName.equals("newline.emptyBlock")) { //$NON-NLS-1$ options.put("net.sourceforge.phpdt.core.formatter.newline.emptyBlock", valueIndex == 0 ? "insert" : "do not insert"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } else if (optionName.equals("lineSplit")) { //$NON-NLS-1$ options.put("net.sourceforge.phpdt.core.formatter.lineSplit", String.valueOf(valueIndex)); //$NON-NLS-1$ //$NON-NLS-2$ } else if (optionName.equals("style.assignment")) { //$NON-NLS-1$ options.put("net.sourceforge.phpdt.core.formatter.style.assignment", valueIndex == 0 ? "compact" : "normal"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } else if (optionName.equals("tabulation.char")) { //$NON-NLS-1$ options.put("net.sourceforge.phpdt.core.formatter.tabulation.char", valueIndex == 0 ? "tab" : "space"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } else if (optionName.equals("tabulation.size")) { //$NON-NLS-1$ options.put("net.sourceforge.phpdt.core.formatter.tabulation.size", String.valueOf(valueIndex)); //$NON-NLS-1$ //$NON-NLS-2$ } } } return options; } /** * Returns the end of the source code. */ private final String copyRemainingSource() { char str[] = scanner.source; int startPosition = scanner.startPosition; int length = str.length - startPosition; StringBuffer bufr = new StringBuffer(length); if (startPosition < str.length) { bufr.append(str, startPosition, length); } return (bufr.toString()); } /** * Inserts tabCount tab character or their equivalent number of spaces. */ private void dumpTab(int tabCount) { if (options.indentWithTab) { for (int j = 0; j < tabCount; j++) { formattedSource.append('\t'); increaseSplitDelta(1); } } else { for (int i = 0, max = options.tabSize * tabCount; i < max; i++) { formattedSource.append(' '); increaseSplitDelta(1); } } } /** * Dumps currentLineBuffer into the formatted string. */ private void flushBuffer() { String currentString = currentLineBuffer.toString(); splitDelta = 0; beginningOfLineIndex = formattedSource.length(); if (containsOpenCloseBraces) { containsOpenCloseBraces = false; outputLine(currentString, false, indentationLevelForOpenCloseBraces, 0, -1, null, 0); indentationLevelForOpenCloseBraces = currentLineIndentationLevel; } else { outputLine(currentString, false, currentLineIndentationLevel, 0, -1, null, 0); } int scannerSourceLength = scanner.source.length; if (scannerSourceLength > 2) { if (scanner.source[scannerSourceLength - 1] == '\n' && scanner.source[scannerSourceLength - 2] == '\r') { formattedSource.append(options.lineSeparatorSequence); increaseGlobalDelta(options.lineSeparatorSequence.length - 2); } else if (scanner.source[scannerSourceLength - 1] == '\n') { formattedSource.append(options.lineSeparatorSequence); increaseGlobalDelta(options.lineSeparatorSequence.length - 1); } else if (scanner.source[scannerSourceLength - 1] == '\r') { formattedSource.append(options.lineSeparatorSequence); increaseGlobalDelta(options.lineSeparatorSequence.length - 1); } } updateMappedPositions(scanner.startPosition); } /** * Formats the input string. */ private void format() { int token = 0; int previousToken = 0; int previousCompilableToken = 0; int indentationOffset = 0; int newLinesInWhitespace = 0; // number of new lines in the previous whitespace token // (used to leave blank lines before comments) int pendingNewLines = 0; boolean expectingOpenBrace = false; boolean clearNonBlockIndents = false; // true if all indentations till the 1st { (usefull after } or ;) boolean pendingSpace = true; boolean pendingNewlineAfterParen = false; // true when a cr is to be put after a ) (in conditional statements) boolean inAssignment = false; boolean inArrayAssignment = false; boolean inThrowsClause = false; boolean inClassOrInterfaceHeader = false; int dollarBraceCount = 0; // openBracketCount is used to count the number of open brackets not closed // yet. int openBracketCount = 0; int unarySignModifier = 0; // openParenthesis[0] is used to count the parenthesis not belonging to a // condition // (eg foo();). parenthesis in for (...) are count elsewhere in the array. int openParenthesisCount = 1; int[] openParenthesis = new int[10]; // tokenBeforeColon is used to know what token goes along with the current // : // it can be case or ? int tokenBeforeColonCount = 0; int[] tokenBeforeColon = new int[10]; constructionsCount = 0; // initializes the constructions count. // contains DO if in a DO..WHILE statement, UNITIALIZED otherwise. int nlicsToken = 0; // fix for 1FF17XY: LFCOM:ALL - Format problem on not matching } and else boolean specialElse = false; // OPTION (IndentationLevel): initial indentation level may be non-zero. currentLineIndentationLevel += constructionsCount; // An InvalidInputException exception might cause the termination of this // loop. try { while (true) { // Get the next token. Catch invalid input and output it // with minimal formatting, also catch end of input and // exit the loop. try { token = scanner.getNextToken(); if (Scanner.DEBUG) { int currentEndPosition = scanner.getCurrentTokenEndPosition(); int currentStartPosition = scanner.getCurrentTokenStartPosition(); System.out.print(currentStartPosition + "," + currentEndPosition + ": "); System.out.println(scanner.toStringAction(token)); } // Patch for line comment // See PR http://dev.eclipse.org/bugs/show_bug.cgi?id=23096 if (token == ITerminalSymbols.TokenNameCOMMENT_LINE) { int length = scanner.currentPosition; loop: for (int index = length - 1; index >= 0; index--) { switch (scanner.source[index]) { case '\r': case '\n': scanner.currentPosition--; break; default: break loop; } } } } catch (InvalidInputException e) { if (!handleInvalidToken(e)) { throw e; } token = 0; } if (token == Scanner.TokenNameEOF) break; /* * ## MODIFYING the indentation level before generating new lines and indentation in the output string */ // Removes all the indentations made by statements not followed by a // block // except if the current token is ELSE, CATCH or if we are in a // switch/case if (clearNonBlockIndents && (token != Scanner.TokenNameWHITESPACE)) { switch (token) { case TokenNameelse: if (constructionsCount > 0 && constructions[constructionsCount - 1] == TokenNameelse) { pendingNewLines = 1; specialElse = true; } indentationLevel += popInclusiveUntil(TokenNameif); break; // case TokenNamecatch : // indentationLevel += popInclusiveUntil(TokenNamecatch); // break; // case TokenNamefinally : // indentationLevel += popInclusiveUntil(TokenNamecatch); // break; case TokenNamewhile: if (nlicsToken == TokenNamedo) { indentationLevel += pop(TokenNamedo); break; } default: indentationLevel += popExclusiveUntilBlockOrCase(); // clear until a CASE, DEFAULT or BLOCK is encountered. // Thus, the indentationLevel is correctly cleared either // in a switch/case statement or in any other situation. } clearNonBlockIndents = false; } // returns to the indentation level created by the SWITCH keyword // if the current token is a CASE or a DEFAULT if (token == TokenNamecase || token == TokenNamedefault) { indentationLevel += pop(TokenNamecase); } // if (token == Scanner.TokenNamethrows) { // inThrowsClause = true; // } if ((token == Scanner.TokenNameclass || token == Scanner.TokenNameinterface) && previousToken != Scanner.TokenNameDOT) { inClassOrInterfaceHeader = true; } /* * ## APPEND newlines and indentations to the output string */ // Do not add a new line between ELSE and IF, if the option // elseIfOnSameLine is true. // Fix for 1ETLWPZ: IVJCOM:ALL - incorrect "else if" formatting // if (pendingNewlineAfterParen // && previousCompilableToken == TokenNameelse // && token == TokenNameif // && options.compactElseIfMode) { // pendingNewlineAfterParen = false; // pendingNewLines = 0; // indentationLevel += pop(TokenNameelse); // // because else if is now one single statement, // // the indentation level after it is increased by one and not by 2 // // (else = 1 indent, if = 1 indent, but else if = 1 indent, not 2). // } // Add a newline & indent to the formatted source string if // a for/if-else/while statement was scanned and there is no block // following it. pendingNewlineAfterParen = pendingNewlineAfterParen || (previousCompilableToken == TokenNameRPAREN && token == TokenNameLBRACE); if (pendingNewlineAfterParen && token != Scanner.TokenNameWHITESPACE) { pendingNewlineAfterParen = false; // Do to add a newline & indent sequence if the current token is an // open brace or a period or if the current token is a semi-colon and // the // previous token is a close paren. // add a new line if a parenthesis belonging to a for() statement // has been closed and the current token is not an opening brace if (token != TokenNameLBRACE && !isComment(token) // to avoid adding new line between else and a comment && token != TokenNameDOT && !(previousCompilableToken == TokenNameRPAREN && token == TokenNameSEMICOLON)) { newLine(1); currentLineIndentationLevel = indentationLevel; pendingNewLines = 0; pendingSpace = false; } else { if (token == TokenNameLBRACE && options.newLineBeforeOpeningBraceMode) { newLine(1); if (constructionsCount > 0 && constructions[constructionsCount - 1] != BLOCK && constructions[constructionsCount - 1] != NONINDENT_BLOCK) { currentLineIndentationLevel = indentationLevel - 1; } else { currentLineIndentationLevel = indentationLevel; } pendingNewLines = 0; pendingSpace = false; } } } if (token == TokenNameLBRACE && options.newLineBeforeOpeningBraceMode && constructionsCount > 0 && constructions[constructionsCount - 1] == TokenNamedo) { newLine(1); currentLineIndentationLevel = indentationLevel - 1; pendingNewLines = 0; pendingSpace = false; } // see PR 1G5G8EC if (token == TokenNameLBRACE && inThrowsClause) { inThrowsClause = false; if (options.newLineBeforeOpeningBraceMode) { newLine(1); currentLineIndentationLevel = indentationLevel; pendingNewLines = 0; pendingSpace = false; } } // see PR 1G5G82G if (token == TokenNameLBRACE && inClassOrInterfaceHeader) { inClassOrInterfaceHeader = false; if (options.newLineBeforeOpeningBraceMode) { newLine(1); currentLineIndentationLevel = indentationLevel; pendingNewLines = 0; pendingSpace = false; } } // Add pending new lines to the formatted source string. // Note: pending new lines are not added if the current token // is a single line comment or whitespace. // if the comment is between parenthesis, there is no blank line // preservation // (if it's a one-line comment, a blank line is added after it). if (((pendingNewLines > 0 && (!isComment(token))) || (newLinesInWhitespace > 0 && (openParenthesisCount <= 1 && isComment(token))) || (previousCompilableToken == TokenNameLBRACE && token == TokenNameRBRACE)) && token != Scanner.TokenNameWHITESPACE) { // Do not add newline & indent between an adjoining close brace and // close paren. Anonymous inner classes may use this form. boolean closeBraceAndCloseParen = previousToken == TokenNameRBRACE && token == TokenNameRPAREN; // OPTION (NewLineInCompoundStatement): do not add newline & indent // between close brace and else, (do) while, catch, and finally if // newlineInCompoundStatement is true. boolean nlicsOption = previousToken == TokenNameRBRACE && !options.newlineInControlStatementMode && (token == TokenNameelse || (token == TokenNamewhile && nlicsToken == TokenNamedo) || token == TokenNamecatch || token == TokenNamefinally); // Do not add a newline & indent between a close brace and // semi-colon. boolean semiColonAndCloseBrace = previousToken == TokenNameRBRACE && token == TokenNameSEMICOLON; // Do not add a new line & indent between a multiline comment and a // opening brace boolean commentAndOpenBrace = previousToken == Scanner.TokenNameCOMMENT_BLOCK && token == TokenNameLBRACE; // Do not add a newline & indent between a close brace and a colon // (in array assignments, for example). boolean commaAndCloseBrace = previousToken == TokenNameRBRACE && token == TokenNameCOMMA; // Add a newline and indent, if appropriate. if (specialElse || (!commentAndOpenBrace && !closeBraceAndCloseParen && !nlicsOption && !semiColonAndCloseBrace && !commaAndCloseBrace)) { // if clearAllBlankLinesMode=false, leaves the blank lines // inserted by the user // if clearAllBlankLinesMode=true, removes all of then // and insert only blank lines required by the formatting. if (!options.clearAllBlankLinesMode) { // (isComment(token)) pendingNewLines = (pendingNewLines < newLinesInWhitespace) ? newLinesInWhitespace : pendingNewLines; pendingNewLines = (pendingNewLines > 2) ? 2 : pendingNewLines; } if (previousCompilableToken == TokenNameLBRACE && token == TokenNameRBRACE) { containsOpenCloseBraces = true; indentationLevelForOpenCloseBraces = currentLineIndentationLevel; if (isComment(previousToken)) { newLine(pendingNewLines); } else { /* * if (!(constructionsCount > 1 && constructions[constructionsCount-1] == NONINDENT_BLOCK && * (constructions[constructionsCount-2] == TokenNamefor */ if (options.newLineInEmptyBlockMode) { if (inArrayAssignment) { newLine(1); // array assigment with an empty block } else { newLine(pendingNewLines); } } // } } } else { // see PR 1FKKC3U: LFCOM:WINNT - Format problem with a comment // before the ';' if (!((previousToken == Scanner.TokenNameCOMMENT_BLOCK || previousToken == Scanner.TokenNameCOMMENT_PHPDOC) && token == TokenNameSEMICOLON)) { newLine(pendingNewLines); } } if (((previousCompilableToken == TokenNameSEMICOLON) || (previousCompilableToken == TokenNameLBRACE) || (previousCompilableToken == TokenNameRBRACE) || (isComment(previousToken))) && (token == TokenNameRBRACE)) { indentationOffset = -1; indentationLevel += popExclusiveUntilBlock(); } if (previousToken == Scanner.TokenNameCOMMENT_LINE && inAssignment) { // PR 1FI5IPO currentLineIndentationLevel++; } else { currentLineIndentationLevel = indentationLevel + indentationOffset; } pendingSpace = false; indentationOffset = 0; } pendingNewLines = 0; newLinesInWhitespace = 0; specialElse = false; if (nlicsToken == TokenNamedo && token == TokenNamewhile) { nlicsToken = 0; } } boolean phpTagAndWhitespace = previousToken == TokenNameINLINE_HTML && token == TokenNameWHITESPACE; switch (token) { // case TokenNameDOLLAR : // dollarBraceCount++; // break; case TokenNameelse: // case TokenNamefinally : expectingOpenBrace = true; pendingNewlineAfterParen = true; indentationLevel += pushControlStatement(token); break; case TokenNamecase: case TokenNamedefault: if (tokenBeforeColonCount == tokenBeforeColon.length) { System .arraycopy(tokenBeforeColon, 0, (tokenBeforeColon = new int[tokenBeforeColonCount * 2]), 0, tokenBeforeColonCount); } tokenBeforeColon[tokenBeforeColonCount++] = TokenNamecase; indentationLevel += pushControlStatement(TokenNamecase); break; case TokenNameQUESTION: if (tokenBeforeColonCount == tokenBeforeColon.length) { System .arraycopy(tokenBeforeColon, 0, (tokenBeforeColon = new int[tokenBeforeColonCount * 2]), 0, tokenBeforeColonCount); } tokenBeforeColon[tokenBeforeColonCount++] = token; break; case TokenNameswitch: case TokenNamefor: case TokenNameforeach: case TokenNameif: case TokenNamewhile: if (openParenthesisCount == openParenthesis.length) { System.arraycopy(openParenthesis, 0, (openParenthesis = new int[openParenthesisCount * 2]), 0, openParenthesisCount); } openParenthesis[openParenthesisCount++] = 0; expectingOpenBrace = true; indentationLevel += pushControlStatement(token); break; case TokenNametry: pendingNewlineAfterParen = true; case TokenNamecatch: // several CATCH statements can be contiguous. // a CATCH is encountered pop until first CATCH (if a CATCH // follows a TRY it works the same way, // as CATCH and TRY are the same token in the stack). expectingOpenBrace = true; indentationLevel += pushControlStatement(TokenNamecatch); break; case TokenNamedo: expectingOpenBrace = true; indentationLevel += pushControlStatement(token); nlicsToken = token; break; case TokenNamenew: break; case TokenNameLPAREN: // if (previousToken == TokenNamesynchronized) { // indentationLevel += pushControlStatement(previousToken); // } else { // Put a space between the previous and current token if the // previous token was not a keyword, open paren, logical // compliment (eg: !), semi-colon, open brace, close brace, // super, or this. if (previousCompilableToken != TokenNameLBRACKET && previousToken != TokenNameIdentifier && previousToken != 0 && previousToken != TokenNameNOT && previousToken != TokenNameLPAREN && previousToken != TokenNameTWIDDLE && previousToken != TokenNameSEMICOLON && previousToken != TokenNameLBRACE && previousToken != TokenNameRBRACE && previousToken != TokenNamesuper) { // && previousToken != TokenNamethis) { space(); } // If in a for/if/while statement, increase the parenthesis count // for the current openParenthesisCount // else increase the count for stand alone parenthesis. if (openParenthesisCount > 0) openParenthesis[openParenthesisCount - 1]++; else openParenthesis[0]++; pendingSpace = false; //S } break; case TokenNameRPAREN: // Decrease the parenthesis count // if there is no more unclosed parenthesis, // a new line and indent may be append (depending on the next // token). if ((openParenthesisCount > 1) && (openParenthesis[openParenthesisCount - 1] > 0)) { openParenthesis[openParenthesisCount - 1]--; if (openParenthesis[openParenthesisCount - 1] <= 0) { pendingNewlineAfterParen = true; inAssignment = false; openParenthesisCount--; } } else { openParenthesis[0]--; } pendingSpace = false; break; case TokenNameLBRACE: if (previousCompilableToken == TokenNameDOLLAR) { dollarBraceCount++; } else { if ((previousCompilableToken == TokenNameRBRACKET) || (previousCompilableToken == TokenNameEQUAL)) { // if (previousCompilableToken == TokenNameRBRACKET) { inArrayAssignment = true; inAssignment = false; } if (inArrayAssignment) { indentationLevel += pushBlock(); } else { // Add new line and increase indentation level after open brace. pendingNewLines = 1; indentationLevel += pushBlock(); } } break; case TokenNameRBRACE: if (dollarBraceCount > 0) { dollarBraceCount--; break; } if (previousCompilableToken == TokenNameRPAREN) { pendingSpace = false; } if (inArrayAssignment) { inArrayAssignment = false; pendingNewLines = 1; indentationLevel += popInclusiveUntilBlock(); } else { pendingNewLines = 1; indentationLevel += popInclusiveUntilBlock(); if (previousCompilableToken == TokenNameRPAREN) { // fix for 1FGDDV6: LFCOM:WIN98 - Weird splitting on message // expression currentLineBuffer.append(options.lineSeparatorSequence); increaseLineDelta(options.lineSeparatorSequence.length); } if (constructionsCount > 0) { switch (constructions[constructionsCount - 1]) { case TokenNamefor: case TokenNameforeach: //indentationLevel += popExclusiveUntilBlock(); //break; case TokenNameswitch: case TokenNameif: case TokenNameelse: case TokenNametry: case TokenNamecatch: case TokenNamefinally: case TokenNamewhile: case TokenNamedo: // case TokenNamesynchronized : clearNonBlockIndents = true; default: break; } } } break; case TokenNameLBRACKET: openBracketCount++; pendingSpace = false; break; case TokenNameRBRACKET: openBracketCount -= (openBracketCount > 0) ? 1 : 0; // if there is no left bracket to close, the right bracket is // ignored. pendingSpace = false; break; case TokenNameCOMMA: case TokenNameDOT: pendingSpace = false; break; case TokenNameSEMICOLON: // Do not generate line terminators in the definition of // the for statement. // if not in this case, jump a line and reduce indentation after // the brace // if the block it closes belongs to a conditional statement (if, // while, do...). if (openParenthesisCount <= 1) { pendingNewLines = 1; if (expectingOpenBrace) { clearNonBlockIndents = true; expectingOpenBrace = false; } } inAssignment = false; pendingSpace = false; break; case TokenNamePLUS_PLUS: case TokenNameMINUS_MINUS: // Do not put a space between a post-increment/decrement // and the identifier being modified. if (previousToken == TokenNameIdentifier || previousToken == TokenNameRBRACKET) { pendingSpace = false; } break; case TokenNamePLUS: // previously ADDITION case TokenNameMINUS: // Handle the unary operators plus and minus via a flag if (!isLiteralToken(previousToken) && previousToken != TokenNameIdentifier && previousToken != TokenNameRPAREN && previousToken != TokenNameRBRACKET) { unarySignModifier = 1; } break; case TokenNameCOLON: // In a switch/case statement, add a newline & indent // when a colon is encountered. if (tokenBeforeColonCount > 0) { if (tokenBeforeColon[tokenBeforeColonCount - 1] == TokenNamecase) { pendingNewLines = 1; } tokenBeforeColonCount--; } break; case TokenNameEQUAL: inAssignment = true; break; case Scanner.TokenNameCOMMENT_LINE: pendingNewLines = 1; if (inAssignment) { currentLineIndentationLevel++; } break; // a line is always inserted after a one-line comment case Scanner.TokenNameCOMMENT_PHPDOC: case Scanner.TokenNameCOMMENT_BLOCK: currentCommentOffset = getCurrentCommentOffset(); pendingNewLines = 1; break; case Scanner.TokenNameWHITESPACE: if (!phpTagAndWhitespace) { // Count the number of line terminators in the whitespace so // line spacing can be preserved near comments. char[] source = scanner.source; newLinesInWhitespace = 0; for (int i = scanner.startPosition, max = scanner.currentPosition; i < max; i++) { if (source[i] == '\r') { if (i < max - 1) { if (source[++i] == '\n') { newLinesInWhitespace++; } else { newLinesInWhitespace++; } } else { newLinesInWhitespace++; } } else if (source[i] == '\n') { newLinesInWhitespace++; } } increaseLineDelta(scanner.startPosition - scanner.currentPosition); break; } // case TokenNameHTML : // // Add the next token to the formatted source string. // // outputCurrentToken(token); // int startPosition = scanner.startPosition; // flushBuffer(); // for (int i = startPosition, max = scanner.currentPosition; i < // max; i++) { // char currentCharacter = scanner.source[i]; // updateMappedPositions(i); // currentLineBuffer.append(currentCharacter); // } // break; default: if ((token == TokenNameIdentifier) || isLiteralToken(token) || token == TokenNamesuper) { // || token == TokenNamethis) { // Do not put a space between a unary operator // (eg: ++, --, +, -) and the identifier being modified. if (previousToken == TokenNamePLUS_PLUS || previousToken == TokenNameMINUS_MINUS || (previousToken == TokenNameMINUS_GREATER && options.compactDereferencingMode) // -> || (previousToken == TokenNamePLUS && unarySignModifier > 0) || (previousToken == TokenNameMINUS && unarySignModifier > 0)) { pendingSpace = false; } unarySignModifier = 0; } break; } // Do not output whitespace tokens. if (token != Scanner.TokenNameWHITESPACE || phpTagAndWhitespace) { /* * Add pending space to the formatted source string. Do not output a space under the following circumstances: 1) this is * the first pass 2) previous token is an open paren 3) previous token is a period 4) previous token is the logical * compliment (eg: !) 5) previous token is the bitwise compliment (eg: ~) 6) previous token is the open bracket (eg: [) 7) * in an assignment statement, if the previous token is an open brace or the current token is a close brace 8) previous * token is a single line comment 9) current token is a '->' */ if (token == TokenNameMINUS_GREATER && options.compactDereferencingMode) pendingSpace = false; boolean openAndCloseBrace = previousCompilableToken == TokenNameLBRACE && token == TokenNameRBRACE; if (pendingSpace && insertSpaceAfter(previousToken) && !(inAssignment && (previousToken == TokenNameLBRACE || token == TokenNameRBRACE)) && previousToken != Scanner.TokenNameCOMMENT_LINE) { if ((!(options.compactAssignmentMode && token == TokenNameEQUAL)) && !openAndCloseBrace) space(); } // Add the next token to the formatted source string. outputCurrentToken(token); if (token == Scanner.TokenNameCOMMENT_LINE && openParenthesisCount > 1) { pendingNewLines = 0; currentLineBuffer.append(options.lineSeparatorSequence); increaseLineDelta(options.lineSeparatorSequence.length); } pendingSpace = true; } // Whitespace tokens do not need to be remembered. if (token != Scanner.TokenNameWHITESPACE || phpTagAndWhitespace) { previousToken = token; if (token != Scanner.TokenNameCOMMENT_BLOCK && token != Scanner.TokenNameCOMMENT_LINE && token != Scanner.TokenNameCOMMENT_PHPDOC) { previousCompilableToken = token; } } } output(copyRemainingSource()); flushBuffer(); // dump the last token of the source in the formatted output. } catch (InvalidInputException e) { output(copyRemainingSource()); flushBuffer(); // dump the last token of the source in the formatted output. } } /** * Formats the char array sourceString, and returns a string containing the formatted version. * * @return the formatted ouput. */ public String formatSourceString(String sourceString) { char[] sourceChars = sourceString.toCharArray(); formattedSource = new StringBuffer(sourceChars.length); scanner.setSource(sourceChars); format(); return formattedSource.toString(); } /** * Formats the char array sourceString, and returns a string containing the formatted version. * * @param string * the string to format * @param indentationLevel * the initial indentation level * @return the formatted ouput. */ public String format(String string, int indentationLevel) { return format(string, indentationLevel, (int[]) null); } /** * Formats the char array sourceString, and returns a string containing the formatted version. The positions array * is modified to contain the mapped positions. * * @param string * the string to format * @param indentationLevel * the initial indentation level * @param positions * the array of positions to map * @return the formatted ouput. */ public String format(String string, int indentationLevel, int[] positions) { return this.format(string, indentationLevel, positions, null); } public String format(String string, int indentationLevel, int[] positions, String lineSeparator) { if (lineSeparator != null) { this.options.setLineSeparator(lineSeparator); } if (positions != null) { this.setPositionsToMap(positions); this.setInitialIndentationLevel(indentationLevel); String formattedString = this.formatSourceString(string); int[] mappedPositions = this.getMappedPositions(); System.arraycopy(mappedPositions, 0, positions, 0, positions.length); return formattedString; } else { this.setInitialIndentationLevel(indentationLevel); return this.formatSourceString(string); } } /** * Formats the char array sourceString, and returns a string containing the formatted version. The initial * indentation level is 0. * * @param string * the string to format * @return the formatted ouput. */ public String format(String string) { return this.format(string, 0, (int[]) null); } /** * Formats a given source string, starting indenting it at a particular depth and using the given options * * @deprecated backport 1.0 internal functionality */ public static String format(String sourceString, int initialIndentationLevel, ConfigurableOption[] options) { CodeFormatter formatter = new CodeFormatter(options); formatter.setInitialIndentationLevel(initialIndentationLevel); return formatter.formatSourceString(sourceString); } /** * Returns the number of characters and tab char between the beginning of the line and the beginning of the comment. */ private int getCurrentCommentOffset() { int linePtr = scanner.linePtr; // if there is no beginning of line, return 0. if (linePtr < 0) return 0; int offset = 0; int beginningOfLine = scanner.lineEnds[linePtr]; int currentStartPosition = scanner.startPosition; char[] source = scanner.source; // find the position of the beginning of the line containing the comment while (beginningOfLine > currentStartPosition) { if (linePtr > 0) { beginningOfLine = scanner.lineEnds[--linePtr]; } else { beginningOfLine = 0; break; } } for (int i = currentStartPosition - 1; i >= beginningOfLine; i--) { char currentCharacter = source[i]; switch (currentCharacter) { case '\t': offset += options.tabSize; break; case ' ': offset++; break; case '\r': case '\n': break; default: return offset; } } return offset; } /** * Returns an array of descriptions for the configurable options. The descriptions may be changed and passed back to a different * compiler. * * @deprecated backport 1.0 internal functionality */ public static ConfigurableOption[] getDefaultOptions(Locale locale) { String componentName = CodeFormatter.class.getName(); FormatterOptions options = new FormatterOptions(); return new ConfigurableOption[] { new ConfigurableOption(componentName, "newline.openingBrace", locale, options.newLineBeforeOpeningBraceMode ? 0 : 1), //$NON-NLS-1$ new ConfigurableOption(componentName, "newline.controlStatement", locale, options.newlineInControlStatementMode ? 0 : 1), //$NON-NLS-1$ new ConfigurableOption(componentName, "newline.clearAll", locale, options.clearAllBlankLinesMode ? 0 : 1), //$NON-NLS-1$ // new ConfigurableOption(componentName, "newline.elseIf", locale, // options.compactElseIfMode ? 0 : 1), //$NON-NLS-1$ new ConfigurableOption(componentName, "newline.emptyBlock", locale, options.newLineInEmptyBlockMode ? 0 : 1), //$NON-NLS-1$ new ConfigurableOption(componentName, "line.split", locale, options.maxLineLength), //$NON-NLS-1$ new ConfigurableOption(componentName, "style.compactAssignment", locale, options.compactAssignmentMode ? 0 : 1), //$NON-NLS-1$ new ConfigurableOption(componentName, "tabulation.char", locale, options.indentWithTab ? 0 : 1), //$NON-NLS-1$ new ConfigurableOption(componentName, "tabulation.size", locale, options.tabSize) //$NON-NLS-1$ }; } /** * Returns the array of mapped positions. Returns null is no positions have been set. * * @return int[] * @deprecated There is no need to retrieve the mapped positions anymore. */ public int[] getMappedPositions() { return mappedPositions; } /** * Returns the priority of the token given as argument
* The most prioritary the token is, the smallest the return value is. * * @return the priority of token * @param token * the token of which the priority is requested */ private static int getTokenPriority(int token) { switch (token) { case TokenNameextends: // case TokenNameimplements : // case TokenNamethrows : return 10; case TokenNameSEMICOLON: // ; return 20; case TokenNameCOMMA: // , return 25; case TokenNameEQUAL: // = return 30; case TokenNameAND_AND: // && case TokenNameOR_OR: // || return 40; case TokenNameQUESTION: // ? case TokenNameCOLON: // : return 50; // it's better cutting on ?: than on ; case TokenNameEQUAL_EQUAL: // == case TokenNameEQUAL_EQUAL_EQUAL: // === case TokenNameNOT_EQUAL: // != case TokenNameNOT_EQUAL_EQUAL: // != return 60; case TokenNameLESS: // < case TokenNameLESS_EQUAL: // <= case TokenNameGREATER: // > case TokenNameGREATER_EQUAL: // >= // case TokenNameinstanceof : // instanceof return 70; case TokenNamePLUS: // + case TokenNameMINUS: // - return 80; case TokenNameMULTIPLY: // * case TokenNameDIVIDE: // / case TokenNameREMAINDER: // % return 90; case TokenNameLEFT_SHIFT: // << case TokenNameRIGHT_SHIFT: // >> // case TokenNameUNSIGNED_RIGHT_SHIFT : // >>> return 100; case TokenNameAND: // & case TokenNameOR: // | case TokenNameXOR: // ^ return 110; case TokenNameMULTIPLY_EQUAL: // *= case TokenNameDIVIDE_EQUAL: // /= case TokenNameREMAINDER_EQUAL: // %= case TokenNamePLUS_EQUAL: // += case TokenNameMINUS_EQUAL: // -= case TokenNameLEFT_SHIFT_EQUAL: // <<= case TokenNameRIGHT_SHIFT_EQUAL: // >>= // case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL : // >>>= case TokenNameAND_EQUAL: // &= case TokenNameXOR_EQUAL: // ^= case TokenNameOR_EQUAL: // .= case TokenNameDOT_EQUAL: // |= return 120; case TokenNameDOT: // . return 130; default: return Integer.MAX_VALUE; } } /** * Handles the exception raised when an invalid token is encountered. Returns true if the exception has been handled, false * otherwise. */ private boolean handleInvalidToken(Exception e) { if (e.getMessage().equals(Scanner.INVALID_CHARACTER_CONSTANT) || e.getMessage().equals(Scanner.INVALID_CHAR_IN_STRING) || e.getMessage().equals(Scanner.INVALID_ESCAPE)) { return true; } return false; } private final void increaseGlobalDelta(int offset) { globalDelta += offset; } private final void increaseLineDelta(int offset) { lineDelta += offset; } private final void increaseSplitDelta(int offset) { splitDelta += offset; } /** * Returns true if a space has to be inserted after operator false otherwise. */ private boolean insertSpaceAfter(int token) { switch (token) { case TokenNameLPAREN: case TokenNameNOT: case TokenNameTWIDDLE: case TokenNameDOT: case 0: // no token case TokenNameWHITESPACE: case TokenNameLBRACKET: case TokenNameDOLLAR: case Scanner.TokenNameCOMMENT_LINE: return false; default: return true; } } /** * Returns true if a space has to be inserted before operator false otherwise.
* Cannot be static as it uses the code formatter options (to know if the compact assignment mode is on). */ private boolean insertSpaceBefore(int token) { switch (token) { case TokenNameEQUAL: return (!options.compactAssignmentMode); default: return false; } } private static boolean isComment(int token) { boolean result = token == Scanner.TokenNameCOMMENT_BLOCK || token == Scanner.TokenNameCOMMENT_LINE || token == Scanner.TokenNameCOMMENT_PHPDOC; return result; } private static boolean isLiteralToken(int token) { boolean result = token == TokenNameIntegerLiteral // || token == TokenNameLongLiteral // || token == TokenNameFloatingPointLiteral || token == TokenNameDoubleLiteral // || token == TokenNameCharacterLiteral || token == TokenNameStringDoubleQuote; return result; } /** * If the length of oneLineBuffer exceeds maxLineLength, it is split and the result is dumped in * formattedSource * * @param newLineCount * the number of new lines to append */ private void newLine(int newLineCount) { // format current line splitDelta = 0; beginningOfLineIndex = formattedSource.length(); String currentLine = currentLineBuffer.toString(); if (containsOpenCloseBraces) { containsOpenCloseBraces = false; outputLine(currentLine, false, indentationLevelForOpenCloseBraces, 0, -1, null, 0); indentationLevelForOpenCloseBraces = currentLineIndentationLevel; } else { outputLine(currentLine, false, currentLineIndentationLevel, 0, -1, null, 0); } // dump line break(s) for (int i = 0; i < newLineCount; i++) { formattedSource.append(options.lineSeparatorSequence); increaseSplitDelta(options.lineSeparatorSequence.length); } // reset formatter for next line int currentLength = currentLine.length(); currentLineBuffer = new StringBuffer(currentLength > maxLineSize ? maxLineSize = currentLength : maxLineSize); increaseGlobalDelta(splitDelta); increaseGlobalDelta(lineDelta); lineDelta = 0; currentLineIndentationLevel = initialIndentationLevel; } private String operatorString(int operator) { switch (operator) { case TokenNameextends: return "extends"; //$NON-NLS-1$ // case TokenNameimplements : // return "implements"; //$NON-NLS-1$ // // case TokenNamethrows : // return "throws"; //$NON-NLS-1$ case TokenNameSEMICOLON: // ; return ";"; //$NON-NLS-1$ case TokenNameCOMMA: // , return ","; //$NON-NLS-1$ case TokenNameEQUAL: // = return "="; //$NON-NLS-1$ case TokenNameAND_AND: // && (15.22) return "&&"; //$NON-NLS-1$ case TokenNameOR_OR: // || (15.23) return "||"; //$NON-NLS-1$ case TokenNameQUESTION: // ? (15.24) return "?"; //$NON-NLS-1$ case TokenNameCOLON: // : (15.24) return ":"; //$NON-NLS-1$ case TokenNamePAAMAYIM_NEKUDOTAYIM: // : (15.24) return "::"; //$NON-NLS-1$ case TokenNameEQUAL_EQUAL: // == (15.20, 15.20.1, 15.20.2, 15.20.3) return "=="; //$NON-NLS-1$ case TokenNameEQUAL_EQUAL_EQUAL: // == (15.20, 15.20.1, 15.20.2, 15.20.3) return "==="; //$NON-NLS-1$ case TokenNameEQUAL_GREATER: // -= (15.25.2) return "=>"; //$NON-NLS-1$ case TokenNameNOT_EQUAL: // != (15.20, 15.20.1, 15.20.2, 15.20.3) return "!="; //$NON-NLS-1$ case TokenNameNOT_EQUAL_EQUAL: // != (15.20, 15.20.1, 15.20.2, 15.20.3) return "!=="; //$NON-NLS-1$ case TokenNameLESS: // < (15.19.1) return "<"; //$NON-NLS-1$ case TokenNameLESS_EQUAL: // <= (15.19.1) return "<="; //$NON-NLS-1$ case TokenNameGREATER: // > (15.19.1) return ">"; //$NON-NLS-1$ case TokenNameGREATER_EQUAL: // >= (15.19.1) return ">="; //$NON-NLS-1$ // case TokenNameinstanceof : // instanceof // return "instanceof"; //$NON-NLS-1$ case TokenNamePLUS: // + (15.17, 15.17.2) return "+"; //$NON-NLS-1$ case TokenNameMINUS: // - (15.17.2) return "-"; //$NON-NLS-1$ case TokenNameMULTIPLY: // * (15.16.1) return "*"; //$NON-NLS-1$ case TokenNameDIVIDE: // / (15.16.2) return "/"; //$NON-NLS-1$ case TokenNameREMAINDER: // % (15.16.3) return "%"; //$NON-NLS-1$ case TokenNameLEFT_SHIFT: // << (15.18) return "<<"; //$NON-NLS-1$ case TokenNameRIGHT_SHIFT: // >> (15.18) return ">>"; //$NON-NLS-1$ // case TokenNameUNSIGNED_RIGHT_SHIFT : // >>> (15.18) // return ">>>"; //$NON-NLS-1$ case TokenNameAND: // & (15.21, 15.21.1, 15.21.2) return "&"; //$NON-NLS-1$ case TokenNameOR: // | (15.21, 15.21.1, 15.21.2) return "|"; //$NON-NLS-1$ case TokenNameXOR: // ^ (15.21, 15.21.1, 15.21.2) return "^"; //$NON-NLS-1$ case TokenNameMULTIPLY_EQUAL: // *= (15.25.2) return "*="; //$NON-NLS-1$ case TokenNameDIVIDE_EQUAL: // /= (15.25.2) return "/="; //$NON-NLS-1$ case TokenNameREMAINDER_EQUAL: // %= (15.25.2) return "%="; //$NON-NLS-1$ case TokenNamePLUS_EQUAL: // += (15.25.2) return "+="; //$NON-NLS-1$ case TokenNameMINUS_EQUAL: // -= (15.25.2) return "-="; //$NON-NLS-1$ case TokenNameMINUS_GREATER: // -= (15.25.2) return "->"; //$NON-NLS-1$ case TokenNameLEFT_SHIFT_EQUAL: // <<= (15.25.2) return "<<="; //$NON-NLS-1$ case TokenNameRIGHT_SHIFT_EQUAL: // >>= (15.25.2) return ">>="; //$NON-NLS-1$ // case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL : // >>>= (15.25.2) // return ">>>="; //$NON-NLS-1$ case TokenNameAND_EQUAL: // &= (15.25.2) return "&="; //$NON-NLS-1$ case TokenNameXOR_EQUAL: // ^= (15.25.2) return "^="; //$NON-NLS-1$ case TokenNameOR_EQUAL: // |= (15.25.2) return "|="; //$NON-NLS-1$ case TokenNameDOT_EQUAL: // .= return ".="; //$NON-NLS-1$ case TokenNameDOT: // . return "."; //$NON-NLS-1$ default: return ""; //$NON-NLS-1$ } } /** * Appends stringToOutput to the formatted output.
* If it contains \n, append a LINE_SEPARATOR and indent after it. */ private void output(String stringToOutput) { char currentCharacter; for (int i = 0, max = stringToOutput.length(); i < max; i++) { currentCharacter = stringToOutput.charAt(i); if (currentCharacter != '\t') { currentLineBuffer.append(currentCharacter); } } } /** * Appends token to the formatted output.
* If it contains \n, append a LINE_SEPARATOR and indent after it. */ private void outputCurrentToken(int token) { char[] source = scanner.source; int startPosition = scanner.startPosition; switch (token) { case Scanner.TokenNameCOMMENT_PHPDOC: case Scanner.TokenNameCOMMENT_BLOCK: case Scanner.TokenNameCOMMENT_LINE: boolean endOfLine = false; int currentCommentOffset = getCurrentCommentOffset(); int beginningOfLineSpaces = 0; endOfLine = false; currentCommentOffset = getCurrentCommentOffset(); beginningOfLineSpaces = 0; boolean pendingCarriageReturn = false; for (int i = startPosition, max = scanner.currentPosition; i < max; i++) { char currentCharacter = source[i]; updateMappedPositions(i); switch (currentCharacter) { case '\r': pendingCarriageReturn = true; endOfLine = true; break; case '\n': if (pendingCarriageReturn) { increaseGlobalDelta(options.lineSeparatorSequence.length - 2); } else { increaseGlobalDelta(options.lineSeparatorSequence.length - 1); } pendingCarriageReturn = false; currentLineBuffer.append(options.lineSeparatorSequence); beginningOfLineSpaces = 0; endOfLine = true; break; case '\t': if (pendingCarriageReturn) { pendingCarriageReturn = false; increaseGlobalDelta(options.lineSeparatorSequence.length - 1); currentLineBuffer.append(options.lineSeparatorSequence); beginningOfLineSpaces = 0; endOfLine = true; } if (endOfLine) { // we remove a maximum of currentCommentOffset characters (tabs // are converted to space numbers). beginningOfLineSpaces += options.tabSize; if (beginningOfLineSpaces > currentCommentOffset) { currentLineBuffer.append(currentCharacter); } else { increaseGlobalDelta(-1); } } else { currentLineBuffer.append(currentCharacter); } break; case ' ': if (pendingCarriageReturn) { pendingCarriageReturn = false; increaseGlobalDelta(options.lineSeparatorSequence.length - 1); currentLineBuffer.append(options.lineSeparatorSequence); beginningOfLineSpaces = 0; endOfLine = true; } if (endOfLine) { // we remove a maximum of currentCommentOffset characters (tabs // are converted to space numbers). beginningOfLineSpaces++; if (beginningOfLineSpaces > currentCommentOffset) { currentLineBuffer.append(currentCharacter); } else { increaseGlobalDelta(-1); } } else { currentLineBuffer.append(currentCharacter); } break; default: if (pendingCarriageReturn) { pendingCarriageReturn = false; increaseGlobalDelta(options.lineSeparatorSequence.length - 1); currentLineBuffer.append(options.lineSeparatorSequence); beginningOfLineSpaces = 0; endOfLine = true; } else { beginningOfLineSpaces = 0; currentLineBuffer.append(currentCharacter); endOfLine = false; } } } updateMappedPositions(scanner.currentPosition - 1); multipleLineCommentCounter++; break; default: for (int i = startPosition, max = scanner.currentPosition; i < max; i++) { char currentCharacter = source[i]; updateMappedPositions(i); currentLineBuffer.append(currentCharacter); } } } /** * Outputs currentString:
* * * @param currentString * string to output * @param preIndented * whether the string to output was pre-indented * @param depth * number of indentation to put in front of currentString * @param operator * value of the operator belonging to currentString. */ private void outputLine(String currentString, boolean preIndented, int depth, int operator, int substringIndex, int[] startSubstringIndexes, int offsetInGlobalLine) { boolean emptyFirstSubString = false; String operatorString = operatorString(operator); boolean placeOperatorBehind = !breakLineBeforeOperator(operator); boolean placeOperatorAhead = !placeOperatorBehind; // dump prefix operator? if (placeOperatorAhead) { if (!preIndented) { dumpTab(depth); preIndented = true; } if (operator != 0) { if (insertSpaceBefore(operator)) { formattedSource.append(' '); increaseSplitDelta(1); } formattedSource.append(operatorString); increaseSplitDelta(operatorString.length()); if (insertSpaceAfter(operator) && operator != TokenNameimplements && operator != TokenNameextends) { // && operator != TokenNamethrows) { formattedSource.append(' '); increaseSplitDelta(1); } } } SplitLine splitLine = null; if (options.maxLineLength == 0 || getLength(currentString, depth) < options.maxLineLength || (splitLine = split(currentString, offsetInGlobalLine)) == null) { // depending on the type of operator, outputs new line before of after // dumping it // indent before postfix operator // indent also when the line cannot be split if (operator == TokenNameextends || operator == TokenNameimplements) { // || operator == TokenNamethrows) { formattedSource.append(' '); increaseSplitDelta(1); } if (placeOperatorBehind) { if (!preIndented) { dumpTab(depth); } } int max = currentString.length(); if (multipleLineCommentCounter != 0) { try { BufferedReader reader = new BufferedReader(new StringReader(currentString)); String line = reader.readLine(); while (line != null) { updateMappedPositionsWhileSplitting(beginningOfLineIndex, beginningOfLineIndex + line.length() + options.lineSeparatorSequence.length); formattedSource.append(line); beginningOfLineIndex = beginningOfLineIndex + line.length(); if ((line = reader.readLine()) != null) { formattedSource.append(options.lineSeparatorSequence); beginningOfLineIndex += options.lineSeparatorSequence.length; dumpTab(currentLineIndentationLevel); } } reader.close(); } catch (IOException e) { e.printStackTrace(); } } else { updateMappedPositionsWhileSplitting(beginningOfLineIndex, beginningOfLineIndex + max); for (int i = 0; i < max; i++) { char currentChar = currentString.charAt(i); switch (currentChar) { case '\r': break; case '\n': if (i != max - 1) { // fix for 1FFYL5C: LFCOM:ALL - Incorrect indentation when // split with a comment inside a condition // a substring cannot end with a lineSeparatorSequence, // except if it has been added by format() after a one-line // comment formattedSource.append(options.lineSeparatorSequence); // 1FGDDV6: LFCOM:WIN98 - Weird splitting on message expression dumpTab(depth - 1); } break; default: formattedSource.append(currentChar); } } } // update positions inside the mappedPositions table if (substringIndex != -1) { if (multipleLineCommentCounter == 0) { int startPosition = beginningOfLineIndex + startSubstringIndexes[substringIndex]; updateMappedPositionsWhileSplitting(startPosition, startPosition + max); } // compute the splitDelta resulting with the operator and blank removal if (substringIndex + 1 != startSubstringIndexes.length) { increaseSplitDelta(startSubstringIndexes[substringIndex] + max - startSubstringIndexes[substringIndex + 1]); } } // dump postfix operator? if (placeOperatorBehind) { if (insertSpaceBefore(operator)) { formattedSource.append(' '); if (operator != 0) { increaseSplitDelta(1); } } formattedSource.append(operatorString); if (operator != 0) { increaseSplitDelta(operatorString.length()); } } return; } // fix for 1FG0BA3: LFCOM:WIN98 - Weird splitting on interfaces // extends has to stand alone on a line when currentString has been split. if (options.maxLineLength != 0 && splitLine != null && (operator == TokenNameextends)) { // || operator == TokenNameimplements // || operator == TokenNamethrows)) { formattedSource.append(options.lineSeparatorSequence); increaseSplitDelta(options.lineSeparatorSequence.length); dumpTab(depth + 1); } else { if (operator == TokenNameextends) { // || operator == TokenNameimplements // || operator == TokenNamethrows) { formattedSource.append(' '); increaseSplitDelta(1); } } // perform actual splitting String result[] = splitLine.substrings; int[] splitOperators = splitLine.operators; if (result[0].length() == 0) { // when the substring 0 is null, the substring 1 is correctly indented. depth--; emptyFirstSubString = true; } // the operator going in front of the result[0] string is the operator // parameter for (int i = 0, max = result.length; i < max; i++) { // the new depth is the current one if this is the first substring, // the current one + 1 otherwise. // if the substring is a comment, use the current indentation Level // instead of the depth // (-1 because the ouputline increases depth). // (fix for 1FFC72R: LFCOM:ALL - Incorrect line split in presence of line // comments) String currentResult = result[i]; if (currentResult.length() != 0 || splitOperators[i] != 0) { int newDepth = (currentResult.startsWith("/*") //$NON-NLS-1$ || currentResult.startsWith("//")) //$NON-NLS-1$ ? indentationLevel - 1 : depth; outputLine(currentResult, i == 0 || (i == 1 && emptyFirstSubString) ? preIndented : false, i == 0 ? newDepth : newDepth + 1, splitOperators[i], i, splitLine.startSubstringsIndexes, currentString .indexOf(currentResult)); if (i != max - 1) { formattedSource.append(options.lineSeparatorSequence); increaseSplitDelta(options.lineSeparatorSequence.length); } } } if (result.length == splitOperators.length - 1) { int lastOperator = splitOperators[result.length]; String lastOperatorString = operatorString(lastOperator); formattedSource.append(options.lineSeparatorSequence); increaseSplitDelta(options.lineSeparatorSequence.length); if (breakLineBeforeOperator(lastOperator)) { dumpTab(depth + 1); if (lastOperator != 0) { if (insertSpaceBefore(lastOperator)) { formattedSource.append(' '); increaseSplitDelta(1); } formattedSource.append(lastOperatorString); increaseSplitDelta(lastOperatorString.length()); if (insertSpaceAfter(lastOperator) && lastOperator != TokenNameimplements && lastOperator != TokenNameextends) { // && lastOperator != TokenNamethrows) { formattedSource.append(' '); increaseSplitDelta(1); } } } } if (placeOperatorBehind) { if (insertSpaceBefore(operator)) { formattedSource.append(' '); increaseSplitDelta(1); } formattedSource.append(operatorString); //increaseSplitDelta(operatorString.length()); } } /** * Pops the top statement of the stack if it is token */ private int pop(int token) { int delta = 0; if ((constructionsCount > 0) && (constructions[constructionsCount - 1] == token)) { delta--; constructionsCount--; } return delta; } /** * Pops the top statement of the stack if it is a BLOCK or a NONINDENT_BLOCK. */ private int popBlock() { int delta = 0; if ((constructionsCount > 0) && ((constructions[constructionsCount - 1] == BLOCK) || (constructions[constructionsCount - 1] == NONINDENT_BLOCK))) { if (constructions[constructionsCount - 1] == BLOCK) delta--; constructionsCount--; } return delta; } /** * Pops elements until the stack is empty or the top element is token.
* Does not remove token from the stack. * * @param token * the token to be left as the top of the stack */ private int popExclusiveUntil(int token) { int delta = 0; int startCount = constructionsCount; for (int i = startCount - 1; i >= 0 && constructions[i] != token; i--) { if (constructions[i] != NONINDENT_BLOCK) delta--; constructionsCount--; } return delta; } /** * Pops elements until the stack is empty or the top element is a BLOCK or a NONINDENT_BLOCK.
* Does not remove it from the stack. */ private int popExclusiveUntilBlock() { int startCount = constructionsCount; int delta = 0; for (int i = startCount - 1; i >= 0 && constructions[i] != BLOCK && constructions[i] != NONINDENT_BLOCK; i--) { constructionsCount--; delta--; } return delta; } /** * Pops elements until the stack is empty or the top element is a BLOCK, a NONINDENT_BLOCK or a * CASE.
* Does not remove it from the stack. */ private int popExclusiveUntilBlockOrCase() { int startCount = constructionsCount; int delta = 0; for (int i = startCount - 1; i >= 0 && constructions[i] != BLOCK && constructions[i] != NONINDENT_BLOCK && constructions[i] != TokenNamecase; i--) { constructionsCount--; delta--; } return delta; } /** * Pops elements until the stack is empty or the top element is token.
* Removes token from the stack too. * * @param token * the token to remove from the stack */ private int popInclusiveUntil(int token) { int startCount = constructionsCount; int delta = 0; for (int i = startCount - 1; i >= 0 && constructions[i] != token; i--) { if (constructions[i] != NONINDENT_BLOCK) delta--; constructionsCount--; } if (constructionsCount > 0) { if (constructions[constructionsCount - 1] != NONINDENT_BLOCK) delta--; constructionsCount--; } return delta; } /** * Pops elements until the stack is empty or the top element is a BLOCK or a NONINDENT_BLOCK.
* Does not remove it from the stack. */ private int popInclusiveUntilBlock() { int startCount = constructionsCount; int delta = 0; for (int i = startCount - 1; i >= 0 && (constructions[i] != BLOCK && constructions[i] != NONINDENT_BLOCK); i--) { delta--; constructionsCount--; } if (constructionsCount > 0) { if (constructions[constructionsCount - 1] == BLOCK) delta--; constructionsCount--; } return delta; } /** * Pushes a block in the stack.
* Pushes a BLOCK if the stack is empty or if the top element is a BLOCK, pushes * NONINDENT_BLOCK otherwise. Creates a new bigger array if the current one is full. */ private int pushBlock() { int delta = 0; if (constructionsCount == constructions.length) System.arraycopy(constructions, 0, (constructions = new int[constructionsCount * 2]), 0, constructionsCount); if ((constructionsCount == 0) || (constructions[constructionsCount - 1] == BLOCK) || (constructions[constructionsCount - 1] == NONINDENT_BLOCK) || (constructions[constructionsCount - 1] == TokenNamecase)) { delta++; constructions[constructionsCount++] = BLOCK; } else { constructions[constructionsCount++] = NONINDENT_BLOCK; } return delta; } /** * Pushes token.
* Creates a new bigger array if the current one is full. */ private int pushControlStatement(int token) { if (constructionsCount == constructions.length) System.arraycopy(constructions, 0, (constructions = new int[constructionsCount * 2]), 0, constructionsCount); constructions[constructionsCount++] = token; return 1; } private static boolean separateFirstArgumentOn(int currentToken) { //return (currentToken == TokenNameCOMMA || currentToken == // TokenNameSEMICOLON); return currentToken != TokenNameif && currentToken != TokenNameLPAREN && currentToken != TokenNameNOT && currentToken != TokenNamewhile && currentToken != TokenNamefor && currentToken != TokenNameforeach && currentToken != TokenNameswitch; } /** * Set the positions to map. The mapped positions should be retrieved using the getMappedPositions() method. * * @param positions * int[] * @deprecated Set the positions to map using the format(String, int, int[]) method. * * @see #getMappedPositions() */ public void setPositionsToMap(int[] positions) { positionsToMap = positions; lineDelta = 0; globalDelta = 0; mappedPositions = new int[positions.length]; } /** * Appends a space character to the current line buffer. */ private void space() { currentLineBuffer.append(' '); increaseLineDelta(1); } /** * Splits stringToSplit on the top level token
* If there are several identical token at the same level, the string is cut into many pieces. * * @return an object containing the operator and all the substrings or null if the string cannot be split */ public SplitLine split(String stringToSplit) { return split(stringToSplit, 0); } /** * Splits stringToSplit on the top level token
* If there are several identical token at the same level, the string is cut into many pieces. * * @return an object containing the operator and all the substrings or null if the string cannot be split */ public SplitLine split(String stringToSplit, int offsetInGlobalLine) { /* * See http://dev.eclipse.org/bugs/show_bug.cgi?id=12540 and http://dev.eclipse.org/bugs/show_bug.cgi?id=14387 */ if (stringToSplit.indexOf("//$NON-NLS") != -1) { //$NON-NLS-1$ return null; } // split doesn't work correct for PHP return null; // local variables // int currentToken = 0; // int splitTokenType = 0; // int splitTokenDepth = Integer.MAX_VALUE; // int splitTokenPriority = Integer.MAX_VALUE; // int[] substringsStartPositions = new int[10]; // // contains the start position of substrings // int[] substringsEndPositions = new int[10]; // // contains the start position of substrings // int substringsCount = 1; // index in the substringsStartPosition array // int[] splitOperators = new int[10]; // // contains the start position of substrings // int splitOperatorsCount = 0; // index in the substringsStartPosition array // int[] openParenthesisPosition = new int[10]; // int openParenthesisPositionCount = 0; // int position = 0; // int lastOpenParenthesisPosition = -1; // // used to remember the position of the 1st open parenthesis // // needed for a pattern like: A.B(C); we want formatted like A.B( split C); // // setup the scanner with a new source // int lastCommentStartPosition = -1; // // to remember the start position of the last comment // int firstTokenOnLine = -1; // // to remember the first token of the line // int previousToken = -1; // // to remember the previous token. // splitScanner.setSource(stringToSplit.toCharArray()); // try { // // start the loop // while (true) { // // takes the next token // try { // if (currentToken != Scanner.TokenNameWHITESPACE) // previousToken = currentToken; // currentToken = splitScanner.getNextToken(); // if (Scanner.DEBUG) { // int currentEndPosition = splitScanner.getCurrentTokenEndPosition(); // int currentStartPosition = splitScanner // .getCurrentTokenStartPosition(); // System.out.print(currentStartPosition + "," + currentEndPosition // + ": "); // System.out.println(scanner.toStringAction(currentToken)); // } // } catch (InvalidInputException e) { // if (!handleInvalidToken(e)) // throw e; // currentToken = 0; // // this value is not modify when an exception is raised. // } // if (currentToken == TokenNameEOF) // break; // if (firstTokenOnLine == -1) { // firstTokenOnLine = currentToken; // } // switch (currentToken) { // case TokenNameRBRACE : // case TokenNameRPAREN : // if (openParenthesisPositionCount > 0) { // if (openParenthesisPositionCount == 1 // && lastOpenParenthesisPosition < openParenthesisPosition[0]) { // lastOpenParenthesisPosition = openParenthesisPosition[0]; // } else if ((splitTokenDepth == Integer.MAX_VALUE) // || (splitTokenDepth > openParenthesisPositionCount && openParenthesisPositionCount == 1)) { // splitTokenType = 0; // splitTokenDepth = openParenthesisPositionCount; // splitTokenPriority = Integer.MAX_VALUE; // substringsStartPositions[0] = 0; // // better token means the whole line until now is the first // // substring // substringsCount = 1; // resets the count of substrings // substringsEndPositions[0] = openParenthesisPosition[0]; // // substring ends on operator start // position = openParenthesisPosition[0]; // // the string mustn't be cut before the closing parenthesis but // // after the opening one. // splitOperatorsCount = 1; // resets the count of split operators // splitOperators[0] = 0; // } // openParenthesisPositionCount--; // } // break; // case TokenNameLBRACE : // case TokenNameLPAREN : // if (openParenthesisPositionCount == openParenthesisPosition.length) { // System // .arraycopy( // openParenthesisPosition, // 0, // (openParenthesisPosition = new int[openParenthesisPositionCount * 2]), // 0, openParenthesisPositionCount); // } // openParenthesisPosition[openParenthesisPositionCount++] = splitScanner.currentPosition; // if (currentToken == TokenNameLPAREN // && previousToken == TokenNameRPAREN) { // openParenthesisPosition[openParenthesisPositionCount - 1] = splitScanner.startPosition; // } // break; // case TokenNameSEMICOLON : // // ; // case TokenNameCOMMA : // // , // case TokenNameEQUAL : // // = // if (openParenthesisPositionCount < splitTokenDepth // || (openParenthesisPositionCount == splitTokenDepth && splitTokenPriority > getTokenPriority(currentToken))) { // // the current token is better than the one we currently have // // (in level or in priority if same level) // // reset the substringsCount // splitTokenDepth = openParenthesisPositionCount; // splitTokenType = currentToken; // splitTokenPriority = getTokenPriority(currentToken); // substringsStartPositions[0] = 0; // // better token means the whole line until now is the first // // substring // if (separateFirstArgumentOn(firstTokenOnLine) // && openParenthesisPositionCount > 0) { // substringsCount = 2; // resets the count of substrings // substringsEndPositions[0] = openParenthesisPosition[splitTokenDepth - 1]; // substringsStartPositions[1] = openParenthesisPosition[splitTokenDepth - 1]; // substringsEndPositions[1] = splitScanner.startPosition; // splitOperatorsCount = 2; // resets the count of split operators // splitOperators[0] = 0; // splitOperators[1] = currentToken; // position = splitScanner.currentPosition; // // next substring will start from operator end // } else { // substringsCount = 1; // resets the count of substrings // substringsEndPositions[0] = splitScanner.startPosition; // // substring ends on operator start // position = splitScanner.currentPosition; // // next substring will start from operator end // splitOperatorsCount = 1; // resets the count of split operators // splitOperators[0] = currentToken; // } // } else { // if ((openParenthesisPositionCount == splitTokenDepth && splitTokenPriority == getTokenPriority(currentToken)) // && splitTokenType != TokenNameEQUAL // && currentToken != TokenNameEQUAL) { // // fix for 1FG0BCN: LFCOM:WIN98 - Missing one indentation after // // split // // take only the 1st = into account. // // if another token with the same priority is found, // // push the start position of the substring and // // push the token into the stack. // // create a new array object if the current one is full. // if (substringsCount == substringsStartPositions.length) { // System // .arraycopy( // substringsStartPositions, // 0, // (substringsStartPositions = new int[substringsCount * 2]), // 0, substringsCount); // System.arraycopy(substringsEndPositions, 0, // (substringsEndPositions = new int[substringsCount * 2]), // 0, substringsCount); // } // if (splitOperatorsCount == splitOperators.length) { // System.arraycopy(splitOperators, 0, // (splitOperators = new int[splitOperatorsCount * 2]), 0, // splitOperatorsCount); // } // substringsStartPositions[substringsCount] = position; // substringsEndPositions[substringsCount++] = splitScanner.startPosition; // // substring ends on operator start // position = splitScanner.currentPosition; // // next substring will start from operator end // splitOperators[splitOperatorsCount++] = currentToken; // } // } // break; // case TokenNameCOLON : // // : (15.24) // // see 1FK7C5R, we only split on a colon, when it is associated // // with a question-mark. // // indeed it might appear also behind a case statement, and we do // // not to break at this point. // if ((splitOperatorsCount == 0) // || splitOperators[splitOperatorsCount - 1] != TokenNameQUESTION) { // break; // } // case TokenNameextends : // case TokenNameimplements : // //case TokenNamethrows : // case TokenNameDOT : // // . // case TokenNameMULTIPLY : // // * (15.16.1) // case TokenNameDIVIDE : // // / (15.16.2) // case TokenNameREMAINDER : // // % (15.16.3) // case TokenNamePLUS : // // + (15.17, 15.17.2) // case TokenNameMINUS : // // - (15.17.2) // case TokenNameLEFT_SHIFT : // // << (15.18) // case TokenNameRIGHT_SHIFT : // // >> (15.18) // // case TokenNameUNSIGNED_RIGHT_SHIFT : // >>> (15.18) // case TokenNameLESS : // // < (15.19.1) // case TokenNameLESS_EQUAL : // // <= (15.19.1) // case TokenNameGREATER : // // > (15.19.1) // case TokenNameGREATER_EQUAL : // // >= (15.19.1) // // case TokenNameinstanceof : // instanceof // case TokenNameEQUAL_EQUAL : // // == (15.20, 15.20.1, 15.20.2, 15.20.3) // case TokenNameEQUAL_EQUAL_EQUAL : // // == (15.20, 15.20.1, 15.20.2, 15.20.3) // case TokenNameNOT_EQUAL : // // != (15.20, 15.20.1, 15.20.2, 15.20.3) // case TokenNameNOT_EQUAL_EQUAL : // // != (15.20, 15.20.1, 15.20.2, 15.20.3) // case TokenNameAND : // // & (15.21, 15.21.1, 15.21.2) // case TokenNameOR : // // | (15.21, 15.21.1, 15.21.2) // case TokenNameXOR : // // ^ (15.21, 15.21.1, 15.21.2) // case TokenNameAND_AND : // // && (15.22) // case TokenNameOR_OR : // // || (15.23) // case TokenNameQUESTION : // // ? (15.24) // case TokenNameMULTIPLY_EQUAL : // // *= (15.25.2) // case TokenNameDIVIDE_EQUAL : // // /= (15.25.2) // case TokenNameREMAINDER_EQUAL : // // %= (15.25.2) // case TokenNamePLUS_EQUAL : // // += (15.25.2) // case TokenNameMINUS_EQUAL : // // -= (15.25.2) // case TokenNameLEFT_SHIFT_EQUAL : // // <<= (15.25.2) // case TokenNameRIGHT_SHIFT_EQUAL : // // >>= (15.25.2) // // case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL : // >>>= (15.25.2) // case TokenNameAND_EQUAL : // // &= (15.25.2) // case TokenNameXOR_EQUAL : // // ^= (15.25.2) // case TokenNameOR_EQUAL : // // |= (15.25.2) // if ((openParenthesisPositionCount < splitTokenDepth || (openParenthesisPositionCount == splitTokenDepth && splitTokenPriority // > getTokenPriority(currentToken))) // && !((currentToken == TokenNamePLUS || currentToken == TokenNameMINUS) && (previousToken == TokenNameLBRACE // || previousToken == TokenNameLBRACKET || splitScanner.startPosition == 0))) { // // the current token is better than the one we currently have // // (in level or in priority if same level) // // reset the substringsCount // splitTokenDepth = openParenthesisPositionCount; // splitTokenType = currentToken; // splitTokenPriority = getTokenPriority(currentToken); // substringsStartPositions[0] = 0; // // better token means the whole line until now is the first // // substring // if (separateFirstArgumentOn(firstTokenOnLine) // && openParenthesisPositionCount > 0) { // substringsCount = 2; // resets the count of substrings // substringsEndPositions[0] = openParenthesisPosition[splitTokenDepth - 1]; // substringsStartPositions[1] = openParenthesisPosition[splitTokenDepth - 1]; // substringsEndPositions[1] = splitScanner.startPosition; // splitOperatorsCount = 3; // resets the count of split operators // splitOperators[0] = 0; // splitOperators[1] = 0; // splitOperators[2] = currentToken; // position = splitScanner.currentPosition; // // next substring will start from operator end // } else { // substringsCount = 1; // resets the count of substrings // substringsEndPositions[0] = splitScanner.startPosition; // // substring ends on operator start // position = splitScanner.currentPosition; // // next substring will start from operator end // splitOperatorsCount = 2; // resets the count of split operators // splitOperators[0] = 0; // // nothing for first operand since operator will be inserted in // // front of the second operand // splitOperators[1] = currentToken; // } // } else { // if (openParenthesisPositionCount == splitTokenDepth // && splitTokenPriority == getTokenPriority(currentToken)) { // // if another token with the same priority is found, // // push the start position of the substring and // // push the token into the stack. // // create a new array object if the current one is full. // if (substringsCount == substringsStartPositions.length) { // System // .arraycopy( // substringsStartPositions, // 0, // (substringsStartPositions = new int[substringsCount * 2]), // 0, substringsCount); // System.arraycopy(substringsEndPositions, 0, // (substringsEndPositions = new int[substringsCount * 2]), // 0, substringsCount); // } // if (splitOperatorsCount == splitOperators.length) { // System.arraycopy(splitOperators, 0, // (splitOperators = new int[splitOperatorsCount * 2]), 0, // splitOperatorsCount); // } // substringsStartPositions[substringsCount] = position; // substringsEndPositions[substringsCount++] = splitScanner.startPosition; // // substring ends on operator start // position = splitScanner.currentPosition; // // next substring will start from operator end // splitOperators[splitOperatorsCount++] = currentToken; // } // } // default : // break; // } // if (isComment(currentToken)) { // lastCommentStartPosition = splitScanner.startPosition; // } else { // lastCommentStartPosition = -1; // } // } // } catch (InvalidInputException e) { // return null; // } // // if the string cannot be split, return null. // if (splitOperatorsCount == 0) // return null; // // ## SPECIAL CASES BEGIN // if (((splitOperatorsCount == 2 && splitOperators[1] == TokenNameDOT // && splitTokenDepth == 0 && lastOpenParenthesisPosition > -1) // || (splitOperatorsCount > 2 && splitOperators[1] == TokenNameDOT // && splitTokenDepth == 0 && lastOpenParenthesisPosition > -1 && lastOpenParenthesisPosition <= options.maxLineLength) || // (separateFirstArgumentOn(firstTokenOnLine) // && splitTokenDepth > 0 && lastOpenParenthesisPosition > -1)) // && (lastOpenParenthesisPosition < splitScanner.source.length && splitScanner.source[lastOpenParenthesisPosition] != ')')) { // // fix for 1FH4J2H: LFCOM:WINNT - Formatter - Empty parenthesis should // // not be broken on two lines // // only one split on a top level . // // or more than one split on . and substring before open parenthesis fits // // one line. // // or split inside parenthesis and first token is not a for/while/if // SplitLine sl = split( // stringToSplit.substring(lastOpenParenthesisPosition), // lastOpenParenthesisPosition); // if (sl == null || sl.operators[0] != TokenNameCOMMA) { // // trim() is used to remove the extra blanks at the end of the // // substring. See PR 1FGYPI1 // return new SplitLine(new int[]{0, 0}, new String[]{ // stringToSplit.substring(0, lastOpenParenthesisPosition).trim(), // stringToSplit.substring(lastOpenParenthesisPosition)}, new int[]{ // offsetInGlobalLine, // lastOpenParenthesisPosition + offsetInGlobalLine}); // } else { // // right substring can be split and is split on comma // // copy substrings and operators // // except if the 1st string is empty. // int startIndex = (sl.substrings[0].length() == 0) ? 1 : 0; // int subStringsLength = sl.substrings.length + 1 - startIndex; // String[] result = new String[subStringsLength]; // int[] startIndexes = new int[subStringsLength]; // int operatorsLength = sl.operators.length + 1 - startIndex; // int[] operators = new int[operatorsLength]; // result[0] = stringToSplit.substring(0, lastOpenParenthesisPosition); // operators[0] = 0; // System.arraycopy(sl.startSubstringsIndexes, startIndex, startIndexes, // 1, subStringsLength - 1); // for (int i = subStringsLength - 1; i >= 0; i--) { // startIndexes[i] += offsetInGlobalLine; // } // System.arraycopy(sl.substrings, startIndex, result, 1, // subStringsLength - 1); // System.arraycopy(sl.operators, startIndex, operators, 1, // operatorsLength - 1); // return new SplitLine(operators, result, startIndexes); // } // } // // if the last token is a comment and the substring before the comment fits // // on a line, // // split before the comment and return the result. // if (lastCommentStartPosition > -1 // && lastCommentStartPosition < options.maxLineLength // && splitTokenPriority > 50) { // int end = lastCommentStartPosition; // int start = lastCommentStartPosition; // if (stringToSplit.charAt(end - 1) == ' ') { // end--; // } // if (start != end && stringToSplit.charAt(start) == ' ') { // start++; // } // return new SplitLine(new int[]{0, 0}, new String[]{ // stringToSplit.substring(0, end), stringToSplit.substring(start)}, // new int[]{0, start}); // } // if (position != stringToSplit.length()) { // if (substringsCount == substringsStartPositions.length) { // System.arraycopy(substringsStartPositions, 0, // (substringsStartPositions = new int[substringsCount * 2]), 0, // substringsCount); // System.arraycopy(substringsEndPositions, 0, // (substringsEndPositions = new int[substringsCount * 2]), 0, // substringsCount); // } // // avoid empty extra substring, e.g. line terminated with a semi-colon // substringsStartPositions[substringsCount] = position; // substringsEndPositions[substringsCount++] = stringToSplit.length(); // } // if (splitOperatorsCount == splitOperators.length) { // System.arraycopy(splitOperators, 0, // (splitOperators = new int[splitOperatorsCount * 2]), 0, // splitOperatorsCount); // } // splitOperators[splitOperatorsCount] = 0; // // the last element of the stack is the position of the end of // // StringToSPlit // // +1 because the substring method excludes the last character // String[] result = new String[substringsCount]; // for (int i = 0; i < substringsCount; i++) { // int start = substringsStartPositions[i]; // int end = substringsEndPositions[i]; // if (stringToSplit.charAt(start) == ' ') { // start++; // substringsStartPositions[i]++; // } // if (end != start && stringToSplit.charAt(end - 1) == ' ') { // end--; // } // result[i] = stringToSplit.substring(start, end); // substringsStartPositions[i] += offsetInGlobalLine; // } // if (splitOperatorsCount > substringsCount) { // System.arraycopy(substringsStartPositions, 0, // (substringsStartPositions = new int[splitOperatorsCount]), 0, // substringsCount); // System.arraycopy(substringsEndPositions, 0, // (substringsEndPositions = new int[splitOperatorsCount]), 0, // substringsCount); // for (int i = substringsCount; i < splitOperatorsCount; i++) { // substringsStartPositions[i] = position; // substringsEndPositions[i] = position; // } // System.arraycopy(splitOperators, 0, // (splitOperators = new int[splitOperatorsCount]), 0, // splitOperatorsCount); // } else { // System.arraycopy(substringsStartPositions, 0, // (substringsStartPositions = new int[substringsCount]), 0, // substringsCount); // System.arraycopy(substringsEndPositions, 0, // (substringsEndPositions = new int[substringsCount]), 0, // substringsCount); // System.arraycopy(splitOperators, 0, // (splitOperators = new int[substringsCount]), 0, substringsCount); // } // SplitLine splitLine = new SplitLine(splitOperators, result, // substringsStartPositions); // return splitLine; } private void updateMappedPositions(int startPosition) { if (positionsToMap == null) { return; } char[] source = scanner.source; int sourceLength = source.length; while (indexToMap < positionsToMap.length && positionsToMap[indexToMap] <= startPosition) { int posToMap = positionsToMap[indexToMap]; if (posToMap < 0 || posToMap >= sourceLength) { // protection against out of bounds position if (posToMap == sourceLength) { mappedPositions[indexToMap] = formattedSource.length(); } indexToMap = positionsToMap.length; // no more mapping return; } if (CharOperation.isWhitespace(source[posToMap])) { mappedPositions[indexToMap] = startPosition + globalDelta + lineDelta; } else { if (posToMap == sourceLength - 1) { mappedPositions[indexToMap] = startPosition + globalDelta + lineDelta; } else { mappedPositions[indexToMap] = posToMap + globalDelta + lineDelta; } } indexToMap++; } } private void updateMappedPositionsWhileSplitting(int startPosition, int endPosition) { if (mappedPositions == null || mappedPositions.length == indexInMap) return; while (indexInMap < mappedPositions.length && startPosition <= mappedPositions[indexInMap] && mappedPositions[indexInMap] < endPosition && indexInMap < indexToMap) { mappedPositions[indexInMap] += splitDelta; indexInMap++; } } private int getLength(String s, int tabDepth) { int length = 0; for (int i = 0; i < tabDepth; i++) { length += options.tabSize; } for (int i = 0, max = s.length(); i < max; i++) { char currentChar = s.charAt(i); switch (currentChar) { case '\t': length += options.tabSize; break; default: length++; } } return length; } /** * Sets the initial indentation level * * @param indentationLevel * new indentation level * * @deprecated */ public void setInitialIndentationLevel(int newIndentationLevel) { this.initialIndentationLevel = currentLineIndentationLevel = indentationLevel = newIndentationLevel; } }