X-Git-Url: http://secure.phpeclipse.com diff --git a/net.sourceforge.phpeclipse.ui/src/net/sourceforge/phpdt/internal/ui/text/JavaIndenter.java b/net.sourceforge.phpeclipse.ui/src/net/sourceforge/phpdt/internal/ui/text/JavaIndenter.java deleted file mode 100644 index 0a1c9a2..0000000 --- a/net.sourceforge.phpeclipse.ui/src/net/sourceforge/phpdt/internal/ui/text/JavaIndenter.java +++ /dev/null @@ -1,1521 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2004 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Common Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package net.sourceforge.phpdt.internal.ui.text; - -import net.sourceforge.phpdt.core.JavaCore; -import net.sourceforge.phpdt.core.formatter.DefaultCodeFormatterConstants; -import net.sourceforge.phpeclipse.ui.WebUI; -//import net.sourceforge.phpeclipse.PHPeclipsePlugin; - -import org.eclipse.core.runtime.Plugin; -//incastrix -//import org.eclipse.jface.text.Assert; -import org.eclipse.core.runtime.Assert; -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.IRegion; -import org.eclipse.jface.text.ITypedRegion; -import org.eclipse.jface.text.TextUtilities; -import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants; - -/** - * Uses the {@link net.sourceforge.phpdt.internal.ui.text.JavaHeuristicScanner}to - * get the indentation level for a certain position in a document. - * - *

- * An instance holds some internal position in the document and is therefore not - * threadsafe. - *

- * - * @since 3.0 - */ -public class JavaIndenter { - - /** The document being scanned. */ - private IDocument fDocument; - - /** The indentation accumulated by findPreviousIndenationUnit. */ - private int fIndent; - - /** - * The absolute (character-counted) indentation offset for special cases - * (method defs, array initializers) - */ - private int fAlign; - - /** The stateful scanposition for the indentation methods. */ - private int fPosition; - - /** The previous position. */ - private int fPreviousPos; - - /** The most recent token. */ - private int fToken; - - /** The line of fPosition. */ - private int fLine; - - /** - * The scanner we will use to scan the document. It has to be installed on - * the same document as the one we get. - */ - private JavaHeuristicScanner fScanner; - - /** - * Creates a new instance. - * - * @param document - * the document to scan - * @param scanner - * the {@link JavaHeuristicScanner} to be used for scanning the - * document. It must be installed on the same - * IDocument. - */ - public JavaIndenter(IDocument document, JavaHeuristicScanner scanner) { - Assert.isNotNull(document); - Assert.isNotNull(scanner); - fDocument = document; - fScanner = scanner; - } - - /** - * Computes the indentation at the reference point of position. - * - * @param offset - * the offset in the document - * @return a String which reflects the indentation at the line in which the - * reference position to offset resides, or - * null if it cannot be determined - */ -// public StringBuffer getReferenceIndentation(int offset) { -// return getReferenceIndentation(offset, false); -// } - - /** - * Computes the indentation at the reference point of position. - * - * @param offset - * the offset in the document - * @param assumeOpeningBrace - * true if an opening brace should be assumed - * @return a String which reflects the indentation at the line in which the - * reference position to offset resides, or - * null if it cannot be determined - */ - private StringBuffer getReferenceIndentation(int offset, - boolean assumeOpeningBrace) { - - int unit; - if (assumeOpeningBrace) - unit = findReferencePosition(offset, Symbols.TokenLBRACE); - else - unit = findReferencePosition(offset, peekChar(offset)); - - // if we were unable to find anything, return null - if (unit == JavaHeuristicScanner.NOT_FOUND) - return null; - - return getLeadingWhitespace(unit); - - } - - /** - * Computes the indentation at offset. - * - * @param offset - * the offset in the document - * @return a String which reflects the correct indentation for the line in - * which offset resides, or null if it cannot be - * determined - */ - public StringBuffer computeIndentation(int offset) { - return computeIndentation(offset, false); - } - - /** - * Computes the indentation at offset. - * - * @param offset - * the offset in the document - * @param assumeOpeningBrace - * true if an opening brace should be assumed - * @return a String which reflects the correct indentation for the line in - * which offset resides, or null if it cannot be - * determined - */ - public StringBuffer computeIndentation(int offset, - boolean assumeOpeningBrace) { - - StringBuffer indent = getReferenceIndentation(offset, - assumeOpeningBrace); - - // handle special alignment - if (fAlign != JavaHeuristicScanner.NOT_FOUND) { - try { - // a special case has been detected. - IRegion line = fDocument.getLineInformationOfOffset(fAlign); - int lineOffset = line.getOffset(); - return createIndent(lineOffset, fAlign); - } catch (BadLocationException e) { - return null; - } - } - - if (indent == null) - return null; - - // add additional indent - //indent.append(createIndent(fIndent)); - indent.insert(0, createIndent(fIndent)); - if (fIndent < 0) - unindent(indent); - - return indent; - } - - /** - * Returns the indentation of the line at offset as a - * StringBuffer. If the offset is not valid, the empty - * string is returned. - * - * @param offset - * the offset in the document - * @return the indentation (leading whitespace) of the line in which - * offset is located - */ - private StringBuffer getLeadingWhitespace(int offset) { - StringBuffer indent = new StringBuffer(); - try { - IRegion line = fDocument.getLineInformationOfOffset(offset); - int lineOffset = line.getOffset(); - int nonWS = fScanner.findNonWhitespaceForwardInAnyPartition( - lineOffset, lineOffset + line.getLength()); - indent.append(fDocument.get(lineOffset, nonWS - lineOffset)); - return indent; - } catch (BadLocationException e) { - return indent; - } - } - - /** - * Reduces indentation in indent by one indentation unit. - * - * @param indent - * the indentation to be modified - */ - private void unindent(StringBuffer indent) { - CharSequence oneIndent = createIndent(); - int i = indent.lastIndexOf(oneIndent.toString()); //$NON-NLS-1$ - if (i != -1) { - indent.delete(i, i + oneIndent.length()); - } - } - - /** - * Creates an indentation string of the length indent - start + 1, - * consisting of the content in fDocument in the range - * [start, indent), with every character replaced by a space except for - * tabs, which are kept as such. - * - *

- * Every run of the number of spaces that make up a tab are replaced by a - * tab character. - *

- * - * @return the indentation corresponding to the document content specified - * by start and indent - */ - private StringBuffer createIndent(int start, int indent) { - final int tabLen = prefTabLength(); - StringBuffer ret = new StringBuffer(); - try { - int spaces = 0; - while (start < indent) { - - char ch = fDocument.getChar(start); - if (ch == '\t') { - ret.append('\t'); - spaces = 0; - } else if (tabLen == -1) { - ret.append(' '); - } else { - spaces++; - if (spaces == tabLen) { - ret.append('\t'); - spaces = 0; - } - } - - start++; - } - // remainder - if (spaces == tabLen) - ret.append('\t'); - else - while (spaces-- > 0) - ret.append(' '); - - } catch (BadLocationException e) { - } - - return ret; - } - - /** - * Creates a string that represents the given number of indents (can be - * spaces or tabs..) - * - * @param indent - * the requested indentation level. - * - * @return the indentation specified by indent - */ - public StringBuffer createIndent(int indent) { - StringBuffer oneIndent = createIndent(); - - StringBuffer ret = new StringBuffer(); - while (indent-- > 0) - ret.append(oneIndent); - - return ret; - } - - /** - * Creates a string that represents one indent (can be spaces or tabs..) - * - * @return one indentation - */ - private StringBuffer createIndent() { - // get a sensible default when running without the infrastructure for - // testing - StringBuffer oneIndent = new StringBuffer(); - // JavaCore plugin= JavaCore.getJavaCore(); - WebUI plugin = WebUI.getDefault(); - if (plugin == null) { - oneIndent.append('\t'); - } else { - if (JavaCore.SPACE - .equals(JavaCore - .getOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR))) { - int tabLen = Integer - .parseInt(JavaCore - .getOption(DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE)); - for (int i = 0; i < tabLen; i++) - oneIndent.append(' '); - } else if (JavaCore.TAB - .equals(JavaCore - .getOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR))) - oneIndent.append('\t'); - else - oneIndent.append('\t'); // default - } - return oneIndent; - } - - /** - * Returns the reference position regarding to indentation for - * offset, or NOT_FOUND. This method calls - * {@link #findReferencePosition(int, int) findReferencePosition(offset, nextChar)} - * where nextChar is the next character after - * offset. - * - * @param offset - * the offset for which the reference is computed - * @return the reference statement relative to which offset - * should be indented, or {@link JavaHeuristicScanner#NOT_FOUND} - */ -// public int findReferencePosition(int offset) { -// return findReferencePosition(offset, peekChar(offset)); -// } - - /** - * Peeks the next char in the document that comes after offset - * on the same line as offset. - * - * @param offset - * the offset into document - * @return the token symbol of the next element, or TokenEOF if there is - * none - */ - private int peekChar(int offset) { - if (offset < fDocument.getLength()) { - try { - IRegion line = fDocument.getLineInformationOfOffset(offset); - int lineOffset = line.getOffset(); - int next = fScanner.nextToken(offset, lineOffset - + line.getLength()); - return next; - } catch (BadLocationException e) { - } - } - return Symbols.TokenEOF; - } - - /** - * Returns the reference position regarding to indentation for - * position, or NOT_FOUND. - * - *

- * If peekNextChar is true, the next token - * after offset is read and taken into account when computing - * the indentation. Currently, if the next token is the first token on the - * line (i.e. only preceded by whitespace), the following tokens are - * specially handled: - *

- * - * @param offset - * the offset for which the reference is computed - * @param nextToken - * the next token to assume in the document - * @return the reference statement relative to which offset - * should be indented, or {@link JavaHeuristicScanner#NOT_FOUND} - */ - public int findReferencePosition(int offset, int nextToken) { - boolean danglingElse = false; - boolean unindent = false; - boolean indent = false; - boolean matchBrace = false; - boolean matchParen = false; - boolean matchCase = false; - - // account for unindenation characters already typed in, but after - // position - // if they are on a line by themselves, the indentation gets adjusted - // accordingly - // - // also account for a dangling else - if (offset < fDocument.getLength()) { - try { - IRegion line = fDocument.getLineInformationOfOffset(offset); - int lineOffset = line.getOffset(); - int prevPos = Math.max(offset - 1, 0); - boolean isFirstTokenOnLine = fDocument.get(lineOffset, - prevPos + 1 - lineOffset).trim().length() == 0; - int prevToken = fScanner.previousToken(prevPos, - JavaHeuristicScanner.UNBOUND); - if (prevToken == Symbols.TokenEOF && nextToken == Symbols.TokenEOF) { - ITypedRegion partition = TextUtilities.getPartition(fDocument, IPHPPartitions.PHP_PARTITIONING, offset, true); - if (partition.getType().equals(IPHPPartitions.PHP_SINGLELINE_COMMENT)) { - fAlign = fScanner.getPosition(); - } else { - fAlign = JavaHeuristicScanner.NOT_FOUND; - } - return JavaHeuristicScanner.NOT_FOUND; - } - boolean bracelessBlockStart = fScanner.isBracelessBlockStart( - prevPos, JavaHeuristicScanner.UNBOUND); - - switch (nextToken) { - case Symbols.TokenEOF: - case Symbols.TokenELSE: - danglingElse = true; - break; - case Symbols.TokenCASE: - case Symbols.TokenDEFAULT: - if (isFirstTokenOnLine) - matchCase = true; - break; - case Symbols.TokenLBRACE: // for opening-brace-on-new-line - // style - // if (bracelessBlockStart && !prefIndentBracesForBlocks()) - // unindent= true; - // else if ((prevToken == Symbols.TokenCOLON || prevToken == - // Symbols.TokenEQUAL || prevToken == Symbols.TokenRBRACKET) && - // !prefIndentBracesForArrays()) - // unindent= true; - // else if (!bracelessBlockStart && - // prefIndentBracesForMethods()) - // indent= true; - // break; - if (bracelessBlockStart) - unindent = true; - else if ((prevToken == Symbols.TokenCOLON - || prevToken == Symbols.TokenEQUAL || prevToken == Symbols.TokenRBRACKET)) - unindent = true; - else if (!bracelessBlockStart) - indent = true; - break; - case Symbols.TokenRBRACE: // closing braces get unindented - if (isFirstTokenOnLine) - matchBrace = true; - break; - case Symbols.TokenRPAREN: - if (isFirstTokenOnLine) - matchParen = true; - break; - } - } catch (BadLocationException e) { - } - } else { - // assume an else could come if we are at the end of file - danglingElse = true; - } - - int ref = findReferencePosition(offset, danglingElse, matchBrace, - matchParen, matchCase); - if (unindent) - fIndent--; - if (indent) - fIndent++; - return ref; - } - - /** - * Returns the reference position regarding to indentation for - * position, or NOT_FOUND.fIndent - * will contain the relative indentation (in indentation units, not - * characters) after the call. If there is a special alignment (e.g. for a - * method declaration where parameters should be aligned), - * fAlign will contain the absolute position of the alignment - * reference in fDocument, otherwise fAlign - * is set to JavaHeuristicScanner.NOT_FOUND. - * - * @param offset - * the offset for which the reference is computed - * @param danglingElse - * whether a dangling else should be assumed at - * position - * @param matchBrace - * whether the position of the matching brace should be returned - * instead of doing code analysis - * @param matchParen - * whether the position of the matching parenthesis should be - * returned instead of doing code analysis - * @param matchCase - * whether the position of a switch statement reference should be - * returned (either an earlier case statement or the switch block - * brace) - * @return the reference statement relative to which position - * should be indented, or {@link JavaHeuristicScanner#NOT_FOUND} - */ - public int findReferencePosition(int offset, boolean danglingElse, - boolean matchBrace, boolean matchParen, boolean matchCase) { - fIndent = 0; // the indentation modification - fAlign = JavaHeuristicScanner.NOT_FOUND; - fPosition = offset; - - // forward cases - // an unindentation happens sometimes if the next token is special, - // namely on braces, parens and case labels - // align braces, but handle the case where we align with the method - // declaration start instead of - // the opening brace. - if (matchBrace) { - if (skipScope(Symbols.TokenLBRACE, Symbols.TokenRBRACE)) { - try { - // align with the opening brace that is on a line by its own - int lineOffset = fDocument.getLineOffset(fLine); - if (lineOffset <= fPosition - && fDocument - .get(lineOffset, fPosition - lineOffset) - .trim().length() == 0) - return fPosition; - } catch (BadLocationException e) { - // concurrent modification - walk default path - } - // if the opening brace is not on the start of the line, skip to - // the start - int pos = skipToStatementStart(true, true); - fIndent = 0; // indent is aligned with reference position - return pos; - } else { - // if we can't find the matching brace, the heuristic is to - // unindent - // by one against the normal position - int pos = findReferencePosition(offset, danglingElse, false, - matchParen, matchCase); - fIndent--; - return pos; - } - } - - // align parenthesis' - if (matchParen) { - if (skipScope(Symbols.TokenLPAREN, Symbols.TokenRPAREN)) - return fPosition; - else { - // if we can't find the matching paren, the heuristic is to - // unindent - // by one against the normal position - int pos = findReferencePosition(offset, danglingElse, - matchBrace, false, matchCase); - fIndent--; - return pos; - } - } - - // the only reliable way to get case labels aligned (due to many - // different styles of using braces in a block) - // is to go for another case statement, or the scope opening brace - if (matchCase) { - return matchCaseAlignment(); - } - - nextToken(); - switch (fToken) { - case Symbols.TokenRBRACE: - // skip the block and fall through - // if we can't complete the scope, reset the scan position - int pos = fPosition; - if (!skipScope()) - fPosition = pos; - case Symbols.TokenSEMICOLON: - // this is the 90% case: after a statement block - // the end of the previous statement / block previous.end - // search to the end of the statement / block before the previous; - // the token just after that is previous.start - return skipToStatementStart(danglingElse, false); - - // scope introduction: special treat who special is - case Symbols.TokenLPAREN: - case Symbols.TokenLBRACE: - case Symbols.TokenLBRACKET: - return handleScopeIntroduction(offset + 1); - - case Symbols.TokenEOF: - // trap when hitting start of document - return 0; - - case Symbols.TokenEQUAL: - // indent assignments - fIndent = prefAssignmentIndent(); - return fPosition; - - case Symbols.TokenCOLON: - // TODO handle ternary deep indentation - fIndent = prefCaseBlockIndent(); - return fPosition; - - case Symbols.TokenQUESTIONMARK: - if (prefTernaryDeepAlign()) { - setFirstElementAlignment(fPosition, offset + 1); - return fPosition; - } else { - fIndent = prefTernaryIndent(); - return fPosition; - } - - // indentation for blockless introducers: - case Symbols.TokenDO: - case Symbols.TokenWHILE: - case Symbols.TokenELSE: - fIndent = prefSimpleIndent(); - return fPosition; - case Symbols.TokenRPAREN: - int line = fLine; - if (skipScope(Symbols.TokenLPAREN, Symbols.TokenRPAREN)) { - int scope = fPosition; - nextToken(); - if (fToken == Symbols.TokenIF || fToken == Symbols.TokenWHILE - || fToken == Symbols.TokenFOR) { - fIndent = prefSimpleIndent(); - return fPosition; - } - fPosition = scope; - if (looksLikeMethodDecl()) { - return skipToStatementStart(danglingElse, false); - } - } - // restore - fPosition = offset; - fLine = line; - // else: fall through to default - - case Symbols.TokenCOMMA: - // inside a list of some type - // easy if there is already a list item before with its own - // indentation - we just align - // if not: take the start of the list ( LPAREN, LBRACE, LBRACKET ) - // and either align or - // indent by list-indent - default: - // inside whatever we don't know about: similar to the list case: - // if we are inside a continued expression, then either align with a - // previous line that has indentation - // or indent from the expression start line (either a scope - // introducer or the start of the expr). - return skipToPreviousListItemOrListStart(); - - } - } - - /** - * Skips to the start of a statement that ends at the current position. - * - * @param danglingElse - * whether to indent aligned with the last if - * @param isInBlock - * whether the current position is inside a block, which limits - * the search scope to the next scope introducer - * @return the reference offset of the start of the statement - */ - private int skipToStatementStart(boolean danglingElse, boolean isInBlock) { - while (true) { - nextToken(); - - if (isInBlock) { - switch (fToken) { - // exit on all block introducers - case Symbols.TokenIF: - case Symbols.TokenELSE: - case Symbols.TokenSYNCHRONIZED: - case Symbols.TokenCOLON: - case Symbols.TokenSTATIC: - case Symbols.TokenCATCH: - case Symbols.TokenDO: - case Symbols.TokenWHILE: - case Symbols.TokenFINALLY: - case Symbols.TokenFOR: - case Symbols.TokenTRY: - return fPosition; - - case Symbols.TokenSWITCH: - fIndent = prefCaseIndent(); - return fPosition; - } - } - - switch (fToken) { - // scope introduction through: LPAREN, LBRACE, LBRACKET - // search stop on SEMICOLON, RBRACE, COLON, EOF - // -> the next token is the start of the statement (i.e. previousPos - // when backward scanning) - case Symbols.TokenLPAREN: - case Symbols.TokenLBRACE: - case Symbols.TokenLBRACKET: - case Symbols.TokenSEMICOLON: - case Symbols.TokenEOF: - return fPreviousPos; - - case Symbols.TokenCOLON: - int pos = fPreviousPos; - if (!isConditional()) - return pos; - break; - - case Symbols.TokenRBRACE: - // RBRACE is a little tricky: it can be the end of an array - // definition, but - // usually it is the end of a previous block - pos = fPreviousPos; // store state - if (skipScope() && looksLikeArrayInitializerIntro()) - continue; // it's an array - else - return pos; // it's not - do as with all the above - - // scopes: skip them - case Symbols.TokenRPAREN: - case Symbols.TokenRBRACKET: - pos = fPreviousPos; - if (skipScope()) - break; - else - return pos; - - // IF / ELSE: align the position after the conditional block - // with the if - // so we are ready for an else, except if danglingElse is false - // in order for this to work, we must skip an else to its if - case Symbols.TokenIF: - if (danglingElse) - return fPosition; - else - break; - case Symbols.TokenELSE: - // skip behind the next if, as we have that one covered - pos = fPosition; - if (skipNextIF()) - break; - else - return pos; - - case Symbols.TokenDO: - // align the WHILE position with its do - return fPosition; - - case Symbols.TokenWHILE: - // this one is tricky: while can be the start of a while loop - // or the end of a do - while - pos = fPosition; - if (hasMatchingDo()) { - // continue searching from the DO on - break; - } else { - // continue searching from the WHILE on - fPosition = pos; - break; - } - default: - // keep searching - - } - - } - } - - /** - * Returns true if the colon at the current position is part of a - * conditional (ternary) expression, false otherwise. - * - * @return true if the colon at the current position is part of a - * conditional - */ - private boolean isConditional() { - while (true) { - nextToken(); - switch (fToken) { - - // search for case, otherwise return true - case Symbols.TokenIDENT: - continue; - case Symbols.TokenCASE: - return false; - - default: - return true; - } - } - } - - /** - * Returns as a reference any previous switch labels (case - * or default) or the offset of the brace that scopes the - * switch statement. Sets fIndent to - * prefCaseIndent upon a match. - * - * @return the reference offset for a switch label - */ - private int matchCaseAlignment() { - while (true) { - nextToken(); - switch (fToken) { - // invalid cases: another case label or an LBRACE must come before a - // case - // -> bail out with the current position - case Symbols.TokenLPAREN: - case Symbols.TokenLBRACKET: - case Symbols.TokenEOF: - return fPosition; - case Symbols.TokenLBRACE: - // opening brace of switch statement - fIndent = 1; //prefCaseIndent() is for Java - return fPosition; - case Symbols.TokenCASE: - case Symbols.TokenDEFAULT: - // align with previous label - fIndent = 0; - return fPosition; - // scopes: skip them - case Symbols.TokenRPAREN: - case Symbols.TokenRBRACKET: - case Symbols.TokenRBRACE: - skipScope(); - break; - default: - // keep searching - continue; - } - } - } - - /** - * Returns the reference position for a list element. The algorithm tries to - * match any previous indentation on the same list. If there is none, the - * reference position returned is determined depending on the type of list: - * The indentation will either match the list scope introducer (e.g. for - * method declarations), so called deep indents, or simply increase the - * indentation by a number of standard indents. See also - * {@link #handleScopeIntroduction(int)}. - * - * @return the reference position for a list item: either a previous list - * item that has its own indentation, or the list introduction - * start. - */ - private int skipToPreviousListItemOrListStart() { - int startLine = fLine; - int startPosition = fPosition; - while (true) { - nextToken(); - - // if any line item comes with its own indentation, adapt to it - if (fLine < startLine) { - try { - int lineOffset = fDocument.getLineOffset(startLine); - int bound = Math.min(fDocument.getLength(), - startPosition + 1); - fAlign = fScanner.findNonWhitespaceForwardInAnyPartition( - lineOffset, bound); - } catch (BadLocationException e) { - // ignore and return just the position - } - return startPosition; - } - - switch (fToken) { - // scopes: skip them - case Symbols.TokenRPAREN: - case Symbols.TokenRBRACKET: - case Symbols.TokenRBRACE: - skipScope(); - break; - - // scope introduction: special treat who special is - case Symbols.TokenLPAREN: - case Symbols.TokenLBRACE: - case Symbols.TokenLBRACKET: - return handleScopeIntroduction(startPosition + 1); - - case Symbols.TokenSEMICOLON: - return fPosition; - case Symbols.TokenQUESTIONMARK: - if (prefTernaryDeepAlign()) { - setFirstElementAlignment(fPosition - 1, fPosition + 1); - } else { - fIndent = prefTernaryIndent(); - } - return fPosition; - case Symbols.TokenEOF: - return 0; - - case Symbols.TokenEQUAL: - // indent assignments - fIndent= prefAssignmentIndent(); - return fPosition; - } - } - } - - /** - * Skips a scope and positions the cursor (fPosition) on - * the token that opens the scope. Returns true if a matching - * peer could be found, false otherwise. The current token - * when calling must be one out of Symbols.TokenRPAREN, - * Symbols.TokenRBRACE, and - * Symbols.TokenRBRACKET. - * - * @return true if a matching peer was found, - * false otherwise - */ - private boolean skipScope() { - switch (fToken) { - case Symbols.TokenRPAREN: - return skipScope(Symbols.TokenLPAREN, Symbols.TokenRPAREN); - case Symbols.TokenRBRACKET: - return skipScope(Symbols.TokenLBRACKET, Symbols.TokenRBRACKET); - case Symbols.TokenRBRACE: - return skipScope(Symbols.TokenLBRACE, Symbols.TokenRBRACE); - default: - Assert.isTrue(false); - return false; - } - } - - /** - * Handles the introduction of a new scope. The current token must be one - * out of Symbols.TokenLPAREN, - * Symbols.TokenLBRACE, and - * Symbols.TokenLBRACKET. Returns as the reference position - * either the token introducing the scope or - if available - the first java - * token after that. - * - *

- * Depending on the type of scope introduction, the indentation will align - * (deep indenting) with the reference position (fAlign will - * be set to the reference position) or fIndent will be set - * to the number of indentation units. - *

- * - * @param bound - * the bound for the search for the first token after the scope - * introduction. - * @return - */ - private int handleScopeIntroduction(int bound) { - switch (fToken) { - // scope introduction: special treat who special is - case Symbols.TokenLPAREN: - int pos = fPosition; // store - - // special: method declaration deep indentation - if (looksLikeMethodDecl()) { - if (prefMethodDeclDeepIndent()) - return setFirstElementAlignment(pos, bound); - else { - fIndent = prefMethodDeclIndent(); - return pos; - } - } else { - fPosition = pos; - if (looksLikeMethodCall()) { - if (prefMethodCallDeepIndent()) - return setFirstElementAlignment(pos, bound); - else { - fIndent = prefMethodCallIndent(); - return pos; - } - } else if (prefParenthesisDeepIndent()) - return setFirstElementAlignment(pos, bound); - } - - // normal: return the parenthesis as reference - fIndent = prefParenthesisIndent(); - return pos; - - case Symbols.TokenLBRACE: - pos = fPosition; // store - - // special: array initializer - if (looksLikeArrayInitializerIntro()) - if (prefArrayDeepIndent()) - return setFirstElementAlignment(pos, bound); - else - fIndent = prefArrayIndent(); - else - fIndent = prefBlockIndent(); - - // normal: skip to the statement start before the scope introducer - // opening braces are often on differently ending indents than e.g. - // a method definition - fPosition = pos; // restore - return skipToStatementStart(true, true); // set to true to match - // the first if - - case Symbols.TokenLBRACKET: - pos = fPosition; // store - - // special: method declaration deep indentation - if (prefArrayDimensionsDeepIndent()) { - return setFirstElementAlignment(pos, bound); - } - - // normal: return the bracket as reference - fIndent = prefBracketIndent(); - return pos; // restore - - default: - Assert.isTrue(false); - return -1; // dummy - } - } - - /** - * Sets the deep indent offset (fAlign) to either the - * offset right after scopeIntroducerOffset or - if available - - * the first Java token after scopeIntroducerOffset, but - * before bound. - * - * @param scopeIntroducerOffset - * the offset of the scope introducer - * @param bound - * the bound for the search for another element - * @return the reference position - */ - private int setFirstElementAlignment(int scopeIntroducerOffset, int bound) { - int firstPossible = scopeIntroducerOffset + 1; // align with the first - // position after the - // scope intro - fAlign = fScanner.findNonWhitespaceForwardInAnyPartition(firstPossible, - bound); - if (fAlign == JavaHeuristicScanner.NOT_FOUND) - fAlign = firstPossible; - return fAlign; - } - - /** - * Returns true if the next token received after calling - * nextToken is either an equal sign or an array designator - * ('[]'). - * - * @return true if the next elements look like the start of - * an array definition - */ - private boolean looksLikeArrayInitializerIntro() { - nextToken(); - if (fToken == Symbols.TokenEQUAL || skipBrackets()) { - return true; - } - return false; - } - - /** - * Skips over the next if keyword. The current token when - * calling this method must be an else keyword. Returns - * true if a matching if could be found, - * false otherwise. The cursor (fPosition) - * is set to the offset of the if token. - * - * @return true if a matching if token was - * found, false otherwise - */ - private boolean skipNextIF() { - Assert.isTrue(fToken == Symbols.TokenELSE); - - while (true) { - nextToken(); - switch (fToken) { - // scopes: skip them - case Symbols.TokenRPAREN: - case Symbols.TokenRBRACKET: - case Symbols.TokenRBRACE: - skipScope(); - break; - - case Symbols.TokenIF: - // found it, return - return true; - case Symbols.TokenELSE: - // recursively skip else-if blocks - skipNextIF(); - break; - - // shortcut scope starts - case Symbols.TokenLPAREN: - case Symbols.TokenLBRACE: - case Symbols.TokenLBRACKET: - case Symbols.TokenEOF: - return false; - } - } - } - - /** - * while(condition); is ambiguous when parsed backwardly, as it is a valid - * statement by its own, so we have to check whether there is a matching do. - * A do can either be separated from the while by a block, or - * by a single statement, which limits our search distance. - * - * @return true if the while currently in - * fToken has a matching do. - */ - private boolean hasMatchingDo() { - Assert.isTrue(fToken == Symbols.TokenWHILE); - nextToken(); - switch (fToken) { - case Symbols.TokenRBRACE: - skipScope(); // and fall thru - case Symbols.TokenSEMICOLON: - skipToStatementStart(false, false); - return fToken == Symbols.TokenDO; - } - return false; - } - - /** - * Skips brackets if the current token is a RBRACKET. There can be nothing - * but whitespace in between, this is only to be used for [] - * elements. - * - * @return true if a [] could be scanned, the - * current token is left at the LBRACKET. - */ - private boolean skipBrackets() { - if (fToken == Symbols.TokenRBRACKET) { - nextToken(); - if (fToken == Symbols.TokenLBRACKET) { - return true; - } - } - return false; - } - - /** - * Reads the next token in backward direction from the heuristic scanner and - * sets the fields fToken, fPreviousPosition and - * fPosition accordingly. - */ - private void nextToken() { - nextToken(fPosition); - } - - /** - * Reads the next token in backward direction of start from - * the heuristic scanner and sets the fields - * fToken, fPreviousPosition and fPosition - * accordingly. - */ - private void nextToken(int start) { - fToken = fScanner - .previousToken(start - 1, JavaHeuristicScanner.UNBOUND); - fPreviousPos = start; - fPosition = fScanner.getPosition() + 1; - try { - fLine = fDocument.getLineOfOffset(fPosition); - } catch (BadLocationException e) { - fLine = -1; - } - } - - /** - * Returns true if the current tokens look like a method - * declaration header (i.e. only the return type and method name). The - * heuristic calls nextToken and expects an identifier - * (method name) and a type declaration (an identifier with optional - * brackets) which also covers the visibility modifier of constructors; it - * does not recognize package visible constructors. - * - * @return true if the current position looks like a method - * declaration header. - */ - private boolean looksLikeMethodDecl() { - /* - * TODO This heuristic does not recognize package private constructors - * since those do have neither type nor visibility keywords. One option - * would be to go over the parameter list, but that might be empty as - * well - hard to do without an AST... - */ - - nextToken(); - if (fToken == Symbols.TokenIDENT) { // method name - do - nextToken(); - while (skipBrackets()); // optional brackets for array valued return - // types - return fToken == Symbols.TokenIDENT; // type name - - } - return false; - } - - /** - * Returns true if the current tokens look like a method call - * header (i.e. an identifier as opposed to a keyword taking parenthesized - * parameters such as if). - *

- * The heuristic calls nextToken and expects an identifier - * (method name). - * - * @return true if the current position looks like a method - * call header. - */ - private boolean looksLikeMethodCall() { - nextToken(); - return fToken == Symbols.TokenIDENT; // method name - } - - /** - * Scans tokens for the matching opening peer. The internal cursor (fPosition) - * is set to the offset of the opening peer if found. - * - * @return true if a matching token was found, - * false otherwise - */ - private boolean skipScope(int openToken, int closeToken) { - - int depth = 1; - - while (true) { - nextToken(); - - if (fToken == closeToken) { - depth++; - } else if (fToken == openToken) { - depth--; - if (depth == 0) - return true; - } else if (fToken == Symbols.TokenEOF) { - return false; - } - } - } - - // TODO adjust once there are per-project settings - - private int prefTabLength() { - int tabLen; - // JavaCore core= JavaCore.getJavaCore(); - WebUI plugin = WebUI.getDefault(); - // if (core != null && plugin != null) - if (plugin != null) - if (JavaCore.SPACE - .equals(JavaCore - .getOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR))) - // if the formatter uses chars to mark indentation, then don't - // substitute any chars - tabLen = -1; // results in no tabs being substituted for - // space runs - else - // if the formatter uses tabs to mark indentations, use the - // visual setting from the editor - // to get nicely aligned indentations - tabLen = plugin - .getPreferenceStore() - .getInt( - AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH); - else - tabLen = 4; // sensible default for testing - - return tabLen; - } - - private boolean prefArrayDimensionsDeepIndent() { - return true; // sensible default - } - - private int prefArrayIndent() { - Plugin plugin = JavaCore.getPlugin(); - if (plugin != null) { - String option = JavaCore - .getOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_EXPRESSIONS_IN_ARRAY_INITIALIZER); - try { - if (DefaultCodeFormatterConstants.getIndentStyle(option) == DefaultCodeFormatterConstants.INDENT_BY_ONE) - return 1; - } catch (IllegalArgumentException e) { - // ignore and return default - } - } - - return prefContinuationIndent(); // default - } - - private boolean prefArrayDeepIndent() { - Plugin plugin = JavaCore.getPlugin(); - if (plugin != null) { - String option = JavaCore - .getOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_EXPRESSIONS_IN_ARRAY_INITIALIZER); - try { - return DefaultCodeFormatterConstants.getIndentStyle(option) == DefaultCodeFormatterConstants.INDENT_ON_COLUMN; - } catch (IllegalArgumentException e) { - // ignore and return default - } - } - - return true; - } - - private boolean prefTernaryDeepAlign() { - Plugin plugin = JavaCore.getPlugin(); - if (plugin != null) { - String option = JavaCore - .getOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_CONDITIONAL_EXPRESSION); - try { - return DefaultCodeFormatterConstants.getIndentStyle(option) == DefaultCodeFormatterConstants.INDENT_ON_COLUMN; - } catch (IllegalArgumentException e) { - // ignore and return default - } - } - return false; - } - - private int prefTernaryIndent() { - Plugin plugin = JavaCore.getPlugin(); - if (plugin != null) { - String option = JavaCore - .getOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_CONDITIONAL_EXPRESSION); - try { - if (DefaultCodeFormatterConstants.getIndentStyle(option) == DefaultCodeFormatterConstants.INDENT_BY_ONE) - return 1; - else - return prefContinuationIndent(); - } catch (IllegalArgumentException e) { - // ignore and return default - } - } - - return prefContinuationIndent(); - } - - private int prefCaseIndent() { - Plugin plugin = JavaCore.getPlugin(); - if (plugin != null) { - if (DefaultCodeFormatterConstants.TRUE - .equals(JavaCore - .getOption(DefaultCodeFormatterConstants.FORMATTER_INDENT_SWITCHSTATEMENTS_COMPARE_TO_SWITCH))) - return prefBlockIndent(); - else - return 0; - } - - return 0; // sun standard - } - - private int prefAssignmentIndent() { - return prefBlockIndent(); - } - - private int prefCaseBlockIndent() { - if (true) - return prefBlockIndent(); - - Plugin plugin = JavaCore.getPlugin(); - if (plugin != null) { - if (DefaultCodeFormatterConstants.TRUE - .equals(JavaCore - .getOption(DefaultCodeFormatterConstants.FORMATTER_INDENT_SWITCHSTATEMENTS_COMPARE_TO_CASES))) - return prefBlockIndent(); - else - return 0; - } - return prefBlockIndent(); // sun standard - } - - private int prefSimpleIndent() { - return prefBlockIndent(); - } - - private int prefBracketIndent() { - return prefBlockIndent(); - } - - private boolean prefMethodDeclDeepIndent() { - Plugin plugin = JavaCore.getPlugin(); - if (plugin != null) { - String option = JavaCore - .getOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_PARAMETERS_IN_METHOD_DECLARATION); - try { - return DefaultCodeFormatterConstants.getIndentStyle(option) == DefaultCodeFormatterConstants.INDENT_ON_COLUMN; - } catch (IllegalArgumentException e) { - // ignore and return default - } - } - - return true; - } - - private int prefMethodDeclIndent() { - Plugin plugin = JavaCore.getPlugin(); - if (plugin != null) { - String option = JavaCore - .getOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_PARAMETERS_IN_METHOD_DECLARATION); - try { - if (DefaultCodeFormatterConstants.getIndentStyle(option) == DefaultCodeFormatterConstants.INDENT_BY_ONE) - return 1; - else - return prefContinuationIndent(); - } catch (IllegalArgumentException e) { - // ignore and return default - } - } - return 1; - } - - private boolean prefMethodCallDeepIndent() { - Plugin plugin = JavaCore.getPlugin(); - if (plugin != null) { - String option = JavaCore - .getOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ARGUMENTS_IN_METHOD_INVOCATION); - try { - return DefaultCodeFormatterConstants.getIndentStyle(option) == DefaultCodeFormatterConstants.INDENT_ON_COLUMN; - } catch (IllegalArgumentException e) { - // ignore and return default - } - } - return false; // sensible default - } - - private int prefMethodCallIndent() { - Plugin plugin = JavaCore.getPlugin(); - if (plugin != null) { - String option = JavaCore - .getOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ARGUMENTS_IN_METHOD_INVOCATION); - try { - if (DefaultCodeFormatterConstants.getIndentStyle(option) == DefaultCodeFormatterConstants.INDENT_BY_ONE) - return 1; - else - return prefContinuationIndent(); - } catch (IllegalArgumentException e) { - // ignore and return default - } - } - - return 1; // sensible default - } - - private boolean prefParenthesisDeepIndent() { - - if (true) // don't do parenthesis deep indentation - return false; - - Plugin plugin = JavaCore.getPlugin(); - if (plugin != null) { - String option = JavaCore - .getOption(DefaultCodeFormatterConstants.FORMATTER_CONTINUATION_INDENTATION); - try { - return DefaultCodeFormatterConstants.getIndentStyle(option) == DefaultCodeFormatterConstants.INDENT_ON_COLUMN; - } catch (IllegalArgumentException e) { - // ignore and return default - } - } - - return false; // sensible default - } - - private int prefParenthesisIndent() { - return prefContinuationIndent(); - } - - private int prefBlockIndent() { - return 1; // sensible default - } - -// private boolean prefIndentBracesForBlocks() { -// Plugin plugin = JavaCore.getPlugin(); -// if (plugin != null) { -// String option = JavaCore -// .getOption(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_BLOCK); -// return option -// .equals(DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED); -// } -// -// return false; // sensible default -// } - -// private boolean prefIndentBracesForArrays() { -// Plugin plugin = JavaCore.getPlugin(); -// if (plugin != null) { -// String option = JavaCore -// .getOption(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_ARRAY_INITIALIZER); -// return option -// .equals(DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED); -// } -// -// return false; // sensible default -// } - -// private boolean prefIndentBracesForMethods() { -// Plugin plugin = JavaCore.getPlugin(); -// if (plugin != null) { -// String option = JavaCore -// .getOption(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_METHOD_DECLARATION); -// return option -// .equals(DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED); -// } -// -// return false; // sensible default -// } - - private int prefContinuationIndent() { - Plugin plugin = JavaCore.getPlugin(); - if (plugin != null) { - String option = JavaCore - .getOption(DefaultCodeFormatterConstants.FORMATTER_CONTINUATION_INDENTATION); - try { - return Integer.parseInt(option); - } catch (NumberFormatException e) { - // ignore and return default - } - } - - return 2; // sensible default - } - -}