/********************************************************************** Copyright (c) 2000, 2002 IBM Corp. 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 implementation www.phpeclipse.de **********************************************************************/ package net.sourceforge.phpeclipse.phpeditor.php; import net.sourceforge.phpdt.internal.compiler.parser.Scanner; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextDoubleClickStrategy; import org.eclipse.jface.text.ITextViewer; /** * Double click strategy aware of PHP identifier syntax rules. */ public class PHPDoubleClickSelector implements ITextDoubleClickStrategy { protected ITextViewer fText; protected int fPos; protected int fStartPos; protected int fEndPos; protected static char[] fgBrackets = { '{', '}', '(', ')', '[', ']', '"', '"' }; /* * Create a PHPDoubleClickSelector. */ public PHPDoubleClickSelector() { super(); } /* * (non-Javadoc) Method declared on ITextDoubleClickStrategy */ public void doubleClicked(ITextViewer text) { fPos = text.getSelectedRange().x; if (fPos < 0) return; fText = text; if (!selectBracketBlock()) selectWord(); } /** * Match the brackets at the current selection. Return true if successful, * false otherwise. */ protected boolean matchBracketsAt() { char prevChar, nextChar; int i; int bracketIndex1 = fgBrackets.length; int bracketIndex2 = fgBrackets.length; fStartPos = -1; fEndPos = -1; // get the chars preceding and following the start position try { IDocument doc = fText.getDocument(); prevChar = doc.getChar(fPos - 1); nextChar = doc.getChar(fPos); // is the char either an open or close bracket? for (i = 0; i < fgBrackets.length; i = i + 2) { if (prevChar == fgBrackets[i]) { fStartPos = fPos - 1; bracketIndex1 = i; } } for (i = 1; i < fgBrackets.length; i = i + 2) { if (nextChar == fgBrackets[i]) { fEndPos = fPos; bracketIndex2 = i; } } if (fStartPos > -1 && bracketIndex1 < bracketIndex2) { fEndPos = searchForClosingBracket(fStartPos, prevChar, fgBrackets[bracketIndex1 + 1], doc); if (fEndPos > -1) return true; else fStartPos = -1; } else if (fEndPos > -1) { fStartPos = searchForOpenBracket(fEndPos, fgBrackets[bracketIndex2 - 1], nextChar, doc); if (fStartPos > -1) return true; else fEndPos = -1; } } catch (BadLocationException x) { } return false; } /** * Select the word at the current selection. Return true if successful, * false otherwise. */ protected boolean matchWord() { IDocument doc = fText.getDocument(); try { int pos = fPos; char c; while (pos >= 0) { c = doc.getChar(pos); if (!Scanner.isPHPIdentifierPart(c) && (c != '$')) { break; } --pos; } fStartPos = pos; pos = fPos; int length = doc.getLength(); while (pos < length) { c = doc.getChar(pos); if (!Scanner.isPHPIdentifierPart(c) && (c != '$')) break; ++pos; } fEndPos = pos; return true; } catch (BadLocationException x) { } return false; } /** * Returns the position of the closing bracket after startPosition. * * @returns the location of the closing bracket. * @param startPosition - * the beginning position * @param openBracket - * the character that represents the open bracket * @param closeBracket - * the character that represents the close bracket * @param document - * the document being searched */ protected int searchForClosingBracket(int startPosition, char openBracket, char closeBracket, IDocument document) throws BadLocationException { int stack = 1; int closePosition = startPosition + 1; int length = document.getLength(); char nextChar; while (closePosition < length && stack > 0) { nextChar = document.getChar(closePosition); if (nextChar == openBracket && nextChar != closeBracket) stack++; else if (nextChar == closeBracket) stack--; closePosition++; } if (stack == 0) return closePosition - 1; else return -1; } /** * Returns the position of the open bracket before startPosition. * * @returns the location of the starting bracket. * @param startPosition - * the beginning position * @param openBracket - * the character that represents the open bracket * @param closeBracket - * the character that represents the close bracket * @param document - * the document being searched */ protected int searchForOpenBracket(int startPosition, char openBracket, char closeBracket, IDocument document) throws BadLocationException { int stack = 1; int openPos = startPosition - 1; char nextChar; while (openPos >= 0 && stack > 0) { nextChar = document.getChar(openPos); if (nextChar == closeBracket && nextChar != openBracket) stack++; else if (nextChar == openBracket) stack--; openPos--; } if (stack == 0) return openPos + 1; else return -1; } /** * Select the area between the selected bracket and the closing bracket. * Return true if successful. */ protected boolean selectBracketBlock() { if (matchBracketsAt()) { if (fStartPos == fEndPos) fText.setSelectedRange(fStartPos, 0); else fText.setSelectedRange(fStartPos + 1, fEndPos - fStartPos - 1); return true; } return false; } /** * Select the word at the current selection. */ protected void selectWord() { if (matchWord()) { if (fStartPos == fEndPos) fText.setSelectedRange(fStartPos, 0); else fText.setSelectedRange(fStartPos + 1, fEndPos - fStartPos - 1); } } }