cdt/cdt_6_0_x/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CIndenter.java
changeset 37 c2bce6dd59e7
child 138 e0657161c0cc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cdt/cdt_6_0_x/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CIndenter.java	Wed Jul 29 14:30:25 2009 -0500
@@ -0,0 +1,2169 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *     Sergey Prigogin (Google)
+ *     Anton Leherbauer (Wind River Systems)
+ *******************************************************************************/
+package org.eclipse.cdt.internal.ui.text;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.preferences.IPreferencesService;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.formatter.DefaultCodeFormatterConstants;
+import org.eclipse.cdt.core.model.ICProject;
+
+import org.eclipse.cdt.internal.corext.util.CodeFormatterUtil;
+
+/**
+ * Uses the {@link org.eclipse.cdt.internal.ui.text.CHeuristicScanner} to
+ * get the indentation level for a certain position in a document.
+ *
+ * <p>
+ * An instance holds some internal position in the document and is therefore
+ * not thread-safe.
+ * </p>
+ */
+public final class CIndenter {
+	
+	/**
+	 * The CDT Core preferences.
+	 */
+	private final class CorePrefs {
+		final boolean prefUseTabs;
+		final int prefTabSize;
+		final int prefIndentationSize;
+		final boolean prefArrayDimensionsDeepIndent;
+		final int prefArrayIndent;
+		final boolean prefArrayDeepIndent;
+		final boolean prefTernaryDeepAlign;
+		final int prefTernaryIndent;
+		final int prefCaseIndent;
+		final int prefCaseBlockIndent;
+		final int prefAssignmentIndent;
+		final int prefSimpleIndent;
+		final int prefBracketIndent;
+		final boolean prefMethodDeclDeepIndent;
+		final boolean prefMethodDeclFirstParameterDeepIndent;
+		final int prefMethodDeclIndent;
+		final boolean prefMethodCallDeepIndent;
+		final boolean prefMethodCallFirstParameterDeepIndent;
+		final int prefMethodCallIndent;
+		final boolean prefParenthesisDeepIndent;
+		final int prefParenthesisIndent;
+		final int prefBlockIndent;
+		final int prefMethodBodyIndent;
+		final int prefTypeIndent;
+		final int prefAccessSpecifierIndent;
+		final int prefAccessSpecifierExtraSpaces;
+		final int prefNamespaceBodyIndent;
+		final boolean prefIndentBracesForBlocks;
+		final boolean prefIndentBracesForArrays;
+		final boolean prefIndentBracesForMethods;
+		final boolean prefIndentBracesForTypes;
+		final int prefContinuationIndent;
+		final boolean prefHasTemplates;
+		final String prefTabChar;
+		
+		private final ICProject fProject;
+
+		/**
+		 * Returns the possibly project-specific core preference defined under <code>key</code>.
+		 *
+		 * @param key the key of the preference
+		 * @return the value of the preference
+		 */
+		private String getCoreFormatterOption(String key) {
+			if (fProject == null)
+				return CCorePlugin.getOption(key);
+			return fProject.getOption(key, true);
+		}
+		
+		CorePrefs(ICProject project) {
+			fProject= project;
+			prefUseTabs= prefUseTabs();
+			prefTabSize= prefTabSize();
+			prefIndentationSize= prefIndentationSize();
+			prefArrayDimensionsDeepIndent= prefArrayDimensionsDeepIndent();
+			prefContinuationIndent= prefContinuationIndent();
+			prefBlockIndent= prefBlockIndent();
+			prefArrayIndent= prefArrayIndent();
+			prefArrayDeepIndent= prefArrayDeepIndent();
+			prefTernaryDeepAlign= prefTernaryDeepAlign();
+			prefTernaryIndent= prefTernaryIndent();
+			prefCaseIndent= prefCaseIndent();
+			prefCaseBlockIndent= prefCaseBlockIndent();
+			prefAssignmentIndent= prefAssignmentIndent();
+			prefIndentBracesForBlocks= prefIndentBracesForBlocks();
+			prefSimpleIndent= prefSimpleIndent();
+			prefBracketIndent= prefBracketIndent();
+			prefMethodDeclDeepIndent= prefMethodDeclDeepIndent();
+			prefMethodDeclFirstParameterDeepIndent= prefMethodDeclFirstParameterDeepIndent();
+			prefMethodDeclIndent= prefMethodDeclIndent();
+			prefMethodCallDeepIndent= prefMethodCallDeepIndent();
+			prefMethodCallFirstParameterDeepIndent= prefMethodCallFirstParameterDeepIndent();
+			prefMethodCallIndent= prefMethodCallIndent();
+			prefParenthesisDeepIndent= prefParenthesisDeepIndent();
+			prefParenthesisIndent= prefParenthesisIndent();
+			prefMethodBodyIndent= prefMethodBodyIndent();
+			prefTypeIndent= prefTypeIndent();
+			prefAccessSpecifierIndent= prefAccessSpecifierIndent();
+			prefAccessSpecifierExtraSpaces= prefAccessSpecifierExtraSpaces();
+			prefNamespaceBodyIndent= prefNamespaceBodyIndent();
+			prefIndentBracesForArrays= prefIndentBracesForArrays();
+			prefIndentBracesForMethods= prefIndentBracesForMethods();
+			prefIndentBracesForTypes= prefIndentBracesForTypes();
+			prefHasTemplates= hasTemplates();
+			prefTabChar= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR);
+		}
+		
+		private boolean prefUseTabs() {
+			return !CCorePlugin.SPACE.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR));
+		}
+
+		private int prefTabSize() {
+			return CodeFormatterUtil.getTabWidth(fProject);
+		}
+
+		private int prefIndentationSize() {
+			return CodeFormatterUtil.getIndentWidth(fProject);
+		}
+
+		private boolean prefArrayDimensionsDeepIndent() {
+			return true; // sensible default, no formatter setting
+		}
+
+		private int prefArrayIndent() {
+			String option= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_EXPRESSIONS_IN_INITIALIZER_LIST);
+			try {
+				if (DefaultCodeFormatterConstants.getIndentStyle(option) == DefaultCodeFormatterConstants.INDENT_BY_ONE)
+					return 1;
+			} catch (IllegalArgumentException e) {
+				// ignore and return default
+			}
+
+			return prefContinuationIndent(); // default
+		}
+
+		private boolean prefArrayDeepIndent() {
+			String option= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_EXPRESSIONS_IN_INITIALIZER_LIST);
+			try {
+				return DefaultCodeFormatterConstants.getIndentStyle(option) == DefaultCodeFormatterConstants.INDENT_ON_COLUMN;
+			} catch (IllegalArgumentException e) {
+				// ignore and return default
+			}
+
+			return true;
+		}
+
+		private boolean prefTernaryDeepAlign() {
+			String option= getCoreFormatterOption(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() {
+			String option= getCoreFormatterOption(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() {
+			if (DefaultCodeFormatterConstants.TRUE.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_INDENT_SWITCHSTATEMENTS_COMPARE_TO_SWITCH)))
+				return 1;
+			else
+				return 0;
+		}
+
+		private int prefCaseBlockIndent() {
+			if (DefaultCodeFormatterConstants.TRUE.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_INDENT_SWITCHSTATEMENTS_COMPARE_TO_CASES)))
+				return 1;
+			else
+				return 0;
+		}
+
+		private int prefAssignmentIndent() {
+			return prefContinuationIndent();
+		}
+
+		private int prefSimpleIndent() {
+			if (prefIndentBracesForBlocks() && prefBlockIndent() == 0)
+				return 1;
+			else
+				return prefBlockIndent();
+		}
+
+		private int prefBracketIndent() {
+			return prefBlockIndent();
+		}
+
+		private boolean prefMethodDeclDeepIndent() {
+			String option= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_PARAMETERS_IN_METHOD_DECLARATION);
+			try {
+				int indentStyle = DefaultCodeFormatterConstants.getIndentStyle(option);
+				return indentStyle == DefaultCodeFormatterConstants.INDENT_ON_COLUMN;
+			} catch (IllegalArgumentException e) {
+				// ignore and return default
+			}
+
+			return false;
+		}
+
+		private boolean prefMethodDeclFirstParameterDeepIndent() {
+			String option= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_PARAMETERS_IN_METHOD_DECLARATION);
+			try {
+				int indentStyle = DefaultCodeFormatterConstants.getIndentStyle(option);
+				int wrappingStyle = DefaultCodeFormatterConstants.getWrappingStyle(option);
+				return indentStyle == DefaultCodeFormatterConstants.INDENT_ON_COLUMN &&
+				    	(wrappingStyle == DefaultCodeFormatterConstants.WRAP_COMPACT_FIRST_BREAK ||
+				    	wrappingStyle == DefaultCodeFormatterConstants.WRAP_ONE_PER_LINE);
+			} catch (IllegalArgumentException e) {
+				// ignore and return default
+			}
+
+			return false;
+		}
+
+		private int prefMethodDeclIndent() {
+			String option= getCoreFormatterOption(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() {
+			String option= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ARGUMENTS_IN_METHOD_INVOCATION);
+			try {
+				int indentStyle = DefaultCodeFormatterConstants.getIndentStyle(option);
+				return indentStyle == DefaultCodeFormatterConstants.INDENT_ON_COLUMN;
+			} catch (IllegalArgumentException e) {
+				// ignore and return default
+			}
+			return false; // sensible default
+		}
+
+		private boolean prefMethodCallFirstParameterDeepIndent() {
+			String option= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ARGUMENTS_IN_METHOD_INVOCATION);
+			try {
+				int indentStyle = DefaultCodeFormatterConstants.getIndentStyle(option);
+				int wrappingStyle = DefaultCodeFormatterConstants.getWrappingStyle(option);
+				return indentStyle == DefaultCodeFormatterConstants.INDENT_ON_COLUMN &&
+				    	(wrappingStyle == DefaultCodeFormatterConstants.WRAP_COMPACT_FIRST_BREAK ||
+				        wrappingStyle == DefaultCodeFormatterConstants.WRAP_ONE_PER_LINE);
+			} catch (IllegalArgumentException e) {
+				// ignore and return default
+			}
+			return false; // sensible default
+		}
+
+		private int prefMethodCallIndent() {
+			String option= getCoreFormatterOption(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() {
+			// don't do parenthesis deep indentation
+//			String option= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_CONTINUATION_INDENTATION);
+//			try {
+//				return DefaultCodeFormatterConstants.getIndentStyle(option) == DefaultCodeFormatterConstants.INDENT_ON_COLUMN;
+//			} catch (IllegalArgumentException e) {
+//				// ignore and return default
+//			}
+
+			return false;
+		}
+
+		private int prefParenthesisIndent() {
+			return prefContinuationIndent();
+		}
+
+		private int prefBlockIndent() {
+			String option= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_INDENT_STATEMENTS_COMPARE_TO_BLOCK);
+			if (DefaultCodeFormatterConstants.FALSE.equals(option))
+				return 0;
+
+			return 1; // sensible default
+		}
+
+		private int prefMethodBodyIndent() {
+			if (DefaultCodeFormatterConstants.FALSE.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_INDENT_STATEMENTS_COMPARE_TO_BODY)))
+				return 0;
+
+			return 1; // sensible default
+		}
+
+		private int prefTypeIndent() {
+			String option= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_INDENT_BODY_DECLARATIONS_COMPARE_TO_ACCESS_SPECIFIER);
+			if (DefaultCodeFormatterConstants.FALSE.equals(option))
+				return 0;
+
+			return 1; // sensible default
+		}
+		
+		private int prefAccessSpecifierIndent() {
+			if (DefaultCodeFormatterConstants.TRUE.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_INDENT_ACCESS_SPECIFIER_COMPARE_TO_TYPE_HEADER)))
+				return 1;
+			else
+				return 0;
+		}
+
+		private int prefAccessSpecifierExtraSpaces() {
+			// Hidden option that enables fractional indent of access specifiers.
+			IPreferencesService prefs = Platform.getPreferencesService();
+			return prefs.getInt(CCorePlugin.PLUGIN_ID, CCorePlugin.PLUGIN_ID + ".formatter.indent_access_specifier_extra_spaces", 0, null); //$NON-NLS-1$
+		}
+
+		private int prefNamespaceBodyIndent() {
+			if (DefaultCodeFormatterConstants.TRUE.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_INDENT_BODY_DECLARATIONS_COMPARE_TO_NAMESPACE_HEADER)))
+				return prefBlockIndent();
+			else
+				return 0;
+		}
+
+		private boolean prefIndentBracesForBlocks() {
+			return DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_BLOCK));
+		}
+
+		private boolean prefIndentBracesForArrays() {
+			return DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_INITIALIZER_LIST));
+		}
+
+		private boolean prefIndentBracesForMethods() {
+			return DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_METHOD_DECLARATION));
+		}
+
+		private boolean prefIndentBracesForTypes() {
+			return DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_TYPE_DECLARATION));
+		}
+
+		private int prefContinuationIndent() {
+			try {
+				return Integer.parseInt(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_CONTINUATION_INDENTATION));
+			} catch (NumberFormatException e) {
+				// ignore and return default
+			}
+
+			return 2; // sensible default
+		}
+		
+		private boolean hasTemplates() {
+			return true;
+		}
+	}
+
+	/** The document being scanned. */
+	private final IDocument fDocument;
+	/** The indentation accumulated by <code>findReferencePosition</code>. */
+	private int fIndent;
+	/** Extra spaces to add on top of fIndent */
+	private int fExtraSpaces;
+	/**
+	 * The absolute (character-counted) indentation offset for special cases
+	 * (method defs, array initializers)
+	 */
+	private int fAlign;
+	/** The stateful scan position for the indentation methods. */
+	private int fPosition;
+	/** The previous position. */
+	private int fPreviousPos;
+	/** The most recent token. */
+	private int fToken;
+	/** The line of <code>fPosition</code>. */
+	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 final CHeuristicScanner fScanner;
+	/**
+	 * The CDT Core preferences.
+	 */
+	private final CorePrefs fPrefs;
+
+	/**
+	 * Creates a new instance.
+	 *
+	 * @param document the document to scan
+	 * @param scanner the {@link CHeuristicScanner} to be used for scanning
+	 * the document. It must be installed on the same <code>IDocument</code>.
+	 */
+	public CIndenter(IDocument document, CHeuristicScanner scanner) {
+		this(document, scanner, null);
+	}
+
+	/**
+	 * Creates a new instance.
+	 *
+	 * @param document the document to scan
+	 * @param scanner the {@link CHeuristicScanner} to be used for scanning
+	 *        the document. It must be installed on the same
+	 *        <code>IDocument</code>.
+	 * @param project the C/C++ project to get the formatter preferences from, or
+	 *        <code>null</code> to use the workspace settings
+	 */
+	public CIndenter(IDocument document, CHeuristicScanner scanner, ICProject project) {
+		Assert.isNotNull(document);
+		Assert.isNotNull(scanner);
+		fDocument= document;
+		fScanner= scanner;
+		fPrefs= new CorePrefs(project);
+	}
+
+	/**
+	 * Computes the indentation at the reference point of <code>position</code>.
+	 *
+	 * @param offset the offset in the document
+	 * @return a String which reflects the indentation at the line in which the
+	 *         reference position to <code>offset</code> resides, or <code>null</code>
+	 *         if it cannot be determined
+	 */
+	public StringBuilder getReferenceIndentation(int offset) {
+		return getReferenceIndentation(offset, false);
+	}
+
+	/**
+	 * Computes the indentation at the reference point of <code>position</code>.
+	 *
+	 * @param offset the offset in the document
+	 * @param assumeOpeningBrace <code>true</code> if an opening brace should be assumed
+	 * @return a String which reflects the indentation at the line in which the
+	 *         reference position to <code>offset</code> resides, or <code>null</code>
+	 *         if it cannot be determined
+	 */
+	private StringBuilder getReferenceIndentation(int offset, boolean assumeOpeningBrace) {
+		int unit;
+		if (assumeOpeningBrace)
+			unit= findReferencePosition(offset, Symbols.TokenLBRACE);
+		else
+			unit= findReferencePosition(offset, peekToken(offset));
+
+		// if we were unable to find anything, return null
+		if (unit == CHeuristicScanner.NOT_FOUND)
+			return null;
+
+		return getLeadingWhitespace(unit);
+	}
+
+	/**
+	 * Computes the indentation at <code>offset</code>.
+	 *
+	 * @param offset the offset in the document
+	 * @return a String which reflects the correct indentation for the line in
+	 *         which offset resides, or <code>null</code> if it cannot be
+	 *         determined
+	 */
+	public StringBuilder computeIndentation(int offset) {
+		return computeIndentation(offset, false);
+	}
+
+	/**
+	 * Computes the indentation at <code>offset</code>.
+	 *
+	 * @param offset the offset in the document
+	 * @param assumeOpeningBrace <code>true</code> if an opening brace should be assumed
+	 * @return a String which reflects the correct indentation for the line in
+	 *         which offset resides, or <code>null</code> if it cannot be
+	 *         determined
+	 */
+	public StringBuilder computeIndentation(int offset, boolean assumeOpeningBrace) {
+		StringBuilder reference= getReferenceIndentation(offset, assumeOpeningBrace);
+
+		// handle special alignment
+		if (fAlign != CHeuristicScanner.NOT_FOUND) {
+			try {
+				// a special case has been detected.
+				IRegion line= fDocument.getLineInformationOfOffset(fAlign);
+				int lineOffset= line.getOffset();
+				return createIndent(lineOffset, fAlign, false);
+			} catch (BadLocationException e) {
+				return null;
+			}
+		}
+
+		if (reference == null)
+			return null;
+
+		// Add additional indent
+		return createReusingIndent(reference, fIndent, fExtraSpaces);
+	}
+
+	/**
+	 * Computes the indentation for a continuation line at <code>offset</code>.
+	 *
+	 * @param offset the offset in the document
+	 * @return a StringBuilder which reflects the correct indentation for
+	 *         the line in  which offset resides, or <code>null</code> if it cannot be
+	 *         determined.
+	 * @throws BadLocationException
+	 */
+	public StringBuilder computeContinuationLineIndentation(int offset) throws BadLocationException {
+		StringBuilder reference= getLeadingWhitespace(offset);
+		IRegion line= fDocument.getLineInformationOfOffset(offset);
+		String string= fDocument.get(line.getOffset(), offset - line.getOffset());
+		if (string.trim().length() == 0)
+			return reference;
+		// Add additional indent
+		return createReusingIndent(reference, fPrefs.prefContinuationIndent, 0);
+	}
+	
+	/**
+	 * Computes the length of a <code>CharacterSequence</code>, counting
+	 * a tab character as the size until the next tab stop and every other
+	 * character as one.
+	 *
+	 * @param indent the string to measure
+	 * @return the visual length in characters
+	 */
+	private int computeVisualLength(CharSequence indent) {
+		final int tabSize= fPrefs.prefTabSize;
+		int length= 0;
+		for (int i= 0; i < indent.length(); i++) {
+			char ch= indent.charAt(i);
+			switch (ch) {
+			case '\t':
+				if (tabSize > 0) {
+					int reminder= length % tabSize;
+					length += tabSize - reminder;
+				}
+				break;
+			case ' ':
+				length++;
+				break;
+			}
+		}
+		return length;
+	}
+
+	/**
+	 * Strips any characters off the end of <code>reference</code> that exceed
+	 * <code>indentLength</code>.
+	 *
+	 * @param reference the string to measure
+	 * @param indentLength the maximum visual indentation length
+	 * @return the stripped <code>reference</code>
+	 */
+	private StringBuilder stripExceedingChars(StringBuilder reference, int indentLength) {
+		final int tabSize= fPrefs.prefTabSize;
+		int measured= 0;
+		int chars= reference.length();
+		int i= 0;
+		for (; measured < indentLength && i < chars; i++) {
+			char ch= reference.charAt(i);
+			switch (ch) {
+			case '\t':
+				if (tabSize > 0) {
+					int reminder= measured % tabSize;
+					measured += tabSize - reminder;
+				}
+				break;
+			case ' ':
+				measured++;
+				break;
+			}
+		}
+		int deleteFrom= measured > indentLength ? i - 1 : i;
+
+		return reference.delete(deleteFrom, chars);
+	}
+
+	/**
+	 * Returns the indentation of the line at <code>offset</code> as a
+	 * <code>StringBuilder</code>. 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
+	 * 		   <code>offset</code> is located
+	 */
+	private StringBuilder getLeadingWhitespace(int offset) {
+		StringBuilder indent= new StringBuilder();
+		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;
+		}
+	}
+
+	/**
+	 * Creates an indentation string of the length indent - start, consisting of
+	 * the content in <code>fDocument</code> in the range [start, indent),
+	 * with every character replaced by a space except for tabs, which are kept
+	 * as such.
+	 * <p>
+	 * If <code>convertSpaceRunsToTabs</code> is <code>true</code>, every
+	 * run of the number of spaces that make up a tab are replaced by a tab
+	 * character. If it is not set, no conversion takes place, but tabs in the
+	 * original range are still copied verbatim.
+	 * </p>
+	 *
+	 * @param start the start of the document region to copy the indent from
+	 * @param indent the exclusive end of the document region to copy the indent
+	 *        from
+	 * @param convertSpaceRunsToTabs whether to convert consecutive runs of
+	 *        spaces to tabs
+	 * @return the indentation corresponding to the document content specified
+	 *         by <code>start</code> and <code>indent</code>
+	 */
+	private StringBuilder createIndent(int start, final int indent, final boolean convertSpaceRunsToTabs) {
+		final boolean convertTabs= fPrefs.prefUseTabs && convertSpaceRunsToTabs;
+		final int tabLen= fPrefs.prefTabSize;
+		final StringBuilder ret= new StringBuilder();
+		try {
+			int spaces= 0;
+			while (start < indent) {
+				char ch= fDocument.getChar(start);
+				if (ch == '\t') {
+					ret.append('\t');
+					spaces= 0;
+				} else if (convertTabs) {
+					spaces++;
+					if (spaces == tabLen) {
+						ret.append('\t');
+						spaces= 0;
+					}
+				} else {
+					ret.append(' ');
+				}
+
+				start++;
+			}
+			// remainder
+			while (spaces-- > 0)
+				ret.append(' ');
+		} catch (BadLocationException e) {
+		}
+
+		return ret;
+	}
+
+	/**
+	 * Creates a string with a visual length of the given
+	 * <code>indentationSize</code>.
+	 *
+	 * @param buffer the original indent to reuse if possible
+	 * @param additional the additional indentation units to add or subtract to
+	 *        reference
+	 * @param extraSpaces additional spaces to add to indentation.
+	 * @return the modified <code>buffer</code> reflecting the indentation
+	 *         adapted to <code>additional</code>
+	 */
+	public StringBuilder createReusingIndent(StringBuilder buffer, int additional, int extraSpaces) {
+		int refLength= computeVisualLength(buffer);
+		int addLength= fPrefs.prefIndentationSize * additional + extraSpaces; // may be < 0
+		int totalLength= Math.max(0, refLength + addLength);
+
+		// copy the reference indentation for the indent up to the last tab
+		// stop within the maxCopy area
+		int minLength= Math.min(totalLength, refLength);
+		int tabSize= fPrefs.prefTabSize;
+		int maxCopyLength= tabSize > 0 ? minLength - minLength % tabSize : minLength; // maximum indent to copy
+		stripExceedingChars(buffer, maxCopyLength);
+
+		// add additional indent
+		int missing= totalLength - maxCopyLength;
+		final int tabs, spaces;
+		if (CCorePlugin.SPACE.equals(fPrefs.prefTabChar)) {
+			tabs= 0;
+			spaces= missing;
+		} else {
+			tabs= tabSize > 0 ? missing / tabSize : 0;
+			spaces= tabSize > 0 ? missing % tabSize : missing;
+		}
+		for (int i= 0; i < tabs; i++)
+			buffer.append('\t');
+		for (int i= 0; i < spaces; i++)
+			buffer.append(' ');
+		return buffer;
+	}
+
+	/**
+	 * Returns relative indent of continuation lines.
+	 * @return a number of indentation units.
+	 */
+	public int getContinuationLineIndent() {
+		return fPrefs.prefContinuationIndent;
+	}
+
+	/**
+	 * Returns the reference position regarding to indentation for <code>offset</code>,
+	 * or <code>NOT_FOUND</code>. This method calls
+	 * {@link #findReferencePosition(int, int) findReferencePosition(offset, nextChar)} where
+	 * <code>nextChar</code> is the next character after <code>offset</code>.
+	 *
+	 * @param offset the offset for which the reference is computed
+	 * @return the reference statement relative to which <code>offset</code>
+	 *         should be indented, or {@link CHeuristicScanner#NOT_FOUND}
+	 */
+	public int findReferencePosition(int offset) {
+		return findReferencePosition(offset, peekToken(offset));
+	}
+
+	/**
+	 * Peeks the next token in the document that comes after <code>offset</code>
+	 * on the same line as <code>offset</code>.
+	 *
+	 * @param offset the offset into document
+	 * @return the token symbol of the next element, or TokenEOF if there is none
+	 */
+	private int peekToken(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 <code>position</code>,
+	 * or <code>NOT_FOUND</code>.
+	 *
+	 * <p>If <code>peekNextChar</code> is <code>true</code>, the next token after
+	 * <code>offset</code> 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:
+	 * <ul>
+	 * 	<li><code>switch</code> labels are indented relative to the switch block</li>
+	 * 	<li>opening curly braces are aligned correctly with the introducing code</li>
+	 * 	<li>closing curly braces are aligned properly with the introducing code of
+	 * 		the matching opening brace</li>
+	 * 	<li>closing parenthesis' are aligned with their opening peer</li>
+	 * 	<li>the <code>else</code> keyword is aligned with its <code>if</code>, anything
+	 * 		else is aligned normally (i.e. with the base of any introducing statements).</li>
+	 *  <li>if there is no token on the same line after <code>offset</code>, the indentation
+	 * 		is the same as for an <code>else</code> keyword</li>
+	 * </ul>
+	 *
+	 * @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 <code>offset</code>
+	 *         should be indented, or {@link CHeuristicScanner#NOT_FOUND}
+	 */
+	public int findReferencePosition(int offset, int nextToken) {
+		boolean danglingElse= false;
+		boolean cancelIndent= false; // If set to true, fIndent is ignored.
+		int extraIndent= 0; // Can be either positive or negative.
+		boolean matchBrace= false;
+		boolean matchParen= false;
+		boolean matchCase= false;
+		boolean matchAccessSpecifier= false;
+
+		// Account for un-indentation 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, CHeuristicScanner.UNBOUND);
+				boolean bracelessBlockStart= fScanner.isBracelessBlockStart(prevPos, CHeuristicScanner.UNBOUND);
+
+				switch (nextToken) {
+				case Symbols.TokenELSE:
+					danglingElse= true;
+					break;
+					
+				case Symbols.TokenCASE:
+				case Symbols.TokenDEFAULT:
+					if (isFirstTokenOnLine)
+						matchCase= true;
+					break;
+					
+				case Symbols.TokenPUBLIC:
+				case Symbols.TokenPROTECTED:
+				case Symbols.TokenPRIVATE:
+					if (isFirstTokenOnLine)
+						matchAccessSpecifier= true;
+					break;
+					
+				case Symbols.TokenLBRACE: // for opening-brace-on-new-line style
+					if (bracelessBlockStart) {
+						extraIndent= fPrefs.prefIndentBracesForBlocks ? 0 : -1;
+					} else if (prevToken == Symbols.TokenCOLON && !fPrefs.prefIndentBracesForBlocks) {
+						extraIndent= -1;
+					} else if ((prevToken == Symbols.TokenEQUAL || prevToken == Symbols.TokenRBRACKET) &&
+							!fPrefs.prefIndentBracesForArrays) {
+						cancelIndent= true;
+					} else if (prevToken == Symbols.TokenRPAREN && fPrefs.prefIndentBracesForMethods) {
+						extraIndent= 1;
+					} else if (prevToken == Symbols.TokenIDENT && fPrefs.prefIndentBracesForTypes) {
+						extraIndent= 1;
+					}
+					break;
+					
+				case Symbols.TokenRBRACE: // closing braces get unindented
+					if (isFirstTokenOnLine || prevToken != Symbols.TokenLBRACE)
+						matchBrace= true;
+					break;
+					
+				case Symbols.TokenRPAREN:
+					if (isFirstTokenOnLine)
+						matchParen= true;
+					break;
+				}
+			} catch (BadLocationException e) {
+			}
+		} else {
+			// don't assume an else could come if we are at the end of file
+			danglingElse= false;
+		}
+
+		int ref= findReferencePosition(offset, danglingElse, matchBrace, matchParen, matchCase,
+				matchAccessSpecifier);
+		if (cancelIndent) {
+			fIndent = 0;
+		} else if (extraIndent > 0) {
+			fAlign= CHeuristicScanner.NOT_FOUND;
+			fIndent += extraIndent;
+		} else {
+			fIndent += extraIndent;
+		}
+		return ref;
+	}
+
+	/**
+	 * Returns the reference position regarding to indentation for <code>position</code>,
+	 * or <code>NOT_FOUND</code>.<code>fIndent</code> 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), <code>fAlign</code> will contain
+	 * the absolute position of the alignment reference in <code>fDocument</code>,
+	 * otherwise <code>fAlign</code> is set to <code>CHeuristicScanner.NOT_FOUND</code>.
+	 *
+	 * @param offset the offset for which the reference is computed
+	 * @param danglingElse whether a dangling else should be assumed at <code>position</code>
+	 * @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)
+	 * @param matchAccessSpecifier whether the position of a class body reference
+	 *            should be returned (either an earlier public/protected/private
+	 *            or the class body brace)
+	 * @return the reference statement relative to which <code>position</code>
+	 *         should be indented, or {@link CHeuristicScanner#NOT_FOUND}
+	 */
+	public int findReferencePosition(int offset, boolean danglingElse, boolean matchBrace, boolean matchParen,
+			boolean matchCase, boolean matchAccessSpecifier) {
+		fIndent= 0; // the indentation modification
+		fAlign= CHeuristicScanner.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,
+						matchAccessSpecifier);
+				fIndent--;
+				return pos;
+			}
+		}
+
+		// Align parentheses
+		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,
+						matchAccessSpecifier);
+				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();
+		}
+
+		// the only reliable way to get access specifiers aligned (due to many different styles of using
+		// braces in a block) is to go for another access specifier, or the scope opening brace.
+		if (matchAccessSpecifier) {
+			return matchAccessSpecifierAlignment();
+		}
+		
+		nextToken();
+		// Skip access specifiers
+		while (fToken == Symbols.TokenCOLON && isAccessSpecifier()) {
+			nextToken();
+		}
+
+		int line= fLine;
+		switch (fToken) {
+		case Symbols.TokenGREATERTHAN:
+		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;
+			return skipToStatementStart(danglingElse, false);
+		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(Math.min(offset + 1, fDocument.getLength()), true);
+
+		case Symbols.TokenEOF:
+			// trap when hitting start of document
+			return CHeuristicScanner.NOT_FOUND;
+
+		case Symbols.TokenEQUAL:
+			// indent assignments
+			fIndent= fPrefs.prefAssignmentIndent;
+			return fPosition;
+
+		case Symbols.TokenCOLON:
+			pos= fPosition;
+			if (looksLikeCaseStatement()) {
+				fIndent= fPrefs.prefCaseBlockIndent;
+				return pos;
+			}
+			fPosition= pos;
+			if (looksLikeTypeInheritanceDecl()) {
+				fIndent= fPrefs.prefBlockIndent;
+				return pos;
+			}
+			fPosition= pos;
+			if (looksLikeConstructorInitializer()) {
+				fIndent= fPrefs.prefBlockIndent;
+				return pos;
+			}
+			fPosition= pos;
+			if (isConditional()) {
+				fPosition= offset;
+				fLine= line;
+				return skipToPreviousListItemOrListStart();
+			}
+			fPosition= pos;
+			return skipToStatementStart(danglingElse, false);
+
+		case Symbols.TokenQUESTIONMARK:
+			if (fPrefs.prefTernaryDeepAlign) {
+				setFirstElementAlignment(fPosition, offset + 1);
+			} else {
+				fIndent= fPrefs.prefTernaryIndent;
+			}
+			return fPosition;
+
+		// indentation for blockless introducers:
+		case Symbols.TokenDO:
+		case Symbols.TokenWHILE:
+		case Symbols.TokenELSE:
+			fIndent= fPrefs.prefSimpleIndent;
+			return fPosition;
+
+		case Symbols.TokenTRY:
+			return skipToStatementStart(danglingElse, false);
+
+		case Symbols.TokenRPAREN:
+			if (skipScope(Symbols.TokenLPAREN, Symbols.TokenRPAREN)) {
+				int scope= fPosition;
+				nextToken();
+				if (fToken == Symbols.TokenIF || fToken == Symbols.TokenWHILE || fToken == Symbols.TokenFOR) {
+					fIndent= fPrefs.prefSimpleIndent;
+					return fPosition;
+				}
+				if (fToken == Symbols.TokenSWITCH) {
+					return fPosition;
+				}
+				fPosition= scope;
+				if (looksLikeMethodDecl()) {
+					return skipToStatementStart(danglingElse, false);
+				}
+				if (fToken == Symbols.TokenCATCH) {
+					return skipToStatementStart(danglingElse, false);
+				}
+				fPosition= scope;
+				if (looksLikeAnonymousTypeDecl()) {
+					return skipToStatementStart(danglingElse, false);
+				}
+			}
+			// restore
+			fPosition= offset;
+			fLine= line;
+			// else: fall through to default
+			return skipToPreviousListItemOrListStart();
+
+		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
+			return skipToPreviousListItemOrListStart();
+		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 expression).
+			return skipToPreviousListItemOrListStart();
+		}
+	}
+
+	/**
+	 * Test whether an identifier encountered during scanning is part of
+	 * a type declaration, by scanning backward and ignoring any identifiers, commas,
+	 * and colons until we hit <code>class</code>, <code>struct</code>, <code>union</code>,
+	 * or <code>enum</code>.  If any braces, semicolons, or parentheses are encountered,
+	 * this is not a type declaration.
+	 * @return the reference offset of the start of the statement
+	 */
+	private int matchTypeDeclaration() {
+		while (true) {
+			nextToken();
+			if (fToken == Symbols.TokenIDENT
+					|| fToken == Symbols.TokenCOMMA
+					|| fToken == Symbols.TokenCOLON
+					|| fToken == Symbols.TokenPUBLIC
+					|| fToken == Symbols.TokenPROTECTED
+					|| fToken == Symbols.TokenPRIVATE) {
+				continue;
+			}
+			if (fToken == Symbols.TokenCLASS
+					|| fToken == Symbols.TokenSTRUCT
+					|| fToken == Symbols.TokenUNION
+					|| fToken == Symbols.TokenENUM) {
+				// inside a type declaration?  Only so if not preceded by '(' or ',' as in
+				// a parameter list.  To be safe, only accept ';' or EOF
+				int pos= fPosition;
+				nextToken();
+				if (fToken == Symbols.TokenSEMICOLON || fToken == Symbols.TokenEOF) {
+					return pos;
+				} else {
+					return CHeuristicScanner.NOT_FOUND;
+				}
+			} else {
+				return CHeuristicScanner.NOT_FOUND;
+			}
+		}
+	}
+
+	/**
+	 * Test whether the colon at the current position marks a case statement
+	 * 
+	 * @return <code>true</code> if this looks like a case statement
+	 */
+	private boolean looksLikeCaseStatement() {
+		nextToken();
+		switch (fToken) {
+		case Symbols.TokenCASE:
+			// char literal got skipped
+			return true;
+		case Symbols.TokenIDENT:
+			nextToken();
+			while (skipQualifiers()) {
+				nextToken();
+			}
+			if (fToken == Symbols.TokenCASE) {
+				return true;
+			}
+			break;
+		case Symbols.TokenOTHER:
+			nextToken();
+			if (fToken == Symbols.TokenCASE) {
+				return true;
+			}
+			break;
+		case Symbols.TokenDEFAULT:
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Test whether the colon at the current position marks a type inheritance decl.
+	 * 
+	 * @return <code>true</code> if this looks like a type inheritance decl.
+	 */
+	private boolean looksLikeTypeInheritanceDecl() {
+		nextToken();
+		switch (fToken) {
+		case Symbols.TokenIDENT:
+			nextToken();
+			while (skipQualifiers()) {
+				nextToken();
+			}
+			switch (fToken) {
+			case Symbols.TokenCLASS:
+			case Symbols.TokenSTRUCT:
+			case Symbols.TokenUNION:
+				return true;
+			}
+			break;
+		}
+		return false;
+	}
+
+	/**
+	 * Test whether the colon at the current position marks a constructor initializer list.
+	 * 
+	 * @return <code>true</code> if this looks like a constructor initializer list.
+	 */
+	private boolean looksLikeConstructorInitializer() {
+		nextToken();
+		if (fToken != Symbols.TokenRPAREN) {
+			return false;
+		}
+		if (!skipScope()) {
+			return false;
+		}
+		nextToken();
+		if (fToken == Symbols.TokenTHROW) {
+			nextToken();
+			if (fToken != Symbols.TokenRPAREN) {
+				return false;
+			}
+			if (!skipScope()) {
+				return false;
+			}
+			nextToken();
+		}
+		if (fToken != Symbols.TokenIDENT) {
+			return false;
+		}
+		nextToken();
+		switch (fToken) {
+		case Symbols.TokenCOLON:
+			nextToken();
+			switch (fToken) {
+			case Symbols.TokenCOLON:  // A::A() :
+			case Symbols.TokenPUBLIC:  // public: A() :
+			case Symbols.TokenPROTECTED:
+			case Symbols.TokenPRIVATE:
+				return true;
+			}
+			return false;
+			
+		case Symbols.TokenLBRACE:  // class A { A() :
+		case Symbols.TokenRBRACE:
+		case Symbols.TokenSEMICOLON:
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Test whether the colon at the current position marks an access specifier.
+	 * 
+	 * @return <code>true</code> if current position marks an access specifier
+	 */
+	private boolean isAccessSpecifier() {
+		int pos= fPosition;
+		int token = fToken;
+		nextToken();
+		switch (fToken) {
+		case Symbols.TokenPUBLIC:
+		case Symbols.TokenPROTECTED:
+		case Symbols.TokenPRIVATE:
+			return true;
+		}
+		fToken = token;
+		fPosition= pos;
+		return false;
+	}
+
+	/**
+	 * Skips to the start of a statement that ends at the current position.
+	 *
+	 * @param danglingElse whether to indent aligned with the last <code>if</code>
+	 * @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) {
+		final int NOTHING= 0;
+		final int READ_PARENS= 1;
+		final int READ_IDENT= 2;
+		int mayBeMethodBody= NOTHING;
+		boolean isTypeBody= false;
+		int startLine = fLine;
+		while (true) {
+			int prevToken= fToken;
+			nextToken();
+
+			if (isInBlock) {
+				switch (fToken) {
+				// exit on all block introducers
+				case Symbols.TokenIF:
+				case Symbols.TokenELSE:
+				case Symbols.TokenCATCH:
+				case Symbols.TokenDO:
+				case Symbols.TokenWHILE:
+				case Symbols.TokenFOR:
+				case Symbols.TokenTRY:
+					return fPosition;
+
+				case Symbols.TokenCLASS:
+				case Symbols.TokenENUM:
+				case Symbols.TokenSTRUCT:
+				case Symbols.TokenUNION:
+					isTypeBody= true;
+					break;
+
+				case Symbols.TokenSWITCH:
+					fIndent= fPrefs.prefCaseIndent;
+					return fPosition;
+				}
+			}
+
+			if (fToken == Symbols.TokenSEMICOLON && fLine == startLine) {
+				// Skip semicolons on the same line. Otherwise we may never reach beginning of a 'for'
+				// statement.
+				continue;
+			}
+
+			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:
+				if (peekToken() == Symbols.TokenFOR) {
+					nextToken();  // Consume 'for'
+					fIndent = fPrefs.prefContinuationIndent;
+					return fPosition;
+				}
+				break;
+
+			case Symbols.TokenLBRACE:
+			case Symbols.TokenSEMICOLON:
+			case Symbols.TokenEOF:
+				if (isInBlock)
+					fIndent= getBlockIndent(mayBeMethodBody == READ_IDENT, isTypeBody);
+				// else: fIndent set by previous calls
+				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()) {
+					if (looksLikeArrayInitializerIntro()) {
+						continue; // it's an array
+					}
+					if (prevToken == Symbols.TokenSEMICOLON) {
+						// end of type def
+						continue;
+					}
+				}
+				if (isInBlock)
+					fIndent= getBlockIndent(mayBeMethodBody == READ_IDENT, isTypeBody);
+				return pos; // it's not - do as with all the above
+
+			// scopes: skip them
+			case Symbols.TokenRPAREN:
+				if (isInBlock)
+					mayBeMethodBody= READ_PARENS;
+				// fall thru
+				pos= fPreviousPos;
+				if (skipScope())
+					break;
+				else
+					return pos;
+			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;
+				}
+			case Symbols.TokenIDENT:
+				if (mayBeMethodBody == READ_PARENS)
+					mayBeMethodBody= READ_IDENT;
+				break;
+
+			default:
+				// keep searching
+			}
+		}
+	}
+
+	private int getBlockIndent(boolean isMethodBody, boolean isTypeBody) {
+		if (isTypeBody) {
+			return fPrefs.prefTypeIndent + fPrefs.prefAccessSpecifierIndent;
+		} else if (isMethodBody) {
+			return fPrefs.prefMethodBodyIndent + (fPrefs.prefIndentBracesForMethods ? 1 : 0);
+		} else {
+			return fIndent;
+		}
+	}
+
+	/**
+	 * Returns <code>true</code> if the colon at the current position is part of a conditional
+	 * (ternary) expression, <code>false</code> otherwise.
+	 *
+	 * @return <code>true</code> if the colon at the current position is part of a conditional
+	 */
+	private boolean isConditional() {
+		while (true) {
+			int previous= fToken;
+			nextToken();
+			switch (fToken) {
+			// search for case labels, which consist of (possibly qualified) identifiers or numbers
+			case Symbols.TokenIDENT:
+				if (previous == Symbols.TokenIDENT) {
+					return false;
+				}
+				// fall thru
+				continue;
+			case Symbols.TokenDOUBLECOLON:
+			case Symbols.TokenOTHER:
+				continue;
+				
+			case Symbols.TokenQUESTIONMARK:
+				return true;
+				
+			case Symbols.TokenSEMICOLON:
+			case Symbols.TokenLBRACE:
+			case Symbols.TokenRBRACE:
+			case Symbols.TokenCASE:
+			case Symbols.TokenDEFAULT:
+			case Symbols.TokenPUBLIC:
+			case Symbols.TokenPROTECTED:
+			case Symbols.TokenPRIVATE:
+			case Symbols.TokenCLASS:
+			case Symbols.TokenSTRUCT:
+			case Symbols.TokenUNION:
+				return false;
+
+			default:
+				return true;
+			}
+		}
+	}
+
+	/**
+	 * Returns as a reference any previous <code>switch</code> labels (<code>case</code>
+	 * or <code>default</code>) or the offset of the brace that scopes the switch
+	 * statement. Sets <code>fIndent</code> to <code>prefCaseIndent</code> upon
+	 * a match.
+	 *
+	 * @return the reference offset for a <code>switch</code> 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.TokenSWITCH:
+				// start of switch statement
+				fIndent= fPrefs.prefCaseIndent;
+				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 as a reference any previous access specifiers (<code>public</code>,
+	 * <code>protected</code> or <code>default</code>) or the offset of the brace that
+	 * scopes the class body.
+	 * Sets <code>fIndent</code> to <code>prefAccessSpecifierIndent</code> upon
+	 * a match.
+	 *
+	 * @return the reference offset for an access specifier (public/protected/private)
+	 */
+	private int matchAccessSpecifierAlignment() {
+		while (true) {
+			nextToken();
+			switch (fToken) {
+			// invalid cases: another access specifier or an LBRACE must come before an access specifier
+			// -> bail out with the current position
+			case Symbols.TokenLPAREN:
+			case Symbols.TokenLBRACKET:
+			case Symbols.TokenEOF:
+				return fPosition;
+				
+			case Symbols.TokenLBRACE:
+				// opening brace of class body
+				int pos= fPosition;
+				int typeDeclPos= matchTypeDeclaration();
+				fIndent= fPrefs.prefAccessSpecifierIndent;
+				fExtraSpaces = fPrefs.prefAccessSpecifierExtraSpaces;
+				if (typeDeclPos != CHeuristicScanner.NOT_FOUND) {
+					return typeDeclPos;
+				}
+				return pos;
+			case Symbols.TokenPUBLIC:
+			case Symbols.TokenPROTECTED:
+			case Symbols.TokenPRIVATE:
+				// align with previous access specifier
+				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, boolean)}.
+	 * @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;
+		boolean seenEqual = fToken == Symbols.TokenEQUAL;
+		boolean seenShiftLeft = fToken == Symbols.TokenSHIFTLEFT;
+		boolean seenRightParen = fToken == Symbols.TokenRPAREN;
+		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);
+					if ((fToken == Symbols.TokenSEMICOLON || fToken == Symbols.TokenRBRACE ||
+							fToken == Symbols.TokenLBRACE && !looksLikeArrayInitializerIntro()) &&
+							(seenEqual || seenShiftLeft || seenRightParen)) {
+						fIndent = fPrefs.prefContinuationIndent;
+					} else {
+						fAlign= fScanner.findNonWhitespaceForwardInAnyPartition(lineOffset, bound);
+						// If the reference line starts with a colon, skip the colon.  
+						if (peekToken(fAlign) == Symbols.TokenCOLON) {
+							fAlign= fScanner.findNonWhitespaceForwardInAnyPartition(fAlign + 1, bound);
+						}
+					}
+				} catch (BadLocationException e) {
+					// Ignore and return just the position
+				}
+				return startPosition;
+			}
+
+			switch (fToken) {
+			// scopes: skip them
+			case Symbols.TokenRPAREN:
+				seenRightParen = true;
+				//$FALL-THROUGH$
+			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, false);
+
+			case Symbols.TokenSEMICOLON:
+				return fPosition;
+
+			case Symbols.TokenQUESTIONMARK:
+				if (fPrefs.prefTernaryDeepAlign) {
+					setFirstElementAlignment(fPosition - 1, fPosition + 1);
+				} else {
+					fIndent= fPrefs.prefTernaryIndent;
+				}
+				return fPosition;
+
+			case Symbols.TokenEQUAL:
+				seenEqual = true;
+				break;
+
+			case Symbols.TokenSHIFTLEFT:
+				seenShiftLeft = true;
+				break;
+
+			case Symbols.TokenEOF:
+				if (seenEqual || seenShiftLeft || seenRightParen) {
+					fIndent = fPrefs.prefContinuationIndent;
+				}
+				return 0;
+			}
+		}
+	}
+
+	/**
+	 * Skips a scope and positions the cursor (<code>fPosition</code>) on the
+	 * token that opens the scope. Returns <code>true</code> if a matching peer
+	 * could be found, <code>false</code> otherwise. The current token when calling
+	 * must be one out of <code>Symbols.TokenRPAREN</code>, <code>Symbols.TokenRBRACE</code>,
+	 * and <code>Symbols.TokenRBRACKET</code>.
+	 *
+	 * @return <code>true</code> if a matching peer was found, <code>false</code> 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);
+		case Symbols.TokenGREATERTHAN:
+			if (!fPrefs.prefHasTemplates)
+				return false;
+			int storedPosition= fPosition;
+			int storedToken= fToken;
+			nextToken();
+			switch (fToken) {
+				case Symbols.TokenIDENT:
+					if (skipScope(Symbols.TokenLESSTHAN, Symbols.TokenGREATERTHAN))
+						return true;
+					break;
+				case Symbols.TokenQUESTIONMARK:
+				case Symbols.TokenGREATERTHAN:
+					if (skipScope(Symbols.TokenLESSTHAN, Symbols.TokenGREATERTHAN))
+						return true;
+					break;
+			}
+			// <> are harder to detect - restore the position if we fail
+			fPosition= storedPosition;
+			fToken= storedToken;
+			return false;
+
+		default:
+			 // programming error
+			Assert.isTrue(false);
+			return false;
+		}
+	}
+
+	/**
+	 * Returns the contents of the current token.
+	 *
+	 * @return the contents of the current token
+	 */
+	private CharSequence getTokenContent() {
+		return new DocumentCharacterIterator(fDocument, fPosition, fPreviousPos);
+	}
+
+	/**
+	 * Handles the introduction of a new scope. The current token must be one out
+	 * of <code>Symbols.TokenLPAREN</code>, <code>Symbols.TokenLBRACE</code>,
+	 * and <code>Symbols.TokenLBRACKET</code>. Returns as the reference position
+	 * either the token introducing the scope or - if available - the first
+	 * token after that.
+	 *
+	 * <p>Depending on the type of scope introduction, the indentation will align
+	 * (deep indenting) with the reference position (<code>fAlign</code> will be
+	 * set to the reference position) or <code>fIndent</code> will be set to
+	 * the number of indentation units.
+	 * </p>
+	 *
+	 * @param bound the bound for the search for the first token after the scope
+	 * introduction.
+	 * @param firstToken <code>true</code> if we are dealing with the first token after
+	 * the opening parenthesis.
+	 * @return the indent
+	 */
+	private int handleScopeIntroduction(int bound, boolean firstToken) {
+		int pos= fPosition; // store
+
+		switch (fToken) {
+		// scope introduction: special treat who special is
+		case Symbols.TokenLPAREN:
+			// special: method declaration deep indentation
+			if (looksLikeMethodDecl()) {
+				if (firstToken ? fPrefs.prefMethodDeclFirstParameterDeepIndent : fPrefs.prefMethodDeclDeepIndent) {
+					return setFirstElementAlignment(pos, bound);
+				} else {
+					fIndent= fPrefs.prefMethodDeclIndent;
+					return pos;
+				}
+			} else {
+				fPosition= pos;
+				if (looksLikeMethodCall()) {
+					if (firstToken ? fPrefs.prefMethodCallFirstParameterDeepIndent : fPrefs.prefMethodCallDeepIndent) {
+						return setFirstElementAlignment(pos, bound);
+					} else {
+						fIndent= fPrefs.prefMethodCallIndent;
+						return pos;
+					}
+				} else if (fPrefs.prefParenthesisDeepIndent) {
+					return setFirstElementAlignment(pos, bound);
+				}
+			}
+
+			// normal: return the parenthesis as reference
+			fIndent= fPrefs.prefParenthesisIndent;
+			return pos;
+
+		case Symbols.TokenLBRACE:
+			final boolean looksLikeArrayInitializerIntro= looksLikeArrayInitializerIntro();
+			// special: array initializer
+			if (looksLikeArrayInitializerIntro) {
+				if (fPrefs.prefArrayDeepIndent)
+					return setFirstElementAlignment(pos, bound);
+				else
+					fIndent= fPrefs.prefArrayIndent;
+			} else if (isNamespace()) {
+				fIndent= fPrefs.prefNamespaceBodyIndent;
+			} else {
+				int typeDeclPos = matchTypeDeclaration();
+				if (typeDeclPos == CHeuristicScanner.NOT_FOUND) {
+					fIndent= fPrefs.prefBlockIndent;
+				} else {
+					fIndent= fPrefs.prefAccessSpecifierIndent + fPrefs.prefTypeIndent;
+				}
+			}
+
+			// normal: skip to the statement start before the scope introducer
+			// opening braces are often on differently ending indents than e.g. a method definition
+			if (!looksLikeArrayInitializerIntro) {
+				fPosition= pos; // restore
+				return skipToStatementStart(true, true); // set to true to match the first if
+			} else {
+				return pos;
+			}
+
+		case Symbols.TokenLBRACKET:
+			// special: method declaration deep indentation
+			if (fPrefs.prefArrayDimensionsDeepIndent) {
+				return setFirstElementAlignment(pos, bound);
+			}
+
+			// normal: return the bracket as reference
+			fIndent= fPrefs.prefBracketIndent;
+			return pos; // restore
+
+		default:
+			// programming error
+			Assert.isTrue(false);
+			return -1; // dummy
+		}
+	}
+
+	/**
+	 * Sets the deep indent offset (<code>fAlign</code>) to either the offset
+	 * right after <code>scopeIntroducerOffset</code> or - if available - the
+	 * first C token after <code>scopeIntroducerOffset</code>, but before
+	 * <code>bound</code>.
+	 *
+	 * @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 == CHeuristicScanner.NOT_FOUND) {
+			fAlign= firstPossible;
+		} else {
+			try {
+				IRegion lineRegion = fDocument.getLineInformationOfOffset(scopeIntroducerOffset);
+				if (fAlign > lineRegion.getOffset() + lineRegion.getLength()) {
+					fAlign= firstPossible; 
+				}
+			} catch (BadLocationException e) {
+				// Ignore.
+			}
+		}
+		return fAlign;
+	}
+
+	/**
+	 * Returns <code>true</code> if the next token received after calling
+	 * <code>nextToken</code> is either an equal sign, an opening brace,
+	 * a comma or an array designator ('[]').
+	 *
+	 * @return <code>true</code> if the next elements look like the start of an array definition
+	 */
+	private boolean looksLikeArrayInitializerIntro() {
+		int pos= fPosition;
+		nextToken();
+		switch (fToken) {
+		case Symbols.TokenEQUAL:
+			return true;
+		case Symbols.TokenRBRACKET:
+			return skipBrackets();
+		case Symbols.TokenLBRACE:
+			if (looksLikeArrayInitializerIntro()) {
+				fPosition= pos;
+				return true;
+			}
+			return false;
+		case Symbols.TokenCOMMA:
+			fPosition= pos;
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Returns <code>true</code> if the the current token is "namespace", or the current token
+	 * is an identifier and the previous token is "namespace".
+	 *
+	 * @return <code>true</code> if the next elements look like the start of a namespace declaration.
+	 */
+	private boolean isNamespace() {
+		int pos = fPosition;
+		if (fToken == Symbols.TokenNAMESPACE) {
+			return true;		// Anonymous namespace
+		} else if (fToken == Symbols.TokenIDENT) {
+			nextToken();		// Get previous token
+			if (fToken == Symbols.TokenNAMESPACE) {
+				return true;	// Named namespace
+			}
+		}
+		fPosition = pos;
+		return false;
+	}
+
+	/**
+	 * Skips over the next <code>if</code> keyword. The current token when calling
+	 * this method must be an <code>else</code> keyword. Returns <code>true</code>
+	 * if a matching <code>if</code> could be found, <code>false</code> otherwise.
+	 * The cursor (<code>fPosition</code>) is set to the offset of the <code>if</code>
+	 * token.
+	 *
+	 * @return <code>true</code> if a matching <code>if</code> token was found, <code>false</code> 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 <code>do</code> can either be separated from the while by a
+	 * block, or by a single statement, which limits our search distance.
+	 *
+	 * @return <code>true</code> if the <code>while</code> currently in
+	 *         <code>fToken</code> has a matching <code>do</code>.
+	 */
+	private boolean hasMatchingDo() {
+		Assert.isTrue(fToken == Symbols.TokenWHILE);
+		nextToken();
+		switch (fToken) {
+		case Symbols.TokenRBRACE:
+			skipScope(); // and fall thru
+			skipToStatementStart(false, false);
+			return fToken == Symbols.TokenDO;
+
+		case Symbols.TokenSEMICOLON:
+			skipToStatementStart(false, false);
+			return fToken == Symbols.TokenDO;
+		}
+		return false;
+	}
+
+	/**
+	 * Skips pointer operators if the current token is a pointer operator.
+	 *
+	 * @return <code>true</code> if a <code>*</code> or <code>&amp;</code> could be scanned, the
+	 *         current token is left at the operator.
+	 */
+	private boolean skipPointerOperators() {
+		if (fToken == Symbols.TokenOTHER) {
+			CharSequence token= getTokenContent();
+			if (token.length() == 1 && token.charAt(0) == '*' || token.charAt(0) == '&') {
+				return true;
+			}
+		} else if (fToken == Symbols.TokenCONST) {
+			return true;
+		}
+		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 <code>[]</code> elements.
+	 *
+	 * @return <code>true</code> if a <code>[]</code> 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;
+	}
+
+	/**
+	 * Skips scope qualifiers of identifiers.
+	 * 
+	 * @return <code>true</code> if a qualifier was encountered, the last token
+	 *         will be an IDENT.
+	 */
+	private boolean skipQualifiers() {
+		if (fToken == Symbols.TokenDOUBLECOLON) {
+			nextToken();
+			if (fToken == Symbols.TokenIDENT) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Reads the next token in backward direction from the heuristic scanner
+	 * and sets the fields <code>fToken, fPreviousPosition</code> and <code>fPosition</code>
+	 * accordingly.
+	 */
+	private void nextToken() {
+		nextToken(fPosition);
+	}
+
+	/**
+	 * Reads the next token in backward direction of <code>start</code> from
+	 * the heuristic scanner and sets the fields <code>fToken, fPreviousPosition</code>
+	 * and <code>fPosition</code> accordingly.
+	 *
+	 * @param start the start offset from which to scan backwards
+	 */
+	private void nextToken(int start) {
+		fToken= fScanner.previousToken(start - 1, CHeuristicScanner.UNBOUND);
+		fPreviousPos= start;
+		fPosition= fScanner.getPosition() + 1;
+		try {
+			fLine= fDocument.getLineOfOffset(fPosition);
+		} catch (BadLocationException e) {
+			fLine= -1;
+		}
+	}
+
+	/**
+	 * Reads the next token in backward direction from the heuristic scanner
+	 * and returns that token without changing the current position.
+	 */
+	private int peekToken() {
+		return fScanner.previousToken(fPosition - 1, CHeuristicScanner.UNBOUND);
+	}
+
+	/**
+	 * Returns <code>true</code> if the current tokens look like a method
+	 * declaration header (i.e. only the return type and method name). The
+	 * heuristic calls <code>nextToken</code> and expects an identifier
+	 * (method name) and an optional return type declaration.
+	 *
+	 * @return <code>true</code> if the current position looks like a method
+	 *         declaration header.
+	 */
+	private boolean looksLikeMethodDecl() {
+		nextToken();
+		switch (fToken) {
+		case Symbols.TokenIDENT: // method name
+			int pos= fPosition;
+			nextToken();
+			// check destructor tilde
+			if (fToken == Symbols.TokenTILDE) {
+				return true;
+			}
+			if (skipQualifiers()) {
+				return true;
+			}
+			// optional brackets for array valued return types
+			while (skipBrackets()) {
+				nextToken();
+			}
+			while (skipPointerOperators()) {
+				nextToken();
+			}
+			switch (fToken) {
+			case Symbols.TokenIDENT:
+				return true;
+			case Symbols.TokenSEMICOLON:
+			case Symbols.TokenRBRACE:
+				fPosition= pos;
+				return true;
+			case Symbols.TokenLBRACE:
+				if (fScanner.looksLikeCompositeTypeDefinitionBackward(fPosition, CHeuristicScanner.UNBOUND)) {
+					fPosition= pos;
+					return true;
+				}
+				break;
+			case Symbols.TokenCOLON:
+				nextToken();
+				switch (fToken) {
+				case Symbols.TokenPUBLIC:
+				case Symbols.TokenPROTECTED:
+				case Symbols.TokenPRIVATE:
+					fPosition= pos;
+					return true;
+				case Symbols.TokenRPAREN:
+					// constructor initializer
+					if (skipScope()) {
+						nextToken();
+						// optional throw
+						if (fToken == Symbols.TokenTHROW) {
+							nextToken();
+							if (fToken != Symbols.TokenRPAREN || !skipScope()) {
+								return false;
+							}
+						}
+						return looksLikeMethodDecl();
+					}
+					break;
+				}
+			}
+			break;
+		case Symbols.TokenARROW:
+		case Symbols.TokenCOMMA:
+		case Symbols.TokenEQUAL:
+		case Symbols.TokenGREATERTHAN:
+		case Symbols.TokenLESSTHAN:
+		case Symbols.TokenMINUS:
+		case Symbols.TokenSHIFTRIGHT:
+		case Symbols.TokenSHIFTLEFT:
+		case Symbols.TokenDELETE:
+		case Symbols.TokenNEW:
+			nextToken();
+			return fToken == Symbols.TokenOPERATOR;
+		case Symbols.TokenOTHER:
+			if (getTokenContent().length() == 1) {
+				nextToken();
+				if (fToken == Symbols.TokenOPERATOR)
+					return true;
+			}
+			if (getTokenContent().length() == 1) {
+				nextToken();
+				if (fToken == Symbols.TokenOPERATOR)
+					return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Returns <code>true</code> if the current tokens look like an anonymous type declaration
+	 * header (i.e. a type name (potentially qualified) and a new keyword). The heuristic calls
+	 * <code>nextToken</code> and expects a possibly qualified identifier (type name) and a new
+	 * keyword
+	 * 
+	 * @return <code>true</code> if the current position looks like a anonymous type declaration
+	 *         header.
+	 */
+	private boolean looksLikeAnonymousTypeDecl() {
+		nextToken();
+		if (fToken == Symbols.TokenIDENT) { // type name
+			nextToken();
+			while (fToken == Symbols.TokenOTHER) { // dot of qualification
+				nextToken();
+				if (fToken != Symbols.TokenIDENT) // qualificating name
+					return false;
+				nextToken();
+			}
+			return fToken == Symbols.TokenNEW;
+		}
+		return false;
+	}
+
+	/**
+	 * Returns <code>true</code> if the current tokens look like a method
+	 * call header (i.e. an identifier as opposed to a keyword taking parenthesized
+	 * parameters such as <code>if</code>).
+	 * <p>The heuristic calls <code>nextToken</code> and expects an identifier
+	 * (method name).
+	 *
+	 * @return <code>true</code> if the current position looks like a method call
+	 *         header.
+	 */
+	private boolean looksLikeMethodCall() {
+		// TODO add awareness for constructor calls with templates: new complex<float>()
+		nextToken();
+		return fToken == Symbols.TokenIDENT; // method name
+	}
+
+	/**
+	 * Scans tokens for the matching opening peer. The internal cursor
+	 * (<code>fPosition</code>) is set to the offset of the opening peer if found.
+	 *
+	 * @param openToken the opening peer token
+	 * @param closeToken the closing peer token
+	 * @return <code>true</code> if a matching token was found, <code>false</code>
+	 *         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;
+			}
+		}
+	}
+}