From: khartlage Date: Sun, 30 Mar 2003 20:04:07 +0000 (+0000) Subject: GotoMatchingBracket implementiert X-Git-Url: http://git.phpeclipse.com GotoMatchingBracket implementiert --- diff --git a/net.sourceforge.phpeclipse/plugin.xml b/net.sourceforge.phpeclipse/plugin.xml index 0dd2df1..8533507 100644 --- a/net.sourceforge.phpeclipse/plugin.xml +++ b/net.sourceforge.phpeclipse/plugin.xml @@ -232,17 +232,16 @@ Temporarily replaced until errors can be ironed out... description="%CodingActionSet.description" visible="false" id="net.sourceforge.phpeclipse.ui.CodingActionSet"> - - - + + + - - - + + + - + id="net.sourceforge.phpeclipse.PHPEditor" + default="true"> + + id="net.sourceforge.phpeclipse.PHPEditor" + default="true"> + id="net.sourceforge.phpeclipse.PHPEditor" + default="true"> + id="net.sourceforge.phpeclipse.PHPEditor" + default="true"> + id="net.sourceforge.phpeclipse.PHPEditor" + default="true"> + id="net.sourceforge.phpeclipse.PHPEditor" + default="true"> + id="net.sourceforge.phpeclipse.PHPEditor" + default="true"> + id="net.sourceforge.phpeclipse.PHPEditor" + default="true"> + + @@ -665,6 +674,7 @@ Temporarily replaced until errors can be ironed out... scopeId="org.eclipse.ui.textEditorScope" configurationId="org.eclipse.ui.defaultAcceleratorConfiguration"> + @@ -687,6 +697,8 @@ Temporarily replaced until errors can be ironed out... scopeId="org.eclipse.ui.textEditorScope" configurationId="org.eclipse.ui.defaultAcceleratorConfiguration"> + + 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*/); // 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*/); - // 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("org.phpeclipse.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("org.phpeclipse.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("org.phpeclipse.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("org.phpeclipse.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("org.phpeclipse.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("org.phpeclipse.phpdt.core.formatter.lineSplit", String.valueOf(valueIndex)); //$NON-NLS-1$ //$NON-NLS-2$ - - } else if(optionName.equals("style.assignment")) { //$NON-NLS-1$ - options.put("org.phpeclipse.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("org.phpeclipse.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("org.phpeclipse.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; - - // 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(); - - // 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 - || constructions[constructionsCount-2] == TokenNamewhile))) {*/ - 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; - } - } - switch (token) { - 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 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 == 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 (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 : - //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 : - - // 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; - 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 == TokenNamePLUS && unarySignModifier > 0) - || (previousToken == TokenNameMINUS && unarySignModifier > 0)) { - pendingSpace = false; - } - unarySignModifier = 0; - } - break; - } - // Do not output whitespace tokens. - if (token != Scanner.TokenNameWHITESPACE) { - - /* 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 - */ - 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) { - 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 TokenNameNOT_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 : // |= - 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 TokenNameLBRACKET : - 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 == TokenNameStringLiteral; - 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 TokenNameEQUAL_EQUAL : // == (15.20, 15.20.1, 15.20.2, 15.20.3) - return "=="; //$NON-NLS-1$ - - case TokenNameNOT_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 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 : // . - 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:
- *
  • If its length is < maxLineLength, output - *
  • Otherwise it is split.
- * @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 != 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; - } - // 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(); - } 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 TokenNameNOT_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; - } + 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*/ + ); // 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*/ + ); + // 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; + + // 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(); + + // 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 + || constructions[constructionsCount-2] == TokenNamewhile))) {*/ + 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; + } + } + switch (token) { + 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 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 == 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 (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 : + //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 : + + // 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; + 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 == TokenNamePLUS && unarySignModifier > 0) + || (previousToken == TokenNameMINUS && unarySignModifier > 0)) { + pendingSpace = false; + } + unarySignModifier = 0; + } + break; + } + // Do not output whitespace tokens. + if (token != Scanner.TokenNameWHITESPACE) { + + /* 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 + */ + 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) { + 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 TokenNameNOT_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 : // |= + 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 TokenNameLBRACKET : + 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 == TokenNameStringLiteral; + 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 TokenNameEQUAL_EQUAL : // == (15.20, 15.20.1, 15.20.2, 15.20.3) + return "=="; //$NON-NLS-1$ + + case TokenNameNOT_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 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 : // . + 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:
+ *
  • If its length is < maxLineLength, output + *
  • Otherwise it is split.
+ * @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 != 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; + } + // 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(); + } 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 TokenNameNOT_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; + } } \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/formatter/impl/FormatterOptions.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/formatter/impl/FormatterOptions.java index 5684b81..ba4127f 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/formatter/impl/FormatterOptions.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/formatter/impl/FormatterOptions.java @@ -12,190 +12,198 @@ package net.sourceforge.phpdt.internal.formatter.impl; import java.util.Map; -public class FormatterOptions { - - /** - * Option IDs - */ - public static final String OPTION_InsertNewlineBeforeOpeningBrace = "org.phpeclipse.phpdt.core.formatter.newline.openingBrace"; //$NON-NLS-1$ - public static final String OPTION_InsertNewlineInControlStatement = "org.phpeclipse.phpdt.core.formatter.newline.controlStatement"; //$NON-NLS-1$ - public static final String OPTION_InsertNewLineBetweenElseAndIf = "org.phpeclipse.phpdt.core.formatter.newline.elseIf"; //$NON-NLS-1$ - public static final String OPTION_InsertNewLineInEmptyBlock = "org.phpeclipse.phpdt.core.formatter.newline.emptyBlock"; //$NON-NLS-1$ - public static final String OPTION_ClearAllBlankLines = "org.phpeclipse.phpdt.core.formatter.newline.clearAll"; //$NON-NLS-1$ - public static final String OPTION_SplitLineExceedingLength = "org.phpeclipse.phpdt.core.formatter.lineSplit"; //$NON-NLS-1$ - public static final String OPTION_CompactAssignment = "org.phpeclipse.phpdt.core.formatter.style.assignment"; //$NON-NLS-1$ - public static final String OPTION_TabulationChar = "org.phpeclipse.phpdt.core.formatter.tabulation.char"; //$NON-NLS-1$ - public static final String OPTION_TabulationSize = "org.phpeclipse.phpdt.core.formatter.tabulation.size"; //$NON-NLS-1$ - - public static final String INSERT = "insert"; //$NON-NLS-1$ - public static final String DO_NOT_INSERT = "do not insert"; //$NON-NLS-1$ - public static final String PRESERVE_ONE = "preserve one"; //$NON-NLS-1$ - public static final String CLEAR_ALL = "clear all"; //$NON-NLS-1$ - public static final String NORMAL = "normal"; //$NON-NLS-1$ - public static final String COMPACT = "compact"; //$NON-NLS-1$ - public static final String TAB = "tab"; //$NON-NLS-1$ - public static final String SPACE = "space"; //$NON-NLS-1$ - - // by default, do not insert blank line before opening brace - public boolean newLineBeforeOpeningBraceMode = false; - - // by default, do not insert blank line behind keywords (ELSE, CATCH, FINALLY,...) in control statements - public boolean newlineInControlStatementMode = false; - - // by default, preserve one blank line per sequence of blank lines - public boolean clearAllBlankLinesMode = false; - - // line splitting will occur when line exceeds this length - public int maxLineLength = 80; - - public boolean compactAssignmentMode = false; // if isTrue, assignments look like x= 12 (not like x = 12); - - //number of consecutive spaces used to replace the tab char - public int tabSize = 4; // n spaces for one tab - public boolean indentWithTab = true; - - public boolean compactElseIfMode = true; // if true, else and if are kept on the same line. - public boolean newLineInEmptyBlockMode = true; // if false, no new line in {} if it's empty. - - public char[] lineSeparatorSequence = System.getProperty("line.separator").toCharArray(); //$NON-NLS-1$ -/** - * Initializing the formatter options with default settings - */ -public FormatterOptions(){ -} -/** - * Initializing the formatter options with external settings - */ -public FormatterOptions(Map settings){ - if (settings == null) return; - - // filter options which are related to the assist component - Object[] entries = settings.entrySet().toArray(); - for (int i = 0, max = entries.length; i < max; i++){ - Map.Entry entry = (Map.Entry)entries[i]; - if (!(entry.getKey() instanceof String)) continue; - if (!(entry.getValue() instanceof String)) continue; - String optionID = (String) entry.getKey(); - String optionValue = (String) entry.getValue(); - - if(optionID.equals(OPTION_InsertNewlineBeforeOpeningBrace)){ - if (optionValue.equals(INSERT)){ - this.newLineBeforeOpeningBraceMode = true; - } else if (optionValue.equals(DO_NOT_INSERT)){ - this.newLineBeforeOpeningBraceMode = false; - } - continue; - } - if(optionID.equals(OPTION_InsertNewlineInControlStatement)){ - if (optionValue.equals(INSERT)){ - this.newlineInControlStatementMode = true; - } else if (optionValue.equals(DO_NOT_INSERT)){ - this.newlineInControlStatementMode = false; - } - continue; - } - if(optionID.equals(OPTION_ClearAllBlankLines)){ - if (optionValue.equals(CLEAR_ALL)){ - this.clearAllBlankLinesMode = true; - } else if (optionValue.equals(PRESERVE_ONE)){ - this.clearAllBlankLinesMode = false; - } - continue; - } - if(optionID.equals(OPTION_InsertNewLineBetweenElseAndIf)){ - if (optionValue.equals(INSERT)){ - this.compactElseIfMode = false; - } else if (optionValue.equals(DO_NOT_INSERT)){ - this.compactElseIfMode = true; - } - continue; - } - if(optionID.equals(OPTION_InsertNewLineInEmptyBlock)){ - if (optionValue.equals(INSERT)){ - this.newLineInEmptyBlockMode = true; - } else if (optionValue.equals(DO_NOT_INSERT)){ - this.newLineInEmptyBlockMode = false; - } - continue; - } - if(optionID.equals(OPTION_SplitLineExceedingLength)){ - try { - int val = Integer.parseInt(optionValue); - if (val >= 0) this.maxLineLength = val; - } catch(NumberFormatException e){ - } - } - if(optionID.equals(OPTION_CompactAssignment)){ - if (optionValue.equals(COMPACT)){ - this.compactAssignmentMode = true; - } else if (optionValue.equals(NORMAL)){ - this.compactAssignmentMode = false; - } - continue; - } - if(optionID.equals(OPTION_TabulationChar)){ - if (optionValue.equals(TAB)){ - this.indentWithTab = true; - } else if (optionValue.equals(SPACE)){ - this.indentWithTab = false; - } - continue; - } - if(optionID.equals(OPTION_TabulationSize)){ - try { - int val = Integer.parseInt(optionValue); - if (val > 0) this.tabSize = val; - } catch(NumberFormatException e){ - } - } - } -} +public class FormatterOptions { -/** - * - * @return int - */ -public int getMaxLineLength() { - return maxLineLength; -} -public int getTabSize() { - return tabSize; -} -public boolean isAddingNewLineBeforeOpeningBrace() { - return newLineBeforeOpeningBraceMode; -} -public boolean isAddingNewLineInControlStatement() { - return newlineInControlStatementMode; -} -public boolean isAddingNewLineInEmptyBlock() { - return newLineInEmptyBlockMode; -} -public boolean isClearingAllBlankLines() { - return clearAllBlankLinesMode; -} -public boolean isCompactingAssignment() { - return compactAssignmentMode; -} -public boolean isCompactingElseIf() { - return compactElseIfMode; -} -public boolean isUsingTabForIndenting() { - return indentWithTab; -} -public void setLineSeparator(String lineSeparator) { - lineSeparatorSequence = lineSeparator.toCharArray(); -} -/** - * @deprecated - should use a Map when creating the options. - */ -public void setMaxLineLength(int maxLineLength) { - this.maxLineLength = maxLineLength; -} -/** - * @deprecated - should use a Map when creating the options. - */ -public void setCompactElseIfMode(boolean flag) { - compactElseIfMode = flag; -} + /** + * Option IDs + */ + public static final String OPTION_InsertNewlineBeforeOpeningBrace = "net.sourceforge.phpdt.core.formatter.newline.openingBrace"; //$NON-NLS-1$ + public static final String OPTION_InsertNewlineInControlStatement = "net.sourceforge.phpdt.core.formatter.newline.controlStatement"; //$NON-NLS-1$ + public static final String OPTION_InsertNewLineBetweenElseAndIf = "net.sourceforge.phpdt.core.formatter.newline.elseIf"; //$NON-NLS-1$ + public static final String OPTION_InsertNewLineInEmptyBlock = "net.sourceforge.phpdt.core.formatter.newline.emptyBlock"; //$NON-NLS-1$ + public static final String OPTION_ClearAllBlankLines = "net.sourceforge.phpdt.core.formatter.newline.clearAll"; //$NON-NLS-1$ + public static final String OPTION_SplitLineExceedingLength = "net.sourceforge.phpdt.core.formatter.lineSplit"; //$NON-NLS-1$ + public static final String OPTION_CompactAssignment = "net.sourceforge.phpdt.core.formatter.style.assignment"; //$NON-NLS-1$ + public static final String OPTION_TabulationChar = "net.sourceforge.phpdt.core.formatter.tabulation.char"; //$NON-NLS-1$ + public static final String OPTION_TabulationSize = "net.sourceforge.phpdt.core.formatter.tabulation.size"; //$NON-NLS-1$ + + public static final String INSERT = "insert"; //$NON-NLS-1$ + public static final String DO_NOT_INSERT = "do not insert"; //$NON-NLS-1$ + public static final String PRESERVE_ONE = "preserve one"; //$NON-NLS-1$ + public static final String CLEAR_ALL = "clear all"; //$NON-NLS-1$ + public static final String NORMAL = "normal"; //$NON-NLS-1$ + public static final String COMPACT = "compact"; //$NON-NLS-1$ + public static final String TAB = "tab"; //$NON-NLS-1$ + public static final String SPACE = "space"; //$NON-NLS-1$ + + // by default, do not insert blank line before opening brace + public boolean newLineBeforeOpeningBraceMode = false; + + // by default, do not insert blank line behind keywords (ELSE, CATCH, FINALLY,...) in control statements + public boolean newlineInControlStatementMode = false; + + // by default, preserve one blank line per sequence of blank lines + public boolean clearAllBlankLinesMode = false; + + // line splitting will occur when line exceeds this length + public int maxLineLength = 80; + + public boolean compactAssignmentMode = false; + // if isTrue, assignments look like x= 12 (not like x = 12); + + //number of consecutive spaces used to replace the tab char + public int tabSize = 4; // n spaces for one tab + public boolean indentWithTab = true; + + public boolean compactElseIfMode = true; + // if true, else and if are kept on the same line. + public boolean newLineInEmptyBlockMode = true; + // if false, no new line in {} if it's empty. + + public char[] lineSeparatorSequence = System.getProperty("line.separator").toCharArray(); //$NON-NLS-1$ + /** + * Initializing the formatter options with default settings + */ + public FormatterOptions() { + } + /** + * Initializing the formatter options with external settings + */ + public FormatterOptions(Map settings) { + if (settings == null) + return; + + // filter options which are related to the assist component + Object[] entries = settings.entrySet().toArray(); + for (int i = 0, max = entries.length; i < max; i++) { + Map.Entry entry = (Map.Entry) entries[i]; + if (!(entry.getKey() instanceof String)) + continue; + if (!(entry.getValue() instanceof String)) + continue; + String optionID = (String) entry.getKey(); + String optionValue = (String) entry.getValue(); + + if (optionID.equals(OPTION_InsertNewlineBeforeOpeningBrace)) { + if (optionValue.equals(INSERT)) { + this.newLineBeforeOpeningBraceMode = true; + } else if (optionValue.equals(DO_NOT_INSERT)) { + this.newLineBeforeOpeningBraceMode = false; + } + continue; + } + if (optionID.equals(OPTION_InsertNewlineInControlStatement)) { + if (optionValue.equals(INSERT)) { + this.newlineInControlStatementMode = true; + } else if (optionValue.equals(DO_NOT_INSERT)) { + this.newlineInControlStatementMode = false; + } + continue; + } + if (optionID.equals(OPTION_ClearAllBlankLines)) { + if (optionValue.equals(CLEAR_ALL)) { + this.clearAllBlankLinesMode = true; + } else if (optionValue.equals(PRESERVE_ONE)) { + this.clearAllBlankLinesMode = false; + } + continue; + } + if (optionID.equals(OPTION_InsertNewLineBetweenElseAndIf)) { + if (optionValue.equals(INSERT)) { + this.compactElseIfMode = false; + } else if (optionValue.equals(DO_NOT_INSERT)) { + this.compactElseIfMode = true; + } + continue; + } + if (optionID.equals(OPTION_InsertNewLineInEmptyBlock)) { + if (optionValue.equals(INSERT)) { + this.newLineInEmptyBlockMode = true; + } else if (optionValue.equals(DO_NOT_INSERT)) { + this.newLineInEmptyBlockMode = false; + } + continue; + } + if (optionID.equals(OPTION_SplitLineExceedingLength)) { + try { + int val = Integer.parseInt(optionValue); + if (val >= 0) + this.maxLineLength = val; + } catch (NumberFormatException e) { + } + } + if (optionID.equals(OPTION_CompactAssignment)) { + if (optionValue.equals(COMPACT)) { + this.compactAssignmentMode = true; + } else if (optionValue.equals(NORMAL)) { + this.compactAssignmentMode = false; + } + continue; + } + if (optionID.equals(OPTION_TabulationChar)) { + if (optionValue.equals(TAB)) { + this.indentWithTab = true; + } else if (optionValue.equals(SPACE)) { + this.indentWithTab = false; + } + continue; + } + if (optionID.equals(OPTION_TabulationSize)) { + try { + int val = Integer.parseInt(optionValue); + if (val > 0) + this.tabSize = val; + } catch (NumberFormatException e) { + } + } + } + } + + /** + * + * @return int + */ + public int getMaxLineLength() { + return maxLineLength; + } + public int getTabSize() { + return tabSize; + } + public boolean isAddingNewLineBeforeOpeningBrace() { + return newLineBeforeOpeningBraceMode; + } + public boolean isAddingNewLineInControlStatement() { + return newlineInControlStatementMode; + } + public boolean isAddingNewLineInEmptyBlock() { + return newLineInEmptyBlockMode; + } + public boolean isClearingAllBlankLines() { + return clearAllBlankLinesMode; + } + public boolean isCompactingAssignment() { + return compactAssignmentMode; + } + public boolean isCompactingElseIf() { + return compactElseIfMode; + } + public boolean isUsingTabForIndenting() { + return indentWithTab; + } + public void setLineSeparator(String lineSeparator) { + lineSeparatorSequence = lineSeparator.toCharArray(); + } + /** + * @deprecated - should use a Map when creating the options. + */ + public void setMaxLineLength(int maxLineLength) { + this.maxLineLength = maxLineLength; + } + /** + * @deprecated - should use a Map when creating the options. + */ + public void setCompactElseIfMode(boolean flag) { + compactElseIfMode = flag; + } } diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/formatter/impl/SplitLine.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/formatter/impl/SplitLine.java index b17a73d..049c220 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/formatter/impl/SplitLine.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/formatter/impl/SplitLine.java @@ -14,198 +14,200 @@ import net.sourceforge.phpdt.core.compiler.ITerminalSymbols; /** Represents a split line: contains an operator and all substrings */ -public class SplitLine implements ITerminalSymbols{ - public int[] operators; // the operator on which the string was split. - public String[] substrings; - public int[] startSubstringsIndexes; -/** - * SplitLine constructor comment. - */ -public SplitLine(int[] operators, String[] substrings) { - this(operators, substrings, null); -} -/** - * SplitLine constructor comment. - */ -public SplitLine(int[] operators, String[] substrings, int[] startIndexes) { - super(); - this.operators=operators; - this.substrings=substrings; - this.startSubstringsIndexes = startIndexes; -} -/** - * Prints a nice representation of the receiver - * @return java.lang.String - */ -public String toString() { - StringBuffer result=new StringBuffer(); - String operatorString = new String(); - - for (int i=0,max=substrings.length;i (15.19.1) - operatorString=">"; //$NON-NLS-1$ - break; - - case TokenNameGREATER_EQUAL : // >= (15.19.1) - operatorString=">="; //$NON-NLS-1$ - break; - -// case TokenNameinstanceof : // instanceof -// operatorString="instanceof"; //$NON-NLS-1$ -// break; - case TokenNamePLUS : // + (15.17, 15.17.2) - operatorString="+"; //$NON-NLS-1$ - break; - - case TokenNameMINUS : // - (15.17.2) - operatorString="-"; //$NON-NLS-1$ - break; - case TokenNameMULTIPLY : // * (15.16.1) - operatorString="*"; //$NON-NLS-1$ - break; - - case TokenNameDIVIDE : // / (15.16.2) - operatorString="/"; //$NON-NLS-1$ - break; - - case TokenNameREMAINDER : // % (15.16.3) - operatorString="%"; //$NON-NLS-1$ - break; - case TokenNameLEFT_SHIFT : // << (15.18) - operatorString="<<"; //$NON-NLS-1$ - break; - - case TokenNameRIGHT_SHIFT : // >> (15.18) - operatorString=">>"; //$NON-NLS-1$ - break; - -// case TokenNameUNSIGNED_RIGHT_SHIFT : // >>> (15.18) -// operatorString=">>>"; //$NON-NLS-1$ -// break; - case TokenNameAND : // & (15.21, 15.21.1, 15.21.2) - operatorString="&"; //$NON-NLS-1$ - break; - - case TokenNameOR : // | (15.21, 15.21.1, 15.21.2) - operatorString="|"; //$NON-NLS-1$ - break; - - case TokenNameXOR : // ^ (15.21, 15.21.1, 15.21.2) - operatorString="^"; //$NON-NLS-1$ - break; - case TokenNameMULTIPLY_EQUAL : // *= (15.25.2) - operatorString="*="; //$NON-NLS-1$ - break; - - case TokenNameDIVIDE_EQUAL : // /= (15.25.2) - operatorString="/="; //$NON-NLS-1$ - break; - case TokenNameREMAINDER_EQUAL : // %= (15.25.2) - operatorString="%="; //$NON-NLS-1$ - break; - - case TokenNamePLUS_EQUAL : // += (15.25.2) - operatorString="+="; //$NON-NLS-1$ - break; - - case TokenNameMINUS_EQUAL : // -= (15.25.2) - operatorString="-="; //$NON-NLS-1$ - break; - - case TokenNameLEFT_SHIFT_EQUAL : // <<= (15.25.2) - operatorString="<<="; //$NON-NLS-1$ - break; - - case TokenNameRIGHT_SHIFT_EQUAL : // >>= (15.25.2) - operatorString=">>="; //$NON-NLS-1$ - break; - -// case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL : // >>>= (15.25.2) -// operatorString=">>>="; //$NON-NLS-1$ -// break; - - case TokenNameAND_EQUAL : // &= (15.25.2) - operatorString="&="; //$NON-NLS-1$ - break; - - case TokenNameXOR_EQUAL : // ^= (15.25.2) - operatorString="^="; //$NON-NLS-1$ - break; - - case TokenNameOR_EQUAL : // |= (15.25.2) - operatorString="|="; //$NON-NLS-1$ - break; - case TokenNameDOT : // . - operatorString="."; //$NON-NLS-1$ - break; - - default: - operatorString=""; //$NON-NLS-1$ - } - if (placeOperatorAhead){ - result.append(operatorString); - } - result.append(currentString); - if (placeOperatorBehind){ - result.append(operatorString); - } - result.append('\n'); - } - return ""; //$NON-NLS-1$ -} +public class SplitLine implements ITerminalSymbols { + public int[] operators; // the operator on which the string was split. + public String[] substrings; + public int[] startSubstringsIndexes; + /** + * SplitLine constructor comment. + */ + public SplitLine(int[] operators, String[] substrings) { + this(operators, substrings, null); + } + /** + * SplitLine constructor comment. + */ + public SplitLine(int[] operators, String[] substrings, int[] startIndexes) { + super(); + this.operators = operators; + this.substrings = substrings; + this.startSubstringsIndexes = startIndexes; + } + /** + * Prints a nice representation of the receiver + * @return java.lang.String + */ + public String toString() { + StringBuffer result = new StringBuffer(); + String operatorString = new String(); + + for (int i = 0, max = substrings.length; i < max; i++) { + int currentOperator = operators[i]; + String currentString = substrings[i]; + boolean placeOperatorAhead = + currentOperator != TokenNameCOMMA + && currentOperator != TokenNameSEMICOLON; + boolean placeOperatorBehind = + currentOperator == TokenNameCOMMA + || currentOperator == TokenNameSEMICOLON; + + switch (currentOperator) { + case TokenNameextends : + operatorString = "extends"; //$NON-NLS-1$ + break; + // case TokenNameimplements: + // operatorString="implements"; //$NON-NLS-1$ + // break; + // case TokenNamethrows: + // operatorString="throws"; //$NON-NLS-1$ + // break; + case TokenNameSEMICOLON : // ; + operatorString = ";"; //$NON-NLS-1$ + break; + case TokenNameCOMMA : // , + operatorString = ","; //$NON-NLS-1$ + break; + case TokenNameEQUAL : // = + operatorString = "="; //$NON-NLS-1$ + break; + case TokenNameAND_AND : // && (15.22) + operatorString = "&&"; //$NON-NLS-1$ + break; + case TokenNameOR_OR : // || (15.23) + operatorString = "||"; //$NON-NLS-1$ + break; + case TokenNameQUESTION : // ? (15.24) + operatorString = "?"; //$NON-NLS-1$ + break; + + case TokenNameCOLON : // : (15.24) + operatorString = ":"; //$NON-NLS-1$ + break; + case TokenNameEQUAL_EQUAL : // == (15.20, 15.20.1, 15.20.2, 15.20.3) + operatorString = "=="; //$NON-NLS-1$ + break; + + case TokenNameNOT_EQUAL : // != (15.20, 15.20.1, 15.20.2, 15.20.3) + operatorString = "!="; //$NON-NLS-1$ + break; + + case TokenNameLESS : // < (15.19.1) + operatorString = "<"; //$NON-NLS-1$ + break; + + case TokenNameLESS_EQUAL : // <= (15.19.1) + operatorString = "<="; //$NON-NLS-1$ + break; + + case TokenNameGREATER : // > (15.19.1) + operatorString = ">"; //$NON-NLS-1$ + break; + + case TokenNameGREATER_EQUAL : // >= (15.19.1) + operatorString = ">="; //$NON-NLS-1$ + break; + + // case TokenNameinstanceof : // instanceof + // operatorString="instanceof"; //$NON-NLS-1$ + // break; + case TokenNamePLUS : // + (15.17, 15.17.2) + operatorString = "+"; //$NON-NLS-1$ + break; + + case TokenNameMINUS : // - (15.17.2) + operatorString = "-"; //$NON-NLS-1$ + break; + case TokenNameMULTIPLY : // * (15.16.1) + operatorString = "*"; //$NON-NLS-1$ + break; + + case TokenNameDIVIDE : // / (15.16.2) + operatorString = "/"; //$NON-NLS-1$ + break; + + case TokenNameREMAINDER : // % (15.16.3) + operatorString = "%"; //$NON-NLS-1$ + break; + case TokenNameLEFT_SHIFT : // << (15.18) + operatorString = "<<"; //$NON-NLS-1$ + break; + + case TokenNameRIGHT_SHIFT : // >> (15.18) + operatorString = ">>"; //$NON-NLS-1$ + break; + + // case TokenNameUNSIGNED_RIGHT_SHIFT : // >>> (15.18) + // operatorString=">>>"; //$NON-NLS-1$ + // break; + case TokenNameAND : // & (15.21, 15.21.1, 15.21.2) + operatorString = "&"; //$NON-NLS-1$ + break; + + case TokenNameOR : // | (15.21, 15.21.1, 15.21.2) + operatorString = "|"; //$NON-NLS-1$ + break; + + case TokenNameXOR : // ^ (15.21, 15.21.1, 15.21.2) + operatorString = "^"; //$NON-NLS-1$ + break; + case TokenNameMULTIPLY_EQUAL : // *= (15.25.2) + operatorString = "*="; //$NON-NLS-1$ + break; + + case TokenNameDIVIDE_EQUAL : // /= (15.25.2) + operatorString = "/="; //$NON-NLS-1$ + break; + case TokenNameREMAINDER_EQUAL : // %= (15.25.2) + operatorString = "%="; //$NON-NLS-1$ + break; + + case TokenNamePLUS_EQUAL : // += (15.25.2) + operatorString = "+="; //$NON-NLS-1$ + break; + + case TokenNameMINUS_EQUAL : // -= (15.25.2) + operatorString = "-="; //$NON-NLS-1$ + break; + + case TokenNameLEFT_SHIFT_EQUAL : // <<= (15.25.2) + operatorString = "<<="; //$NON-NLS-1$ + break; + + case TokenNameRIGHT_SHIFT_EQUAL : // >>= (15.25.2) + operatorString = ">>="; //$NON-NLS-1$ + break; + + // case TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL : // >>>= (15.25.2) + // operatorString=">>>="; //$NON-NLS-1$ + // break; + + case TokenNameAND_EQUAL : // &= (15.25.2) + operatorString = "&="; //$NON-NLS-1$ + break; + + case TokenNameXOR_EQUAL : // ^= (15.25.2) + operatorString = "^="; //$NON-NLS-1$ + break; + + case TokenNameOR_EQUAL : // |= (15.25.2) + operatorString = "|="; //$NON-NLS-1$ + break; + case TokenNameDOT : // . + operatorString = "."; //$NON-NLS-1$ + break; + + default : + operatorString = ""; //$NON-NLS-1$ + } + if (placeOperatorAhead) { + result.append(operatorString); + } + result.append(currentString); + if (placeOperatorBehind) { + result.append(operatorString); + } + result.append('\n'); + } + return ""; //$NON-NLS-1$ + } } diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/ActionMessages.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/ActionMessages.java new file mode 100644 index 0000000..120b578 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/ActionMessages.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 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.ui.actions; + +import java.text.MessageFormat; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * Class that gives access to the action messages resource bundle. + */ +public class ActionMessages { + + private static final String BUNDLE_NAME= "net.sourceforge.phpdt.internal.ui.actions.ActionMessages"; //$NON-NLS-1$ + + private static final ResourceBundle RESOURCE_BUNDLE= ResourceBundle.getBundle(BUNDLE_NAME); + + private ActionMessages() { + // no instance + } + + /** + * Returns the resource string associated with the given key in the resource bundle. If there isn't + * any value under the given key, the key is returned. + * + * @param key the resource key + * @return the string + */ + public static String getString(String key) { + try { + return RESOURCE_BUNDLE.getString(key); + } catch (MissingResourceException e) { + return '!' + key + '!'; + } + } + + /** + * Returns the formatted resource string associated with the given key in the resource bundle. + * MessageFormat is used to format the message. If there isn't any value + * under the given key, the key is returned. + * + * @param key the resource key + * @param arg the message argument + * @return the string + */ + public static String getFormattedString(String key, Object arg) { + return getFormattedString(key, new Object[] { arg }); + } + + /** + * Returns the formatted resource string associated with the given key in the resource bundle. + * MessageFormat is used to format the message. If there isn't any value + * under the given key, the key is returned. + * + * @param key the resource key + * @param args the message arguments + * @return the string + */ + public static String getFormattedString(String key, Object[] args) { + return MessageFormat.format(getString(key), args); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/ActionMessages.properties b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/ActionMessages.properties new file mode 100644 index 0000000..b51f21d --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/actions/ActionMessages.properties @@ -0,0 +1,237 @@ +################################################################################ +# Copyright (c) 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 +################################################################################ + +OpenWithMenu.label=Open Wit&h +RefactorMenu.label=Re&factor +SourceMenu.label=&Source +NavigateMenu.label=&Navigate + +BuildAction.label=&Build Project +RebuildAction.label=Rebuild Pro&ject + +SelectionConverter.codeResolveOrInput_failed=Couldn't convert text selection into a PHP element +SelectionConverter.codeResolve_failed=Couldn't convert text selection into a PHP element + +OpenAction.label=&Open +OpenAction.tooltip=Open an editor on the selected element +OpenAction.description=Open an editor on the selected element +OpenAction.declaration.label=&Open Declaration@F3 +OpenAction.select_element=&Select or enter the element to open: + +OpenAction.error.title=Open +OpenAction.error.message=Cannot open default editor. +OpenAction.error.messageArgs=Cannot open default editor on {0}. {1} +OpenAction.error.messageProblems=Problems Opening Editor +OpenAction.error.messageBadSelection=Current text selection doesn't resolve to a PHP element + +OpenSuperImplementationAction.label=Open S&uper Implementation +OpenSuperImplementationAction.tooltip=Open the Implementation in the Super Type +OpenSuperImplementationAction.description=Open the Implementation in the Super Type +OpenSuperImplementationAction.error.title=Open Super Implementation +OpenSuperImplementationAction.error.message=Opening failed. Check log for details. +OpenSuperImplementationAction.not_applicable=Operation not applicable to current text selection. Please position the cursor inside a method. +OpenSuperImplementationAction.no_super_implementation=There isn''t any super implementation for method ''{0}''. + +OpenTypeHierarchyAction.label=Open Type Hie&rarchy +OpenTypeHierarchyAction.tooltip=Open a type hierarchy on the selected element +OpenTypeHierarchyAction.description=Open a type hierarchy on the selected element +OpenTypeHierarchyAction.dialog.title=Open Type Hierarchy +OpenTypeHierarchyAction.messages.title=Can\'t create type hierarchy +OpenTypeHierarchyAction.messages.no_php_element=No PHP element selected. +OpenTypeHierarchyAction.messages.no_php_resources=Selected package fragment doesn\'t contain any PHP resource. +OpenTypeHierarchyAction.messages.no_types=Selected compilation unit doesn\'t contain a type. +OpenTypeHierarchyAction.messages.no_valid_php_element=No valid PHP element selected. + +ShowInPackageViewAction.label=Show in Pac&kage Explorer +ShowInPackageViewAction.description=Show the selected element in Package Explorer +ShowInPackageViewAction.tooltip=Show in Package Explorer +ShowInPackageViewAction.select_name=&Select or enter the element to reveal: +ShowInPackageViewAction.dialog.title=Show In Package Explorer +ShowInPackageViewAction.error.message=Internal error. Please see log for details. +ShowInPackageViewAction.not_found=Couldn\'t reveal the selected element in Package Explorer. May be the element is filtered out. + +ShowInNavigatorView.label=Show in &Navigator View +ShowInNavigatorView.dialog.title=Show in Navigator View +ShowInNavigatorView.dialog.message=Select the element to be opened in the navigator view: +ShowInNavigatorView.error.activation_failed=Unable to activate Resource Navigator +ShowInNavigatorView.error.conversion_failed=Unable to convert PHP element into a resource + +OverrideMethodsAction.label=O&verride/Implement Methods... +OverrideMethodsAction.description=Override or Implement Methods from super types. +OverrideMethodsAction.tooltip=Override/Implement Methods + +OverrideMethodsAction.error.title=Override/Implement Methods +OverrideMethodsAction.error.nothing_found=No methods to override found for this type. +OverrideMethodsAction.error.type_removed_in_editor=Input type has been removed in editor. +OverrideMethodsAction.not_applicable=Operation not applicable to current text selection. Please position the cursor inside a type. + +AddGetterSetterAction.label=Gene&rate Getter and Setter... +AddGetterSetterAction.description=Generate Getter and Setter methods for the field +AddGetterSetterAction.tooltip=Generate Getter and Setter methods for the Field + +AddGetterSetterAction.error.title=Generate Getter and Setter +AddGetterSetterAction.error.actionfailed=Generating Getter and Setter Failed. +AddGetterSetterAction.error.fieldNotExisting=The field ''{0}'' has been removed in the editor. +AddGetterSetterAction.not_applicable=Operation not applicable to current text selection. Please select a field or a type that declares some fields. +AddGetterSetterAction.read_only=The compilation unit in which the field ''{0}'' is declared is read only. + +AddGetterSetterAction.QueryDialog.title=Generate Getter and Setter +AddGetterSetterAction.SkipSetterForFinalDialog.message=Field ''{0}'' is final.\nOK to skip creation of the setter method? +AddGetterSetterAction.SkipExistingDialog.message=Method ''{0}'' already exists.\nSkip creation? +AddGetterSetterAction.SkipExistingDialog.skip.label=&Skip +AddGetterSetterAction.SkipExistingDialog.replace.label=&Replace +AddGetterSetterAction.SkipExistingDialog.skipAll.label=Skip &All + +AddUnimplementedConstructorsAction.label=Add &Constructors from Superclass +AddUnimplementedConstructorsAction.description=Evaluate and add constructors from superclass +AddUnimplementedConstructorsAction.tooltip=Add Constructors from Superclass + +AddUnimplementedConstructorsAction.error.title=Add Constructors from Superclass +AddUnimplementedConstructorsAction.error.nothing_found=No unimplemented constructors found. +AddUnimplementedConstructorsAction.error.type_removed_in_editor=Input type has been removed in editor. +AddUnimplementedConstructorsAction.not_applicable=Operation not applicable to current text selection. Please position the cursor inside a type. + +AddJavaDocStubAction.label=Add &Javadoc Comment +AddJavaDocStubAction.description=Add a Javadoc comment stub to the member element +AddJavaDocStubAction.tooltip=Add a Javadoc comment stub to the member element + +AddJavaDocStubsAction.error.dialogTitle=Add Javadoc Comment +AddJavaDocStubsAction.error.noWorkingCopy=Could not find working copy. +AddJavaDocStubsAction.error.memberNotExisting=Member has been removed in editor. +AddJavaDocStubsAction.error.actionFailed=Error while adding Javadoc comment +AddJavaDocStubsAction.not_applicable=Operation not applicable to current text selection. Please position the cursor inside a type or method. + +ExternalizeStringsAction.label= &Externalize Strings... +ExternalizeStringsAction.dialog.title= Externalize Strings +ExternalizeStringsAction.dialog.message=Couldn't open Externalize String Wizard + +FindStringsToExternalizeAction.label= &Find Strings to Externalize... +FindStringsToExternalizeAction.dialog.title= Find Strings to Externalize +FindStringsToExternalizeAction.error.message=Unexpected Exception. See log. +FindStringsToExternalizeAction.foundStrings= {0} in {1} +FindStringsToExternalizeAction.noStrings= No strings to externalize were found. +FindStringsToExternalizeAction.not_externalized= {0} ¬ externalized string(s) found. +FindStringsToExternalizeAction.button.label= &Externalize... +FindStringsToExternalizeAction.hide= &Hide compilation units with no strings to externalize +FindStringsToExternalizeAction.find_strings=Finding not externalized strings... + +OpenExternalJavadocAction.label=Open E&xternal Javadoc +OpenExternalJavadocAction.description=Opens the Javadoc of the selected element in an external browser +OpenExternalJavadocAction.tooltip=Opens the Javadoc of the selected element in an external browser +OpenExternalJavadocAction.help_not_available=Help support not available +OpenExternalJavadocAction.select_element=&Select or enter the element to open: +OpenExternalJavadocAction.libraries.no_location=The documentation location for ''{0}'' has not been configured. For elements from libraries specify the Javadoc location URL on the property page of the parent JAR (''{1}'') +OpenExternalJavadocAction.source.no_location=The documentation location for ''{0}'' has not been configured. For elements from source specify the Javadoc location URL on the property page of the parent project (''{1}'') +OpenExternalJavadocAction.no_entry=The documentation does not contain an entry for ''{0}''.\n(File ''{1}'' does not exist.) +OpenExternalJavadocAction.opening_failed=Opening Javadoc failed. See log for details +OpenExternalJavadocAction.dialog.title=Open External Javadoc +OpenExternalJavadocAction.code_resolve_failed=Couldn't convert text selection into a PHP element + +SelfEncapsulateFieldAction.label=&Self Encapsulate... +SelfEncapsulateFieldAction.dialog.title=Self Encapsulate Field +SelfEncapsulateFieldAction.dialog.unavailable=Operation unavailable on the current selection. Select a field. +SelfEncapsulateFieldAction.dialog.cannot_perform=Cannot perform refactoring. See log for more details. +SelfEncapsulateFieldAction.dialog.field_doesnot_exit=Field {0} doesn't exist in editor buffer anymore. + +OrganizeImportsAction.label=Or&ganize Imports@Ctrl+Shift+O +OrganizeImportsAction.tooltip=Evaluate All Required Imports and Replace the Current Imports +OrganizeImportsAction.description=Evaluate all required imports and replace the current imports + +OrganizeImportsAction.multi.op.description=Organizing imports... +OrganizeImportsAction.multi.error.parse={0}: Compilation unit has parse errors. No changes applied. +OrganizeImportsAction.multi.error.readonly={0}: Compilation unit is read-only. No changes applied. +OrganizeImportsAction.multi.error.unresolvable={0}: Compilation unit contains ambiguous references. User interaction required. +OrganizeImportsAction.multi.error.unexpected={0}: Unexpected error. See log for details. + +OrganizeImportsAction.selectiondialog.title=Organize Imports +OrganizeImportsAction.selectiondialog.message=&Choose type to import: + +OrganizeImportsAction.error.title=Organize Imports +OrganizeImportsAction.error.message=Unexpected error in organize imports. See log for details. + +OrganizeImportsAction.single.error.parse=Compilation unit has parse errors. No changes applied. + +OrganizeImportsAction.summary_added={0} import(s) added. +OrganizeImportsAction.summary_removed={0} import(s) removed. + +OrganizeImportsAction.multi.status.title=Organize Imports +OrganizeImportsAction.multi.status.description=Problems while organizing imports on some compilation units. See 'Details' for more information. + +OpenBrowserUtil.help_not_available=Help support not available + +MemberFilterActionGroup.hide_fields.label=Hide Fields +MemberFilterActionGroup.hide_fields.tooltip=Hide Fields +MemberFilterActionGroup.hide_fields.description=Toggles the visibility of fields + +MemberFilterActionGroup.hide_static.label=Hide Static Members +MemberFilterActionGroup.hide_static.tooltip=Hide Static Members +MemberFilterActionGroup.hide_static.description=Toggles the visibility of static members + +MemberFilterActionGroup.hide_nonpublic.label=Hide Non-Public Members +MemberFilterActionGroup.hide_nonpublic.tooltip=Hide Non-Public Members +MemberFilterActionGroup.hide_nonpublic.description=Toggles the visibility of non-public members + +NewWizardsActionGroup.new=Ne&w + +OpenProjectAction.dialog.title=Open Project +OpenProjectAction.dialog.message=Select project(s) to be opened +OpenProjectAction.error.message=Problems while opening projects +OpenProjectAction.no_php_nature.one=The following project doesn't have a PHP nature and is therefore not present in the Package Explorer: +OpenProjectAction.no_php_nature.multiple=The following projects don't have a PHP nature and are therefore not present in the Package Explorer: + +AddGetterSetterAction.dialog.title=&Select Methods to Create in Type ''{0}'': +AddGetterSetterAction.one_selected=1 method selected +AddGetterSetterAction.methods_selected={0} methods selected +AddGettSetterAction.typeContainsNoFields.message=The type contains no fields or all fields have getters/setters already. + +OpenJavaPerspectiveAction.dialog.title=Open PHP Perspective +OpenJavaPerspectiveAction.error.open_failed=Couldn\'t open PHP perspective + +OpenJavaBrowsingPerspectiveAction.dialog.title=Open PHP Browsing Perspective +OpenJavaBrowsingPerspectiveAction.error.open_failed=Couldn\'t open PHP browsing perspective + +OpenTypeInHierarchyAction.label=Open Type in Hierarchy...@Ctrl+Shift+H +OpenTypeInHierarchyAction.description=Open a type a the type hierarchy +OpenTypeInHierarchyAction.tooltip=Open a type in a type hierarchy +OpenTypeInHierarchyAction.dialogMessage=&Choose a type (? = any character, * = any string): +OpenTypeInHierarchyAction.dialogTitle=Open Type in Hierarchy + +RefreshAction.label= Re&fresh +RefreshAction.toolTip= Refresh +RefreshAction.progressMessage= Refreshing... +RefreshAction.error.title= Refresh Problems +RefreshAction.error.message= Problems occurred refreshing the selected resources. +RefreshAction.locationDeleted.title= Project location has been deleted +RefreshAction.locationDeleted.message= The location for project {0} ({1}) has been deleted.\n Delete {0} from the workspace? + +ModifyParameterAction.problem.title=Refactoring +ModifyParameterAction.problem.message=Operation not possible. + +PullUpAction.problem.title=Refactoring +PullUpAction.problem.message=Operation not possible. + +OverrideMethodQuery.groupMethodsByTypes=Group methods by &types +OverrideMethodQuery.dialog.title=Override/Implement Methods +OverrideMethodQuery.dialog.description=&Select methods to override or implement: +OverrideMethodQuery.selectioninfo.one={0} method selected. +OverrideMethodQuery.selectioninfo.more={0} methods selected. + +ActionUtil.notOnBuildPath.title=Operation Cannot be Performed +ActionUtil.notOnBuildPath.message=The resource is not on the build path of a PHP project. + +SelectAllAction.label= Select A&ll +SelectAllAction.tooltip= Select All + +AddJARToClasspathAction.label=Add to Build Path +AddJARToClasspathAction.toolTip=Add JAR to the PHP build path +AddJARToClasspathAction.progressMessage=Adding to build path... +AddJARToClasspathAction.error.title=Add To Build Path +AddJARToClasspathAction.error.message=Problems occurred while adding to the build path. diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/PHPCodeReader.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/PHPCodeReader.java new file mode 100644 index 0000000..41db8c4 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/PHPCodeReader.java @@ -0,0 +1,233 @@ +package net.sourceforge.phpdt.internal.ui.text; + +/* + * (c) Copyright IBM Corp. 2000, 2001. + * All Rights Reserved. + */ + +import java.io.IOException; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; + +import net.sourceforge.phpdt.internal.corext.phpdoc.SingleCharReader; + +/** + * Reads from a document either forwards or backwards. May be configured to + * skip comments and strings. + */ +public class PHPCodeReader extends SingleCharReader { + + /** The EOF character */ + public static final int EOF= -1; + + private boolean fSkipComments= false; + private boolean fSkipStrings= false; + private boolean fForward= false; + + private IDocument fDocument; + private int fOffset; + + private int fEnd= -1; + private int fCachedLineNumber= -1; + private int fCachedLineOffset= -1; + + + public PHPCodeReader() { + } + + /** + * Returns the offset of the last read character. Should only be called after read has been called. + */ + public int getOffset() { + return fForward ? fOffset -1 : fOffset; + } + + public void configureForwardReader(IDocument document, int offset, int length, boolean skipComments, boolean skipStrings) throws IOException { + fDocument= document; + fOffset= offset; + fSkipComments= skipComments; + fSkipStrings= skipStrings; + + fForward= true; + fEnd= Math.min(fDocument.getLength(), fOffset + length); + } + + public void configureBackwardReader(IDocument document, int offset, boolean skipComments, boolean skipStrings) throws IOException { + fDocument= document; + fOffset= offset; + fSkipComments= skipComments; + fSkipStrings= skipStrings; + + fForward= false; + try { + fCachedLineNumber= fDocument.getLineOfOffset(fOffset); + } catch (BadLocationException x) { + throw new IOException(x.getMessage()); + } + } + + /* + * @see Reader#close() + */ + public void close() throws IOException { + fDocument= null; + } + + /* + * @see SingleCharReader#read() + */ + public int read() throws IOException { + try { + return fForward ? readForwards() : readBackwards(); + } catch (BadLocationException x) { + throw new IOException(x.getMessage()); + } + } + + private void gotoCommentEnd() throws BadLocationException { + while (fOffset < fEnd) { + char current= fDocument.getChar(fOffset++); + if (current == '*') { + if (fOffset < fEnd && fDocument.getChar(fOffset) == '/') { + ++ fOffset; + return; + } + } + } + } + + private void gotoStringEnd(char delimiter) throws BadLocationException { + while (fOffset < fEnd) { + char current= fDocument.getChar(fOffset++); + if (current == '\\') { + // ignore escaped characters + ++ fOffset; + } else if (current == delimiter) { + return; + } + } + } + + private void gotoLineEnd() throws BadLocationException { + int line= fDocument.getLineOfOffset(fOffset); + fOffset= fDocument.getLineOffset(line + 1); + } + + private int readForwards() throws BadLocationException { + while (fOffset < fEnd) { + char current= fDocument.getChar(fOffset++); + + switch (current) { + case '/': + + if (fSkipComments && fOffset < fEnd) { + char next= fDocument.getChar(fOffset); + if (next == '*') { + // a comment starts, advance to the comment end + ++ fOffset; + gotoCommentEnd(); + continue; + } else if (next == '/') { + // '//'-comment starts, advance to the line end + gotoLineEnd(); + continue; + } + } + + return current; + + case '"': + case '\'': + + if (fSkipStrings) { + gotoStringEnd(current); + continue; + } + + return current; + } + + return current; + } + + return EOF; + } + + private void handleSingleLineComment() throws BadLocationException { + int line= fDocument.getLineOfOffset(fOffset); + if (line < fCachedLineNumber) { + fCachedLineNumber= line; + fCachedLineOffset= fDocument.getLineOffset(line); + int offset= fOffset; + while (fCachedLineOffset < offset) { + char current= fDocument.getChar(offset--); + if (current == '/' && fCachedLineOffset <= offset && fDocument.getChar(offset) == '/') { + fOffset= offset; + return; + } + } + } + } + + private void gotoCommentStart() throws BadLocationException { + while (0 < fOffset) { + char current= fDocument.getChar(fOffset--); + if (current == '*' && 0 <= fOffset && fDocument.getChar(fOffset) == '/') + return; + } + } + + private void gotoStringStart(char delimiter) throws BadLocationException { + while (0 < fOffset) { + char current= fDocument.getChar(fOffset); + if (current == delimiter) { + if ( !(0 <= fOffset && fDocument.getChar(fOffset -1) == '\\')) + return; + } + -- fOffset; + } + } + + private int readBackwards() throws BadLocationException { + + while (0 < fOffset) { + -- fOffset; + + handleSingleLineComment(); + + char current= fDocument.getChar(fOffset); + switch (current) { + case '/': + + if (fSkipComments && fOffset > 1) { + char next= fDocument.getChar(fOffset - 1); + if (next == '*') { + // a comment ends, advance to the comment start + fOffset -= 2; + gotoCommentStart(); + continue; + } + } + + return current; + + case '"': + case '\'': + + if (fSkipStrings) { + -- fOffset; + gotoStringStart(current); + continue; + } + + return current; + } + + return current; + } + + return EOF; + } +} + diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/PHPPairMatcher.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/PHPPairMatcher.java new file mode 100644 index 0000000..97a0edd --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/PHPPairMatcher.java @@ -0,0 +1,172 @@ +package net.sourceforge.phpdt.internal.ui.text; + +/* + * (c) Copyright IBM Corp. 2000, 2001. + * All Rights Reserved. + */ + +import java.io.IOException; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.Region; + +/** + * Helper class for match pairs of characters. + */ +public class PHPPairMatcher { + + + public static final int LEFT= 1; + public static final int RIGHT= 2; + + + protected char[] fPairs; + protected IDocument fDocument; + protected int fOffset; + + protected int fStartPos; + protected int fEndPos; + protected int fAnchor; + + protected PHPCodeReader fReader= new PHPCodeReader(); + + + public PHPPairMatcher(char[] pairs) { + fPairs= pairs; + } + + public IRegion match(IDocument document, int offset) { + + fOffset= offset; + + if (fOffset < 0) + return null; + + fDocument= document; + + if (matchPairsAt() && fStartPos != fEndPos) + return new Region(fStartPos, fEndPos - fStartPos + 1); + + return null; + } + + public int getAnchor() { + return fAnchor; + } + + public void dispose() { + fDocument= null; + if (fReader != null) { + try { + fReader.close(); + } catch (IOException x) { + // ignore + } + fReader= null; + } + } + + protected boolean matchPairsAt() { + + int i; + int pairIndex1= fPairs.length; + int pairIndex2= fPairs.length; + + fStartPos= -1; + fEndPos= -1; + + // get the chars preceding and following the start position + try { + + char prevChar= fDocument.getChar(Math.max(fOffset - 1, 0)); + char nextChar= fDocument.getChar(fOffset); + + // search for opening peer character next to the activation point + for (i= 0; i < fPairs.length; i= i + 2) { + if (nextChar == fPairs[i]) { + fStartPos= fOffset; + pairIndex1= i; + } else if (prevChar == fPairs[i]) { + fStartPos= fOffset - 1; + pairIndex1= i; + } + } + + // search for closing peer character next to the activation point + for (i= 1; i < fPairs.length; i= i + 2) { + if (prevChar == fPairs[i]) { + fEndPos= fOffset - 1; + pairIndex2= i; + } else if (nextChar == fPairs[i]) { + fEndPos= fOffset; + pairIndex2= i; + } + } + + if (fEndPos > -1) { + fAnchor= RIGHT; + fStartPos= searchForOpeningPeer(fEndPos, fPairs[pairIndex2 - 1], fPairs[pairIndex2], fDocument); + if (fStartPos > -1) + return true; + else + fEndPos= -1; + } else if (fStartPos > -1) { + fAnchor= LEFT; + fEndPos= searchForClosingPeer(fStartPos, fPairs[pairIndex1], fPairs[pairIndex1 + 1], fDocument); + if (fEndPos > -1) + return true; + else + fStartPos= -1; + } + + } catch (BadLocationException x) { + } catch (IOException x) { + } + + return false; + } + + protected int searchForClosingPeer(int offset, int openingPeer, int closingPeer, IDocument document) throws IOException { + + fReader.configureForwardReader(document, offset + 1, document.getLength(), true, true); + + int stack= 1; + int c= fReader.read(); + while (c != PHPCodeReader.EOF) { + if (c == openingPeer && c != closingPeer) + stack++; + else if (c == closingPeer) + stack--; + + if (stack == 0) + return fReader.getOffset(); + + c= fReader.read(); + } + + return -1; + } + + protected int searchForOpeningPeer(int offset, int openingPeer, int closingPeer, IDocument document) throws IOException { + + fReader.configureBackwardReader(document, offset, true, true); + + int stack= 1; + int c= fReader.read(); + while (c != PHPCodeReader.EOF) { + if (c == closingPeer && c != openingPeer) + stack++; + else if (c == openingPeer) + stack--; + + if (stack == 0) + return fReader.getOffset(); + + c= fReader.read(); + } + + return -1; + } +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/viewsupport/IViewPartInputProvider.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/viewsupport/IViewPartInputProvider.java new file mode 100644 index 0000000..54764c8 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/viewsupport/IViewPartInputProvider.java @@ -0,0 +1,15 @@ +package net.sourceforge.phpdt.internal.ui.viewsupport; + +/** + * Interface common to all view parts that provide an input. + */ +public interface IViewPartInputProvider { + + /** + * Returns the input. + * + * @return the input object + */ + public Object getViewPartInput(); + +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/actions/GenerateActionGroup.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/actions/GenerateActionGroup.java index 8f68e78..0607a3e 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/actions/GenerateActionGroup.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/actions/GenerateActionGroup.java @@ -22,6 +22,7 @@ import org.eclipse.debug.internal.ui.actions.ActionMessages; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; import org.eclipse.jface.util.Assert; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; @@ -36,6 +37,7 @@ import org.eclipse.ui.actions.AddBookmarkAction; import org.eclipse.ui.part.Page; import org.eclipse.ui.texteditor.ConvertLineDelimitersAction; import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; +import org.eclipse.ui.texteditor.IUpdate; /** * Action group that adds the source and generate actions to a part's context @@ -49,6 +51,7 @@ import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; */ public class GenerateActionGroup extends ActionGroup { + private PHPEditor fEditor; private boolean fEditorIsOwner; private IWorkbenchSite fSite; private String fGroupName= IContextMenuConstants.GROUP_SOURCE; @@ -76,6 +79,7 @@ public class GenerateActionGroup extends ActionGroup { */ public GenerateActionGroup(PHPEditor editor, String groupName) { fSite= editor.getSite(); + fEditor= editor; fEditorIsOwner= true; fGroupName= groupName; ISelectionProvider provider= fSite.getSelectionProvider(); @@ -213,14 +217,6 @@ public class GenerateActionGroup extends ActionGroup { */ public void editorStateChanged() { Assert.isTrue(fEditorIsOwner); -// fAddImport.update(); -// fExternalizeStrings.editorStateChanged(); -// fOrganizeImports.editorStateChanged(); -// fOverrideMethods.editorStateChanged(); -// fAddUnimplementedConstructors.editorStateChanged(); -// fAddJavaDocStub.editorStateChanged(); -// fSurroundWithTryCatch.editorStateChanged(); -// fAddGetterSetter.editorStateChanged(); // http://dev.eclipse.org/bugs/show_bug.cgi?id=17709 fConvertToMac.update(); @@ -255,25 +251,27 @@ public class GenerateActionGroup extends ActionGroup { } } - private IMenuManager createEditorSubMenu(IMenuManager mainMenu) { - IMenuManager result= new MenuManager(ActionMessages.getString("SourceMenu.label")); //$NON-NLS-1$ - int added= 0; -// added+= addAction(result, fOrganizeImports); -// added+= addAction(result, fAddImport); -// result.add(new Separator()); -// added+= addAction(result, fOverrideMethods); -// added+= addAction(result, fAddGetterSetter); -// added+= addAction(result, fAddUnimplementedConstructors); -// added+= addAction(result, fAddJavaDocStub); - added+= addAction(result, fAddBookmark); -// result.add(new Separator()); -// added+= addAction(result, fSurroundWithTryCatch); -// added+= addAction(result, fExternalizeStrings); - if (added == 0) - result= null; - return result; - } - + private IMenuManager createEditorSubMenu(IMenuManager mainMenu) { + IMenuManager result= new MenuManager(ActionMessages.getString("SourceMenu.label")); //$NON-NLS-1$ + int added= 0; + added+= addEditorAction(result, "Comment"); //$NON-NLS-1$ + added+= addEditorAction(result, "Uncomment"); //$NON-NLS-1$ +// result.add(new Separator()); +// added+= addAction(result, fOrganizeImports); +// added+= addAction(result, fAddImport); + result.add(new Separator()); +// added+= addAction(result, fOverrideMethods); +// added+= addAction(result, fAddGetterSetter); +// added+= addAction(result, fAddUnimplementedConstructors); +// added+= addAction(result, fAddJavaDocStub); + added+= addAction(result, fAddBookmark); +// result.add(new Separator()); +// added+= addAction(result, fSurroundWithTryCatch); +// added+= addAction(result, fExternalizeStrings); + if (added == 0) + result= null; + return result; + } /* (non-Javadoc) * Method declared in ActionGroup */ @@ -285,6 +283,7 @@ public class GenerateActionGroup extends ActionGroup { provider.removeSelectionChangedListener(listener); } } + fEditor= null; super.dispose(); } @@ -298,9 +297,9 @@ public class GenerateActionGroup extends ActionGroup { // actionBar.setGlobalActionHandler(JdtActionConstants.EXTERNALIZE_STRINGS, fExternalizeStrings); // actionBar.setGlobalActionHandler(JdtActionConstants.FIND_STRINGS_TO_EXTERNALIZE, fFindStringsToExternalize); // actionBar.setGlobalActionHandler(JdtActionConstants.ORGANIZE_IMPORTS, fOrganizeImports); -// actionBar.setGlobalActionHandler(JdtActionConstants.CONVERT_LINE_DELIMITERS_TO_WINDOWS, fConvertToWindows); -// actionBar.setGlobalActionHandler(JdtActionConstants.CONVERT_LINE_DELIMITERS_TO_UNIX, fConvertToUNIX); -// actionBar.setGlobalActionHandler(JdtActionConstants.CONVERT_LINE_DELIMITERS_TO_MAC, fConvertToMac); + actionBar.setGlobalActionHandler(PHPdtActionConstants.CONVERT_LINE_DELIMITERS_TO_WINDOWS, fConvertToWindows); + actionBar.setGlobalActionHandler(PHPdtActionConstants.CONVERT_LINE_DELIMITERS_TO_UNIX, fConvertToUNIX); + actionBar.setGlobalActionHandler(PHPdtActionConstants.CONVERT_LINE_DELIMITERS_TO_MAC, fConvertToMac); if (!fEditorIsOwner) { // editor provides its own implementation of these actions. actionBar.setGlobalActionHandler(IWorkbenchActionConstants.BOOKMARK, fAddBookmark); @@ -323,4 +322,23 @@ public class GenerateActionGroup extends ActionGroup { } return 0; } + + private int addEditorAction(IMenuManager menu, String actionID) { + if (fEditor == null) + return 0; + IAction action= fEditor.getAction(actionID); + if (action == null) + return 0; + if (action instanceof IUpdate) + ((IUpdate)action).update(); + if (action.isEnabled()) { + menu.add(action); + return 1; + } + return 0; + } + + private boolean isEditorOwner() { + return fEditor != null; + } } diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/actions/GotoMatchingBracketAction.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/actions/GotoMatchingBracketAction.java new file mode 100644 index 0000000..4bd636d --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/actions/GotoMatchingBracketAction.java @@ -0,0 +1,32 @@ +package net.sourceforge.phpdt.ui.actions; + +/* + * (c) Copyright IBM Corp. 2000, 2001. + * All Rights Reserved. + */ + +import net.sourceforge.phpdt.internal.corext.Assert; +import net.sourceforge.phpeclipse.phpeditor.PHPEditor; +import net.sourceforge.phpeclipse.phpeditor.PHPEditorMessages; + +import org.eclipse.jface.action.Action; + + +public class GotoMatchingBracketAction extends Action { + + public final static String GOTO_MATCHING_BRACKET= "GotoMatchingBracket"; //$NON-NLS-1$ + + private final PHPEditor fEditor; + + public GotoMatchingBracketAction(PHPEditor editor) { + super(PHPEditorMessages.getString("GotoMatchingBracket.label")); + Assert.isNotNull(editor); + fEditor= editor; + setEnabled(null != fEditor); + } + + public void run() { + fEditor.gotoMatchingBracket(); + } + +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/actions/PHPEditorActionDefinitionIds.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/actions/PHPEditorActionDefinitionIds.java index aab8e47..72fc67e 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/actions/PHPEditorActionDefinitionIds.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/actions/PHPEditorActionDefinitionIds.java @@ -9,4 +9,13 @@ public interface PHPEditorActionDefinitionIds { * Value: net.sourceforge.phpeclipse.phpeditor.uncomment */ public static final String UNCOMMENT = "net.sourceforge.phpdt.ui.actions.uncomment"; + + // navigate + + /** + * Action definition ID of the navigate -> open action + * (value "org.phpeclipse.phpdt.ui.edit.text.php.open.editor"). + */ + public static final String OPEN_EDITOR= "net.sourceforge.phpeclipse.ui.edit.text.php.open.editor"; //$NON-NLS-1$ + } diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/actions/PHPdtActionConstants.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/actions/PHPdtActionConstants.java index 0709883..0b9bf6b 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/actions/PHPdtActionConstants.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/ui/actions/PHPdtActionConstants.java @@ -49,5 +49,29 @@ public class PHPdtActionConstants { * phpeclipse.phpdt.ui.actions.Format"). */ public static final String FORMAT = "net.sourceforge.phpeclipse.phpeditor.Format"; //$NON-NLS-1$ + + /** + * Source menu: name of standard Convert Line Delimiters To Windows global action + * (value "org.phpeclipse.phpdt.ui.actions.ConvertLineDelimitersToWindows"). + */ + public static String CONVERT_LINE_DELIMITERS_TO_WINDOWS= "net.sourceforge.phpeclipse.ui.actions.ConvertLineDelimitersToWindows"; //$NON-NLS-1$ + + /** + * Source menu: name of standard Convert Line Delimiters To UNIX global action + * (value "org.phpeclipse.phpdt.ui.actions.ConvertLineDelimitersToUNIX"). + */ + public static String CONVERT_LINE_DELIMITERS_TO_UNIX= "net.sourceforge.phpeclipse.ui.actions.ConvertLineDelimitersToUNIX"; //$NON-NLS-1$ + + /** + * Source menu: name of standardConvert Line Delimiters ToMac global action + * (value "org.phpeclipse.phpdt.ui.actions.ConvertLineDelimitersToMac"). + */ + public static String CONVERT_LINE_DELIMITERS_TO_MAC= "net.sourceforge.phpeclipse.ui.actions.ConvertLineDelimitersToMac"; //$NON-NLS-1$ + + /** + * Navigate menu: name of standard Open global action + * (value "org.phpeclipse.phpdt.ui.actions.Open"). + */ + public static final String OPEN= "net.sourceforge.phpeclipse.ui.actions.Open"; //$NON-NLS-1$ } diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPActionContributor.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPActionContributor.java index 587bc9d..999ec19 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPActionContributor.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPActionContributor.java @@ -12,10 +12,17 @@ Contributors: Klaus Hartlage - www.eclipseproject.de **********************************************************************/ -import net.sourceforge.phpdt.ui.IContextMenuConstants; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.ResourceBundle; + +import net.sourceforge.phpdt.ui.actions.GotoMatchingBracketAction; import net.sourceforge.phpdt.ui.actions.PHPdtActionConstants; +import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.Separator; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IEditorPart; @@ -24,19 +31,22 @@ import org.eclipse.ui.actions.ActionGroup; import org.eclipse.ui.actions.RetargetAction; import org.eclipse.ui.texteditor.BasicTextEditorActionContributor; import org.eclipse.ui.texteditor.ITextEditor; +import org.eclipse.ui.texteditor.ITextEditorActionConstants; import org.eclipse.ui.texteditor.RetargetTextEditorAction; /** * Contributes interesting PHP actions to the desktop's Edit menu and the toolbar. */ -public class PHPActionContributor extends BasicTextEditorActionContributor { +public class PHPActionContributor extends BasicTextEditorActionContributor { // protected RetargetTextEditorAction fContentAssistTip; // protected TextEditorAction fTogglePresentation; protected RetargetAction fRetargetContentAssist; - + protected RetargetTextEditorAction fContentAssist; - + private RetargetTextEditorAction fGotoMatchingBracket; + private List fRetargetToolbarActions = new ArrayList(); + protected PHPParserAction parserAction; /** @@ -44,40 +54,77 @@ public class PHPActionContributor extends BasicTextEditorActionContributor { */ public PHPActionContributor() { super(); - - fRetargetContentAssist= new RetargetAction(PHPdtActionConstants.CONTENT_ASSIST, PHPEditorMessages.getString("ContentAssistProposal.label")); //$NON-NLS-1$ - fRetargetContentAssist.setActionDefinitionId(PHPEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS); - - fContentAssist= new RetargetTextEditorAction(PHPEditorMessages.getResourceBundle(), "ContentAssistProposal."); //$NON-NLS-1$ - fContentAssist.setActionDefinitionId(PHPEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS); -// fContentAssist.setImageDescriptor(JavaPluginImages.DESC_CLCL_CODE_ASSIST); -// fContentAssist.setDisabledImageDescriptor(JavaPluginImages.DESC_DLCL_CODE_ASSIST); - - + + ResourceBundle b = PHPEditorMessages.getResourceBundle(); + + fRetargetContentAssist = new RetargetAction(PHPdtActionConstants.CONTENT_ASSIST, PHPEditorMessages.getString("ContentAssistProposal.label")); //$NON-NLS-1$ + fRetargetContentAssist.setActionDefinitionId( + PHPEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS); + + fContentAssist = new RetargetTextEditorAction(b, "ContentAssistProposal."); //$NON-NLS-1$ + fContentAssist.setActionDefinitionId( + PHPEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS); + + fGotoMatchingBracket = new RetargetTextEditorAction(b, "GotoMatchingBracket."); //$NON-NLS-1$ + fGotoMatchingBracket.setActionDefinitionId( + PHPEditorActionDefinitionIds.GOTO_MATCHING_BRACKET); + + // fContentAssist.setImageDescriptor(JavaPluginImages.DESC_CLCL_CODE_ASSIST); + // fContentAssist.setDisabledImageDescriptor(JavaPluginImages.DESC_DLCL_CODE_ASSIST); + // fContentAssist = new RetargetTextEditorAction(PHPEditorMessages.getResourceBundle(), "ContentAssistProposal."); //$NON-NLS-1$ // fContentAssistTip = new RetargetTextEditorAction(PHPEditorMessages.getResourceBundle(), "ContentAssistTip."); //$NON-NLS-1$ // fTogglePresentation = new PresentationAction(); - - + parserAction = PHPParserAction.getInstance(); } /* * @see EditorActionBarContributor#contributeToMenu(IMenuManager) */ -// public void contributeToMenu(IMenuManager menu) { -// -// super.contributeToMenu(menu); -// -// IMenuManager editMenu= menu.findMenuUsingPath(IWorkbenchActionConstants.M_EDIT); -// if (editMenu != null) { -// editMenu.add(new Separator(IContextMenuConstants.GROUP_OPEN)); -// editMenu.add(new Separator(IContextMenuConstants.GROUP_GENERATE)); -// -// editMenu.appendToGroup(IContextMenuConstants.GROUP_GENERATE, fRetargetContentAssist); -// } -// } - + // public void contributeToMenu(IMenuManager menu) { + // super.contributeToMenu(menu); + // IMenuManager editMenu= menu.findMenuUsingPath(IWorkbenchActionConstants.M_EDIT); + // if (editMenu != null) { + // MenuManager structureSelection= new MenuManager(JavaEditorMessages.getString("ExpandSelectionMenu.label")); //$NON-NLS-1$ + // structureSelection.add(fStructureSelectEnclosingAction); + // structureSelection.add(fStructureSelectNextAction); + // structureSelection.add(fStructureSelectPreviousAction); + // structureSelection.add(fStructureSelectHistoryAction); + // editMenu.appendToGroup(IContextMenuConstants.GROUP_OPEN, structureSelection); + // editMenu.appendToGroup(IContextMenuConstants.GROUP_OPEN, fGotoPreviousMemberAction); + // editMenu.appendToGroup(IContextMenuConstants.GROUP_OPEN, fGotoNextMemberAction); + // editMenu.appendToGroup(IContextMenuConstants.GROUP_OPEN, fGotoMatchingBracket); + + // editMenu.appendToGroup(IContextMenuConstants.GROUP_GENERATE, fShowOutline); + // } + // } + /* + * @see EditorActionBarContributor#contributeToMenu(IMenuManager) + */ + // public void contributeToMenu(IMenuManager menu) { + // + // super.contributeToMenu(menu); + // + // IMenuManager editMenu= menu.findMenuUsingPath(IWorkbenchActionConstants.M_EDIT); + // if (editMenu != null) { + // editMenu.add(new Separator(IContextMenuConstants.GROUP_OPEN)); + // editMenu.add(new Separator(IContextMenuConstants.GROUP_GENERATE)); + // + // editMenu.appendToGroup(IContextMenuConstants.GROUP_GENERATE, fRetargetContentAssist); + // } + // } + + /* + * @see EditorActionBarContributor#contributeToToolBar(IToolBarManager) + */ + public void contributeToToolBar(IToolBarManager tbm) { + tbm.add(new Separator()); + Iterator e = fRetargetToolbarActions.iterator(); + while (e.hasNext()) + tbm.add((IAction) e.next()); + } + /* * @see IEditorActionBarContributor#init(IActionBars) */ @@ -85,14 +132,19 @@ public class PHPActionContributor extends BasicTextEditorActionContributor { super.init(bars); IMenuManager menuManager = bars.getMenuManager(); - IMenuManager editMenu = menuManager.findMenuUsingPath(IWorkbenchActionConstants.M_EDIT); + IMenuManager editMenu = + menuManager.findMenuUsingPath(IWorkbenchActionConstants.M_EDIT); if (editMenu != null) { editMenu.add(new Separator()); editMenu.add(fContentAssist); + editMenu.add(fGotoMatchingBracket); + // editMenu.add(fContentAssistTip); } - bars.setGlobalActionHandler(PHPdtActionConstants.CONTENT_ASSIST, fContentAssist); + bars.setGlobalActionHandler( + PHPdtActionConstants.CONTENT_ASSIST, + fContentAssist); // IToolBarManager toolBarManager = bars.getToolBarManager(); // if (toolBarManager != null) { // toolBarManager.add(new Separator()); @@ -109,15 +161,23 @@ public class PHPActionContributor extends BasicTextEditorActionContributor { fContentAssist.setAction(getAction(textEditor, "ContentAssistProposal")); //$NON-NLS-1$ // fContentAssistTip.setAction(getAction(editor, "ContentAssistTip")); //$NON-NLS-1$ - + fGotoMatchingBracket.setAction( + getAction(textEditor, GotoMatchingBracketAction.GOTO_MATCHING_BRACKET)); + IActionBars bars = getActionBars(); - bars.setGlobalActionHandler(PHPdtActionConstants.COMMENT, getAction(textEditor, "Comment")); - bars.setGlobalActionHandler(PHPdtActionConstants.UNCOMMENT, getAction(textEditor, "Uncomment")); - bars.setGlobalActionHandler(PHPdtActionConstants.FORMAT, getAction(textEditor, "Format")); - + bars.setGlobalActionHandler( + PHPdtActionConstants.COMMENT, + getAction(textEditor, "Comment")); + bars.setGlobalActionHandler( + PHPdtActionConstants.UNCOMMENT, + getAction(textEditor, "Uncomment")); + bars.setGlobalActionHandler( + PHPdtActionConstants.FORMAT, + getAction(textEditor, "Format")); + if (part instanceof PHPEditor) { - PHPEditor cuEditor= (PHPEditor)part; - ActionGroup group= cuEditor.getActionGroup(); + PHPEditor cuEditor = (PHPEditor) part; + ActionGroup group = cuEditor.getActionGroup(); if (group != null) group.fillActionBars(bars); } @@ -132,7 +192,7 @@ public class PHPActionContributor extends BasicTextEditorActionContributor { * @see IEditorActionBarContributor#setActiveEditor(IEditorPart) */ public void setActiveEditor(IEditorPart part) { - doSetActiveEditor(part); + doSetActiveEditor(part); } /* diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditor.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditor.java index 479f880..ed60680 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditor.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditor.java @@ -12,7 +12,9 @@ Contributors: Klaus Hartlage - www.eclipseproject.de **********************************************************************/ import net.sourceforge.phpdt.internal.ui.actions.CompositeActionGroup; +import net.sourceforge.phpdt.internal.ui.text.PHPPairMatcher; import net.sourceforge.phpdt.ui.actions.GenerateActionGroup; +import net.sourceforge.phpdt.ui.actions.GotoMatchingBracketAction; import net.sourceforge.phpeclipse.IPreferenceConstants; import net.sourceforge.phpeclipse.PHPeclipsePlugin; import net.sourceforge.phpeclipse.phpeditor.php.PHPCodeScanner; @@ -25,8 +27,13 @@ import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.preference.PreferenceConverter; +import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextOperationTarget; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.ITextViewerExtension3; +import org.eclipse.jface.text.Region; import org.eclipse.jface.text.source.AnnotationRulerColumn; import org.eclipse.jface.text.source.CompositeRuler; import org.eclipse.jface.text.source.ISourceViewer; @@ -35,6 +42,8 @@ import org.eclipse.jface.text.source.IVerticalRulerColumn; import org.eclipse.jface.text.source.LineNumberRulerColumn; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.actions.ActionContext; @@ -42,6 +51,7 @@ import org.eclipse.ui.actions.ActionGroup; import org.eclipse.ui.editors.text.TextEditor; import org.eclipse.ui.texteditor.ContentAssistAction; import org.eclipse.ui.texteditor.DefaultRangeIndicator; +import org.eclipse.ui.texteditor.IEditorStatusLine; import org.eclipse.ui.texteditor.ITextEditorActionConstants; import org.eclipse.ui.texteditor.TextOperationAction; import org.eclipse.ui.views.contentoutline.IContentOutlinePage; @@ -49,12 +59,15 @@ import org.eclipse.ui.views.contentoutline.IContentOutlinePage; * PHP specific text editor. */ public class PHPEditor extends TextEditor { +// extends StatusTextEditor implements IViewPartInputProvider { // extends TextEditor { // protected PHPActionGroup fActionGroups; /** The outline page */ private PHPContentOutlinePage fOutlinePage; private IPreferenceStore phpPrefStore; + /** The editor's bracket matcher */ + private PHPPairMatcher fBracketMatcher; /** The line number ruler column */ private LineNumberRulerColumn fLineNumberRulerColumn; @@ -67,6 +80,7 @@ public class PHPEditor extends TextEditor { */ public PHPEditor() { super(); + setEditorContextMenuId("#PHPEditorContext"); //$NON-NLS-1$ setRulerContextMenuId("#PHPRulerContext"); //$NON-NLS-1$ } // @@ -127,9 +141,6 @@ public class PHPEditor extends TextEditor { PHPEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS); setAction("ContentAssistProposal", action); //$NON-NLS-1$ - // System.out.println(action.getId()); - // System.out.println(action.getActionDefinitionId()); - setAction( "ContentAssistTip", new TextOperationAction( @@ -147,9 +158,6 @@ public class PHPEditor extends TextEditor { action.setActionDefinitionId(PHPEditorActionDefinitionIds.COMMENT); setAction("Comment", action); - // System.out.println(action.getId()); - // System.out.println(action.getActionDefinitionId()); - action = new TextOperationAction( PHPEditorMessages.getResourceBundle(), @@ -159,20 +167,20 @@ public class PHPEditor extends TextEditor { action.setActionDefinitionId(PHPEditorActionDefinitionIds.UNCOMMENT); setAction("Uncomment", action); - action = new TextOperationAction( - PHPEditorMessages.getResourceBundle(), "Format.", this, ISourceViewer.FORMAT); //$NON-NLS-1$ + action = new TextOperationAction(PHPEditorMessages.getResourceBundle(), "Format.", this, ISourceViewer.FORMAT); //$NON-NLS-1$ action.setActionDefinitionId(PHPEditorActionDefinitionIds.FORMAT); setAction("Format", action); //$NON-NLS-1$ - - // System.out.println(action.getId()); - // System.out.println(action.getActionDefinitionId()); - - // fActionGroups = new PHPActionGroup(this, ITextEditorActionConstants.GROUP_EDIT); + markAsStateDependentAction("ContentAssistProposal", true); //$NON-NLS-1$ markAsStateDependentAction("Comment", true); //$NON-NLS-1$ markAsStateDependentAction("Uncomment", true); //$NON-NLS-1$ markAsStateDependentAction("Format", true); //$NON-NLS-1$ - + + action = new GotoMatchingBracketAction(this); + action.setActionDefinitionId( + PHPEditorActionDefinitionIds.GOTO_MATCHING_BRACKET); + setAction(GotoMatchingBracketAction.GOTO_MATCHING_BRACKET, action); + fGenerateActionGroup = new GenerateActionGroup(this, ITextEditorActionConstants.GROUP_EDIT); @@ -248,18 +256,22 @@ public class PHPEditor extends TextEditor { fOutlinePage.setInput(input); } + /* + * @see org.phpeclipse.phpdt.internal.ui.viewsupport.IViewPartInputProvider#getViewPartInput() + */ +// public Object getViewPartInput() { +// return getEditorInput().getAdapter(IFile.class); +// } + /** The PHPEditor implementation of this * AbstractTextEditor method adds any * PHPEditor specific entries. */ public void editorContextMenuAboutToShow(MenuManager menu) { super.editorContextMenuAboutToShow(menu); - // addAction(menu, "ContentAssistProposal"); //$NON-NLS-1$ - // addAction(menu, "ContentAssistTip"); //$NON-NLS-1$ - addAction(menu, ITextEditorActionConstants.GROUP_EDIT, "Format"); //$NON-NLS-1$ - - // fActionGroups.fillContextMenu(menu); - + + addAction(menu, ITextEditorActionConstants.GROUP_EDIT, "Format"); //$NON-NLS-1$ + ActionContext context = new ActionContext(getSelectionProvider().getSelection()); fContextMenuGroup.setContext(context); @@ -471,7 +483,7 @@ public class PHPEditor extends TextEditor { } /* (non-Javadoc) - * Method declared on AbstractTextEditor + * Method declared on TextEditor */ protected void initializeEditor() { PHPEditorEnvironment.connect(this); @@ -504,4 +516,126 @@ public class PHPEditor extends TextEditor { } }); } + + private static IRegion getSignedSelection(ITextViewer viewer) { + + StyledText text = viewer.getTextWidget(); + int caretOffset = text.getCaretOffset(); + Point selection = text.getSelection(); + + // caret left + int offset, length; + if (caretOffset == selection.x) { + offset = selection.y; + length = selection.x - selection.y; + + // caret right + } else { + offset = selection.x; + length = selection.y - selection.x; + } + + return new Region(offset, length); + } + + private final static char[] BRACKETS = { '{', '}', '(', ')', '[', ']' }; + + private static boolean isBracket(char character) { + for (int i = 0; i != BRACKETS.length; ++i) + if (character == BRACKETS[i]) + return true; + return false; + } + + private static boolean isSurroundedByBrackets( + IDocument document, + int offset) { + if (offset == 0 || offset == document.getLength()) + return false; + + try { + return isBracket(document.getChar(offset - 1)) + && isBracket(document.getChar(offset)); + + } catch (BadLocationException e) { + return false; + } + } + /** + * Jumps to the matching bracket. + */ + public void gotoMatchingBracket() { + + if (fBracketMatcher == null) + fBracketMatcher = new PHPPairMatcher(BRACKETS); + + ISourceViewer sourceViewer = getSourceViewer(); + IDocument document = sourceViewer.getDocument(); + if (document == null) + return; + + IRegion selection = getSignedSelection(sourceViewer); + + int selectionLength = Math.abs(selection.getLength()); + if (selectionLength > 1) { + setStatusLineErrorMessage(PHPEditorMessages.getString("GotoMatchingBracket.error.invalidSelection")); //$NON-NLS-1$ + sourceViewer.getTextWidget().getDisplay().beep(); + return; + } + + // #26314 + int sourceCaretOffset = selection.getOffset() + selection.getLength(); + if (isSurroundedByBrackets(document, sourceCaretOffset)) + sourceCaretOffset -= selection.getLength(); + + IRegion region = fBracketMatcher.match(document, sourceCaretOffset); + if (region == null) { + setStatusLineErrorMessage(PHPEditorMessages.getString("GotoMatchingBracket.error.noMatchingBracket")); //$NON-NLS-1$ + sourceViewer.getTextWidget().getDisplay().beep(); + return; + } + + int offset = region.getOffset(); + int length = region.getLength(); + + if (length < 1) + return; + + int anchor = fBracketMatcher.getAnchor(); + int targetOffset = + (PHPPairMatcher.RIGHT == anchor) ? offset : offset + length - 1; + + boolean visible = false; + if (sourceViewer instanceof ITextViewerExtension3) { + ITextViewerExtension3 extension = (ITextViewerExtension3) sourceViewer; + visible = (extension.modelOffset2WidgetOffset(targetOffset) > -1); + } else { + IRegion visibleRegion = sourceViewer.getVisibleRegion(); + visible = + (targetOffset >= visibleRegion.getOffset() + && targetOffset < visibleRegion.getOffset() + visibleRegion.getLength()); + } + + if (!visible) { + setStatusLineErrorMessage(PHPEditorMessages.getString("GotoMatchingBracket.error.bracketOutsideSelectedElement")); //$NON-NLS-1$ + sourceViewer.getTextWidget().getDisplay().beep(); + return; + } + + if (selection.getLength() < 0) + targetOffset -= selection.getLength(); + + sourceViewer.setSelectedRange(targetOffset, selection.getLength()); + sourceViewer.revealRange(targetOffset, selection.getLength()); + } + /** + * Ses the given message as error message to this editor's status line. + * @param msg message to be set + */ + protected void setStatusLineErrorMessage(String msg) { + IEditorStatusLine statusLine = + (IEditorStatusLine) getAdapter(IEditorStatusLine.class); + if (statusLine != null) + statusLine.setMessage(true, msg, null); + } } diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditorActionDefinitionIds.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditorActionDefinitionIds.java index 2a236ab..fb97a56 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditorActionDefinitionIds.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditorActionDefinitionIds.java @@ -1,6 +1,14 @@ package net.sourceforge.phpeclipse.phpeditor; public interface PHPEditorActionDefinitionIds { + /** + * Action definition ID of the edit -> go to matching bracket action + * (value "org.phpeclipse.phpdt.ui.edit.text.php.goto.matching.bracket"). + * + * @since 2.1 + */ + public static final String GOTO_MATCHING_BRACKET= "net.sourceforge.phpeclipse.ui.edit.text.php.goto.matching.bracket"; //$NON-NLS-1$ + /** * Value: net.sourceforge.phpeclipse.phpeditor.comment */ diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditorMessages.properties b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditorMessages.properties index 87fb2bb..d79bc16 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditorMessages.properties +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditorMessages.properties @@ -42,3 +42,11 @@ ParserAction.label=Parse the PHP file ParserAction.tooltip=Parse the current PHP file ParserAction.image=java.gif ParserAction.description=Parse the current PHP file + + +GotoMatchingBracket.label=Go to Matching &Bracket +GotoMatchingBracket.tooltip=Go to Matching Bracket +GotoMatchingBracket.description=Go to Matching Bracket +GotoMatchingBracket.error.invalidSelection=No bracket selected +GotoMatchingBracket.error.noMatchingBracket=No matching bracket found +GotoMatchingBracket.error.bracketOutsideSelectedElement=Matching bracket is outside of selected element diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/php/PHPCompletionProcessor.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/php/PHPCompletionProcessor.java index 3bfd969..6f5c592 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/php/PHPCompletionProcessor.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/php/PHPCompletionProcessor.java @@ -367,13 +367,13 @@ public class PHPCompletionProcessor implements IContentAssistProcessor { // try { // - // JavaCodeReader reader= new JavaCodeReader(); + // PHPCodeReader reader= new PHPCodeReader(); // reader.configureBackwardReader(document, offset, true, true); // // int nestingLevel= 0; // // int curr= reader.read(); - // while (curr != JavaCodeReader.EOF) { + // while (curr != PHPCodeReader.EOF) { // // if (')' == (char) curr) // ++ nestingLevel;