/*******************************************************************************
* Copyright (c) 2009, 2016 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.doubleclick;
import org.eclipse.jface.text.*;
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.php.internal.core.documentModel.partitioner.PHPPartitionTypes;
import org.eclipse.php.internal.ui.PHPUiPlugin;
import org.eclipse.php.internal.ui.editor.PHPPairMatcher;
import org.eclipse.swt.graphics.Point;
import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
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.ITextRegionCollection;
import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionContainer;
import org.eclipse.wst.sse.ui.internal.StructuredTextViewer;
import org.w3c.dom.Node;
/**
* This class was added in order to solve the problem of selecting variable name
* in the editor. The default behaviour when double-clicking a variable, for
* instance $myVar, is to make only myVar selected - without the dollar sign.
* This class also fixes selection of PHPdoc tags. This class fixes this
* behaviour.
*
* @author guy.g
*
*/
public class PHPDoubleClickStrategy extends DefaultTextDoubleClickStrategy {
protected final static char[] BRACKETS = { '{', '}', '(', ')', '[', ']' };
protected PHPPairMatcher fPairMatcher = new PHPPairMatcher(BRACKETS);
@Override
public void doubleClicked(ITextViewer textViewer) {
if (textViewer instanceof StructuredTextViewer) {
StructuredTextViewer structuredTextViewer = (StructuredTextViewer) textViewer;
IStructuredModel structuredModel = null;
try {
structuredModel = StructuredModelManager.getModelManager()
.getExistingModelForRead(structuredTextViewer.getDocument());
if (structuredModel != null) {
int caretPosition = textViewer.getSelectedRange().x;
if (caretPosition > 0) {
Node node = (Node) structuredModel.getIndexedRegion(caretPosition);
if (node != null) {
IStructuredDocumentRegion sdRegion = structuredModel.getStructuredDocument()
.getRegionAtCharacterOffset(caretPosition);
if (sdRegion != null) {
ITextRegion tRegion = sdRegion.getRegionAtCharacterOffset(caretPosition);
ITextRegionCollection container = sdRegion;
if (tRegion instanceof ITextRegionContainer) {
container = (ITextRegionContainer) tRegion;
tRegion = container.getRegionAtCharacterOffset(caretPosition);
}
// We should always hit the PhpScriptRegion:
if (tRegion != null && tRegion.getType() == PHPRegionContext.PHP_CONTENT) {
IPHPScriptRegion phpScriptRegion = (IPHPScriptRegion) tRegion;
int offset = caretPosition - container.getStartOffset()
- phpScriptRegion.getStart();
tRegion = phpScriptRegion.getPHPToken(offset);
// Handle double-click on PHPDoc tags:
if (tRegion.getType() == PHPRegionTypes.PHP_VARIABLE
|| tRegion.getType() == PHPRegionTypes.PHP_THIS
|| PHPPartitionTypes.isPHPDocTagState(tRegion.getType())) {
int regionStart = container.getStartOffset() + phpScriptRegion.getStart();
if (caretPosition == regionStart + tRegion.getTextEnd()) {
final IDocument document = textViewer.getDocument();
IRegion region = findWord(document, caretPosition - 1);
if (region != null) {
textViewer.setSelectedRange(region.getOffset(), region.getLength());
}
} else {
textViewer.setSelectedRange(regionStart + tRegion.getStart(),
tRegion.getTextLength());
}
return; // Stop processing
}
// Check if the user double clicked on a
// variable in a PHP comment (fix
// bug#201079).
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=493467
// TODO: we don't have a method like
// PHPPartitionTypes.isPHPLineCommentStartRegion(type)
// to determine if we're at the beginning
// of a single-line comment so for now check
// region type at offset - 1 to be sure that
// previous character is still in comment.
if (PHPPartitionTypes.isPHPCommentState(tRegion.getType()) && offset > 0
&& PHPPartitionTypes.isPHPCommentState(
phpScriptRegion.getPHPToken(offset - 1).getType())) {
resetVariableSelectionRangeInComments(textViewer, structuredTextViewer);
return;
}
}
}
}
}
}
} catch (BadLocationException e) {
PHPUiPlugin.log(e);
} finally {
if (structuredModel != null) {
structuredModel.releaseFromRead();
}
}
}
// We reach here only if there was an error or one of conditions hasn't
// met our requirements:
super.doubleClicked(textViewer);
}
@Override
protected IRegion findExtendedDoubleClickSelection(IDocument document, int offset) {
IRegion match = fPairMatcher.match(document, offset);
if (match != null && match.getLength() >= 2) {
return new Region(match.getOffset() + 1, match.getLength() - 2);
}
return findWord(document, offset);
}
/**
* When the user double click on a variable in a comment, include the
* preceding $ sign in the selection (bug#201079)
*
* @param textViewer
* @param structuredTextViewer
* @throws BadLocationException
*/
private void resetVariableSelectionRangeInComments(ITextViewer textViewer,
StructuredTextViewer structuredTextViewer) throws BadLocationException {
super.doubleClicked(textViewer);
Point selectedRange = structuredTextViewer.getSelectedRange();
int offset = selectedRange.x;
if (offset > 0) {
IDocument document = structuredTextViewer.getDocument();
char previousChar = document.getChar(offset - 1);
if (previousChar == '$') {
structuredTextViewer.setSelectedRange(offset - 1, selectedRange.y + 1);
// handle one letter variable name selection (the default just
// selectes the $ sign)
} else if (selectedRange.y == 1 && document.getChar(offset) == '$') {
structuredTextViewer.setSelectedRange(offset, selectedRange.y + 1);
}
}
}
}