/*******************************************************************************
* 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.ui.autoEdit;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DocumentCommand;
import org.eclipse.jface.text.IAutoEditStrategy;
import org.eclipse.php.internal.core.documentModel.parser.regions.PHPRegionTypes;
import org.eclipse.php.internal.core.format.FormatterUtils;
import org.eclipse.php.internal.ui.text.PHPDocumentRegionEdgeMatcher;
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;
/**
*
* @author guy.g
*
*/
public abstract class MatchingCharAutoEditStrategy implements IAutoEditStrategy {
protected static final char CURLY_OPEN = '{';
protected static final char CURLY_CLOSE = '}';
protected static final char ROUND_OPEN = '(';
protected static final char ROUND_CLOSE = ')';
protected static final char SQUARE_OPEN = '[';
protected static final char SQUARE_CLOSE = ']';
protected static final char SINGLE_QUOTE = '\'';
protected static final char DOUBLE_QUOTES = '\"';
protected static final char BACK_QUOTE = '`';
protected static final char BACK_SLASH = '\\';
protected static final int SEARCH_NOT_VALID = -1;
protected static final int MATCHING_BRACKET_NEEDED = 0;
protected static final int MATCHING_BRACKET_NOT_NEEDED = 1;
protected static PHPDocumentRegionEdgeMatcher matcher = new PHPDocumentRegionEdgeMatcher();
protected boolean isClosingBracket(final char c) {
return c == ROUND_CLOSE || c == SQUARE_CLOSE || c == CURLY_CLOSE;
}
protected boolean isQuote(final char c) {
return c == SINGLE_QUOTE || c == DOUBLE_QUOTES || c == BACK_QUOTE;
}
protected static char getMatchingChar(final char c) {
switch (c) {
case CURLY_OPEN:
return CURLY_CLOSE;
case CURLY_CLOSE:
return CURLY_OPEN;
case ROUND_OPEN:
return ROUND_CLOSE;
case ROUND_CLOSE:
return ROUND_OPEN;
case SQUARE_OPEN:
return SQUARE_CLOSE;
case SQUARE_CLOSE:
return SQUARE_OPEN;
case DOUBLE_QUOTES:
case SINGLE_QUOTE:
case BACK_QUOTE:
return c;
}
return '-';
}
/**
* returns true if the offset in the document is not to the left of text
* excluding php closing tag (?>) and comments
*/
protected boolean shouldAddClosingBracket(final IStructuredDocument document, final int offset,
final boolean isQuote) throws BadLocationException {
// check the case of the end of the document
// if we are after close PHP tag, don't give auto completion
// otherwise, we could be typing our code without having a php close tag
// and we do need completion
// (can't check region type since it is wrong)
if (document.getLength() == offset) {
if (offset >= 2 && document.getChar(offset - 2) == '?' && document.getChar(offset - 1) == '>')
return false;
else
return true;
}
if (document.getLength() == offset + 1) {
return true;
}
final char currChar = document.getChar(offset);
final char nextChar = document.getChar(offset + 1);
if (Character.isWhitespace(currChar) || isClosingBracket(currChar) || isQuote && isQuote(currChar)
|| currChar == ';' || currChar == ',')
return true;
if (offset + 1 >= document.getLength())
return false;
final String state = FormatterUtils.getPartitionType(document, offset);
if (state == PHPRegionTypes.PHP_OPENTAG)
return true;
if (currChar == '/' && (nextChar == '/' || nextChar == '*'))
return true;
if (currChar == '?' && nextChar == '>')
return true;
// in case of <<<
if (currChar == '<' && nextChar == '<' && offset + 2 < document.getLength()
&& document.getChar(offset + 2) == '<')
return true;
return false;
}
protected static boolean isSpecialOpenCurlyInQuotes(final IStructuredDocument document, final int offset)
throws BadLocationException {
final IStructuredDocumentRegion sdRegion = document.getRegionAtCharacterOffset(offset);
if (sdRegion == null)
return false;
final ITextRegion tRegion = sdRegion.getRegionAtCharacterOffset(offset);
// TODO need to support heredoc also
if (tRegion == null || tRegion.getType() != PHPRegionTypes.PHP_ENCAPSED_AND_WHITESPACE)
return false;
final char firstChar = document.getChar(sdRegion.getStartOffset() + tRegion.getStart());
if (firstChar != DOUBLE_QUOTES && firstChar != BACK_QUOTE)
return false;
final char bracketChar = document.getChar(offset + 1);
return bracketChar == '$';
}
/**
* when we call command.offset++; we also need to check command.caretOffset.
* bug 312439: Improper cursor jumps when using associative arrays in
* content assist https://bugs.eclipse.org/bugs/show_bug.cgi?id=312439
*
* @param command
*/
protected void adjustDocumentOffset(DocumentCommand command) {
command.offset++;
if (command.caretOffset != -1) {
command.caretOffset = command.offset;
}
}
}