/*******************************************************************************
* Copyright (c) 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
* Zend Technologies
*******************************************************************************/
package org.eclipse.php.internal.core.format;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IRegion;
import org.eclipse.php.internal.core.documentModel.parser.PHPRegionContext;
import org.eclipse.php.internal.core.documentModel.parser.regions.IPHPScriptRegion;
import org.eclipse.php.internal.core.documentModel.parser.regions.PHPRegionTypes;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionContainer;
public class CurlyCloseIndentationStrategy implements IIndentationStrategy {
public void placeMatchingBlanks(IStructuredDocument document, StringBuilder result, int lineNumber, int forOffset)
throws BadLocationException {
final IRegion curlyOpenLine = getCurlyOpenLineInformation(document, forOffset);
if (curlyOpenLine == null) {
return;
}
IndentationBaseDetector indentationDetector = new IndentationBaseDetector(document,
document.getLineOfOffset(curlyOpenLine.getOffset()), forOffset);
int indentationBaseLineIndex = indentationDetector.getIndentationBaseLine(true);
final IRegion indentationBaseLine = document.getLineInformation(indentationBaseLineIndex);
String blanks = ""; //$NON-NLS-1$
if (indentationBaseLine != null) {
blanks = FormatterUtils.getLineBlanks(document, indentationBaseLine);
} else { // if no matching bracket was found leaving the bracket as is.
blanks = FormatterUtils.getLineBlanks(document, document.getLineInformationOfOffset(forOffset));
}
result.append(blanks);
}
/**
* This function returns the line in which the corresponding '{' of the '}'
* found
*
* TODO this function has a bug in it: if there is a '{' inside inner state
* then it will not ignore it as it should.
*/
protected IRegion getCurlyOpenLineInformation(IStructuredDocument document, int forOffset)
throws BadLocationException {
int offset = forOffset;
int curlyCount = 0;
IStructuredDocumentRegion sdRegion = document.getRegionAtCharacterOffset(offset);
if (sdRegion == null) {
return null;
}
ITextRegion tRegion = sdRegion.getRegionAtCharacterOffset(offset);
if (tRegion == null && offset == document.getLength()) {
tRegion = sdRegion.getRegionAtCharacterOffset(offset - 1);
}
int regionStart = sdRegion.getStartOffset(tRegion);
// in case of container we have to extract the PhpScriptRegion
if (tRegion instanceof ITextRegionContainer) {
ITextRegionContainer container = (ITextRegionContainer) tRegion;
tRegion = container.getRegionAtCharacterOffset(offset);
regionStart += tRegion.getStart();
}
do {
if (tRegion instanceof IPHPScriptRegion) {
IPHPScriptRegion scriptRegion = (IPHPScriptRegion) tRegion;
tRegion = scriptRegion.getPHPToken(offset - regionStart - 1);
// go backward over the region to find a 'case' or 'default'
// region
// in this case is the same indentation
// other case if look for the '{' of the 'switch' region
while (true) {
String token = tRegion.getType();
if (token == PHPRegionTypes.PHP_CURLY_OPEN) {
curlyCount--;
if (curlyCount < 0) {
return document.getLineInformationOfOffset(tRegion.getStart() + regionStart);
}
} else if (token == PHPRegionTypes.PHP_CURLY_CLOSE) {
curlyCount++;
}
if (tRegion.getStart() > 0) {
tRegion = scriptRegion.getPHPToken(tRegion.getStart() - 1);
} else {
break;
}
}
}
tRegion = null;
if (sdRegion == null) {
return null;
}
// looking for the previous php block, maybe the '{' is in it
// (https://bugs.eclipse.org/bugs/show_bug.cgi?id=201648)
while ((sdRegion = sdRegion.getPrevious()) != null) {
if (sdRegion.getFirstRegion().getType().equals(PHPRegionContext.PHP_OPEN)) {
tRegion = sdRegion.getRegions().get(1);
regionStart = sdRegion.getStartOffset(tRegion);
offset = sdRegion.getEndOffset(tRegion);
break;
}
}
} while (tRegion != null);
return null;
}
}