9a38d3bd3d8e410f3196fd17d2a5677d3c4cfdbe
[phpeclipse.git] / net.sourceforge.phpeclipse.ui / src / net / sourceforge / phpeclipse / phpeditor / php / PHPDoubleClickSelector.java
1 /**********************************************************************
2  Copyright (c) 2000, 2002 IBM Corp. and others.
3  All rights reserved. This program and the accompanying materials
4  are made available under the terms of the Common Public License v1.0
5  which accompanies this distribution, and is available at
6  http://www.eclipse.org/legal/cpl-v10.html
7
8  Contributors:
9  IBM Corporation - Initial implementation
10  www.phpeclipse.de
11  **********************************************************************/
12 package net.sourceforge.phpeclipse.phpeditor.php;
13
14 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
15
16 import org.eclipse.jface.text.BadLocationException;
17 import org.eclipse.jface.text.IDocument;
18 import org.eclipse.jface.text.ITextDoubleClickStrategy;
19 import org.eclipse.jface.text.ITextViewer;
20
21 /**
22  * Double click strategy aware of PHP identifier syntax rules.
23  */
24 public class PHPDoubleClickSelector implements ITextDoubleClickStrategy {
25
26         protected ITextViewer fText;
27
28         protected int fPos;
29
30         protected int fStartPos;
31
32         protected int fEndPos;
33
34         protected static char[] fgBrackets = { '{', '}', '(', ')', '[', ']', '"',
35                         '"' };
36
37         /*
38          * Create a PHPDoubleClickSelector.
39          */
40         public PHPDoubleClickSelector() {
41                 super();
42         }
43
44         /*
45          * (non-Javadoc) Method declared on ITextDoubleClickStrategy
46          */
47         public void doubleClicked(ITextViewer text) {
48
49                 fPos = text.getSelectedRange().x;
50
51                 if (fPos < 0)
52                         return;
53
54                 fText = text;
55
56                 if (!selectBracketBlock())
57                         selectWord();
58         }
59
60         /**
61          * Match the brackets at the current selection. Return true if successful,
62          * false otherwise.
63          */
64         protected boolean matchBracketsAt() {
65
66                 char prevChar, nextChar;
67
68                 int i;
69                 int bracketIndex1 = fgBrackets.length;
70                 int bracketIndex2 = fgBrackets.length;
71
72                 fStartPos = -1;
73                 fEndPos = -1;
74
75                 // get the chars preceding and following the start position
76                 try {
77
78                         IDocument doc = fText.getDocument();
79
80                         prevChar = doc.getChar(fPos - 1);
81                         nextChar = doc.getChar(fPos);
82
83                         // is the char either an open or close bracket?
84                         for (i = 0; i < fgBrackets.length; i = i + 2) {
85                                 if (prevChar == fgBrackets[i]) {
86                                         fStartPos = fPos - 1;
87                                         bracketIndex1 = i;
88                                 }
89                         }
90                         for (i = 1; i < fgBrackets.length; i = i + 2) {
91                                 if (nextChar == fgBrackets[i]) {
92                                         fEndPos = fPos;
93                                         bracketIndex2 = i;
94                                 }
95                         }
96
97                         if (fStartPos > -1 && bracketIndex1 < bracketIndex2) {
98                                 fEndPos = searchForClosingBracket(fStartPos, prevChar,
99                                                 fgBrackets[bracketIndex1 + 1], doc);
100                                 if (fEndPos > -1)
101                                         return true;
102                                 else
103                                         fStartPos = -1;
104                         } else if (fEndPos > -1) {
105                                 fStartPos = searchForOpenBracket(fEndPos,
106                                                 fgBrackets[bracketIndex2 - 1], nextChar, doc);
107                                 if (fStartPos > -1)
108                                         return true;
109                                 else
110                                         fEndPos = -1;
111                         }
112
113                 } catch (BadLocationException x) {
114                 }
115
116                 return false;
117         }
118
119         /**
120          * Select the word at the current selection. Return true if successful,
121          * false otherwise.
122          */
123         protected boolean matchWord() {
124
125                 IDocument doc = fText.getDocument();
126
127                 try {
128
129                         int pos = fPos;
130                         char c;
131
132                         while (pos >= 0) {
133                                 c = doc.getChar(pos);
134                                 if (!Scanner.isPHPIdentifierPart(c) && (c != '$')) {
135                                         break;
136                                 }
137                                 --pos;
138                         }
139
140                         fStartPos = pos;
141
142                         pos = fPos;
143                         int length = doc.getLength();
144
145                         while (pos < length) {
146                                 c = doc.getChar(pos);
147                                 if (!Scanner.isPHPIdentifierPart(c) && (c != '$'))
148                                         break;
149                                 ++pos;
150                         }
151
152                         fEndPos = pos;
153
154                         return true;
155
156                 } catch (BadLocationException x) {
157                 }
158
159                 return false;
160         }
161
162         /**
163          * Returns the position of the closing bracket after startPosition.
164          * 
165          * @returns the location of the closing bracket.
166          * @param startPosition -
167          *            the beginning position
168          * @param openBracket -
169          *            the character that represents the open bracket
170          * @param closeBracket -
171          *            the character that represents the close bracket
172          * @param document -
173          *            the document being searched
174          */
175         protected int searchForClosingBracket(int startPosition, char openBracket,
176                         char closeBracket, IDocument document) throws BadLocationException {
177                 int stack = 1;
178                 int closePosition = startPosition + 1;
179                 int length = document.getLength();
180                 char nextChar;
181
182                 while (closePosition < length && stack > 0) {
183                         nextChar = document.getChar(closePosition);
184                         if (nextChar == openBracket && nextChar != closeBracket)
185                                 stack++;
186                         else if (nextChar == closeBracket)
187                                 stack--;
188                         closePosition++;
189                 }
190
191                 if (stack == 0)
192                         return closePosition - 1;
193                 else
194                         return -1;
195
196         }
197
198         /**
199          * Returns the position of the open bracket before startPosition.
200          * 
201          * @returns the location of the starting bracket.
202          * @param startPosition -
203          *            the beginning position
204          * @param openBracket -
205          *            the character that represents the open bracket
206          * @param closeBracket -
207          *            the character that represents the close bracket
208          * @param document -
209          *            the document being searched
210          */
211         protected int searchForOpenBracket(int startPosition, char openBracket,
212                         char closeBracket, IDocument document) throws BadLocationException {
213                 int stack = 1;
214                 int openPos = startPosition - 1;
215                 char nextChar;
216
217                 while (openPos >= 0 && stack > 0) {
218                         nextChar = document.getChar(openPos);
219                         if (nextChar == closeBracket && nextChar != openBracket)
220                                 stack++;
221                         else if (nextChar == openBracket)
222                                 stack--;
223                         openPos--;
224                 }
225
226                 if (stack == 0)
227                         return openPos + 1;
228                 else
229                         return -1;
230         }
231
232         /**
233          * Select the area between the selected bracket and the closing bracket.
234          * Return true if successful.
235          */
236         protected boolean selectBracketBlock() {
237                 if (matchBracketsAt()) {
238
239                         if (fStartPos == fEndPos)
240                                 fText.setSelectedRange(fStartPos, 0);
241                         else
242                                 fText.setSelectedRange(fStartPos + 1, fEndPos - fStartPos - 1);
243
244                         return true;
245                 }
246                 return false;
247         }
248
249         /**
250          * Select the word at the current selection.
251          */
252         protected void selectWord() {
253                 if (matchWord()) {
254
255                         if (fStartPos == fEndPos)
256                                 fText.setSelectedRange(fStartPos, 0);
257                         else
258                                 fText.setSelectedRange(fStartPos + 1, fEndPos - fStartPos - 1);
259                 }
260         }
261 }