2 * This program and the accompanying materials
3 * are made available under the terms of the Common Public License v1.0
4 * which accompanies this distribution, and is available at
5 * http://www.eclipse.org/legal/cpl-v10.html
6 * Created on 05.03.2003
8 * @author Stefan Langer (musk)
9 * @version $Revision: 1.16 $
11 package net.sourceforge.phpeclipse.phpeditor.php;
15 import org.eclipse.jface.text.*;
16 import org.eclipse.jface.text.rules.*;
21 public class PHPPartitionScanner implements IPartitionTokenScanner
23 private static final boolean DEBUG = true;
24 private boolean fInString = false;
25 private boolean fInDoubString = false;
26 private IDocument fDocument = null;
27 private int fOffset = -1;
28 private String fContentType = IPHPPartitionScannerConstants.HTML;
29 private String fPrevContentType = IPHPPartitionScannerConstants.HTML;
31 private boolean partitionBorder = false;
32 private int fTokenOffset;
33 private int fEnd = -1;
35 private int fCurrentLength;
36 private Map tokens = new HashMap();
38 public PHPPartitionScanner()
41 IPHPPartitionScannerConstants.PHP,
42 new Token(IPHPPartitionScannerConstants.PHP));
44 IPHPPartitionScannerConstants.PHP_MULTILINE_COMMENT,
45 new Token(IPHPPartitionScannerConstants.PHP_MULTILINE_COMMENT));
47 IPHPPartitionScannerConstants.HTML,
48 new Token(IPHPPartitionScannerConstants.HTML));
50 IPHPPartitionScannerConstants.HTML_MULTILINE_COMMENT,
51 new Token(IPHPPartitionScannerConstants.HTML_MULTILINE_COMMENT));
53 IDocument.DEFAULT_CONTENT_TYPE,
54 new Token(IDocument.DEFAULT_CONTENT_TYPE));
57 private IToken getToken(String type)
59 fLength = fCurrentLength;
67 int line = fDocument.getLineOfOffset(fOffset);
73 fOffset - fDocument.getLineOffset(line)));
76 catch (BadLocationException e)
78 // TODO Auto-generated catch block
82 Assert.isTrue(fLength > 0, "Partition length <= 0!");
84 // String can never cross partition borders so reset string detection
86 fInDoubString = false;
87 IToken token = (IToken) this.tokens.get(type);
88 Assert.isNotNull(token, "Token for type \"" + type + "\" not found!");
92 "Partition: fTokenOffset="
103 * @see org.eclipse.jface.text.rules.IPartitionTokenScanner#setPartialRange(org.eclipse.jface.text.IDocument, int, int, java.lang.String, int)
105 public void setPartialRange(
115 "PartialRange: contentType="
117 + " partitionOffset="
123 if (partitionOffset > -1)
125 partitionBorder = false;
126 // because of strings we have to parse the whole partition
130 offset - partitionOffset + length);
131 // sometimes we get a wrong partition so we retrieve the partition
132 // directly from the document
133 fContentType = fDocument.getContentType(partitionOffset);
134 //TODO determine the previouse contenttypes as a stack
135 //if(partitionOffset > 1)
136 // fPrevContentType = fDocument.getContentType(partitionOffset-1);
139 this.setRange(document, offset, length);
142 catch (BadLocationException e)
144 // should never happen
145 // TODO print stack trace to log
146 // fall back just scan the whole document again
147 this.setRange(document, 0, fDocument.getLength());
153 * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenLength()
155 public int getTokenLength()
161 * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenOffset()
163 public int getTokenOffset()
169 * @see org.eclipse.jface.text.rules.ITokenScanner#nextToken()
171 public IToken nextToken()
175 // check if we are not allready at the end of the
177 if ((c = read()) == ICharacterScanner.EOF)
179 partitionBorder = false;
187 fTokenOffset = fOffset;
188 partitionBorder = false;
191 while ((c = read()) != ICharacterScanner.EOF)
196 if (!isInString(IPHPPartitionScannerConstants.PHP)
198 != IPHPPartitionScannerConstants.PHP_MULTILINE_COMMENT
199 && checkPattern(new char[] { '?', 'p', 'h', 'p' }, true))
201 if (fContentType != IPHPPartitionScannerConstants.PHP
202 && fCurrentLength > 5)
205 IToken token = getToken(fContentType);
206 // save previouse contenttype
207 //TODO build stack for previouse contenttype
208 fPrevContentType = fContentType;
210 fContentType = IPHPPartitionScannerConstants.PHP;
215 fContentType = IPHPPartitionScannerConstants.PHP;
217 // remember offset of this partition
218 fTokenOffset = fOffset - 5;
222 !isInString(IPHPPartitionScannerConstants.PHP)
224 != IPHPPartitionScannerConstants
225 .PHP_MULTILINE_COMMENT
226 && checkPattern(new char[] { '?' }, false))
228 if (fContentType != IPHPPartitionScannerConstants.PHP
229 && fCurrentLength > 2)
232 IToken token = getToken(fContentType);
233 // save previouse contenttype
234 fPrevContentType = fContentType;
235 fContentType = IPHPPartitionScannerConstants.PHP;
239 fContentType = IPHPPartitionScannerConstants.PHP;
240 // remember offset of this partition
241 fTokenOffset = fOffset - 2;
245 !isInString(IPHPPartitionScannerConstants.PHP)
246 && checkPattern(new char[] { '!', '-', '-' }))
247 { // return previouse partition
249 != IPHPPartitionScannerConstants
250 .HTML_MULTILINE_COMMENT
251 && fCurrentLength > 4)
254 IToken token = getToken(fContentType);
256 IPHPPartitionScannerConstants
257 .HTML_MULTILINE_COMMENT;
262 IPHPPartitionScannerConstants
263 .HTML_MULTILINE_COMMENT;
265 fTokenOffset = fOffset - 4;
270 if (!isInString(IPHPPartitionScannerConstants.PHP)
271 && fContentType == IPHPPartitionScannerConstants.PHP)
273 if ((c = read()) == '>')
275 if (fPrevContentType != null)
276 fContentType = fPrevContentType;
279 IPHPPartitionScannerConstants.HTML;
280 partitionBorder = true;
281 return getToken(IPHPPartitionScannerConstants.PHP);
283 else if (c != ICharacterScanner.EOF)
288 if (!isInString(IPHPPartitionScannerConstants.PHP)
290 == IPHPPartitionScannerConstants
291 .HTML_MULTILINE_COMMENT
292 && checkPattern(new char[] { '-', '>' }))
294 fContentType = IPHPPartitionScannerConstants.HTML;
295 partitionBorder = true;
297 IPHPPartitionScannerConstants
298 .HTML_MULTILINE_COMMENT);
302 if (!isInString(IPHPPartitionScannerConstants.PHP) && (c = read()) == '*')
303 { // MULTINE COMMENT JAVASCRIPT, CSS, PHP
304 if (fContentType == IPHPPartitionScannerConstants.PHP
305 && fCurrentLength > 2)
308 IToken token = getToken(fContentType);
310 IPHPPartitionScannerConstants
311 .PHP_MULTILINE_COMMENT;
316 == IPHPPartitionScannerConstants
317 .PHP_MULTILINE_COMMENT)
320 fTokenOffset = fOffset - 2;
325 else if (!isInString(IPHPPartitionScannerConstants.PHP) && c != ICharacterScanner.EOF)
329 if (!isInString(IPHPPartitionScannerConstants.PHP) && (c = read()) == '/')
332 == IPHPPartitionScannerConstants
333 .PHP_MULTILINE_COMMENT)
335 fContentType = IPHPPartitionScannerConstants.PHP;
336 partitionBorder = true;
338 IPHPPartitionScannerConstants
339 .PHP_MULTILINE_COMMENT);
343 == IPHPPartitionScannerConstants
344 .CSS_MULTILINE_COMMENT)
349 == IPHPPartitionScannerConstants
350 .JS_MULTILINE_COMMENT)
354 else if (!isInString(IPHPPartitionScannerConstants.PHP) && c != ICharacterScanner.EOF)
359 fInString = !fInString;
362 // toggle String mode
364 fInDoubString = !fInDoubString;
367 } // end of file reached but we have to return the
369 return getToken(fContentType);
372 * @see org.eclipse.jface.text.rules.ITokenScanner#setRange(org.eclipse.jface.text.IDocument, int, int)
374 public void setRange(IDocument document, int offset, int length)
379 "SET RANGE: offset=" + offset + " length=" + length);
382 fDocument = document;
384 fTokenOffset = offset;
387 fEnd = fOffset + length;
389 fInDoubString = false;
390 //partitionBorder = false;
400 return fDocument.getChar(fOffset++);
402 return ICharacterScanner.EOF;
404 catch (BadLocationException e)
406 // should never happen
407 // TODO write stacktrace to log
409 return ICharacterScanner.EOF;
413 private void unread()
419 private void unread(int num)
422 fCurrentLength -= num;
425 private boolean checkPattern(char[] pattern)
427 return checkPattern(pattern, false);
431 * Check if next character sequence read from document is equals to
432 * the provided pattern. Pattern is read from left to right until the
433 * first character read doesn't match. If this happens all read characters are
435 * @param pattern The pattern to check.
436 * @return <code>true</code> if pattern is equals else returns <code>false</code>.
438 private boolean checkPattern(char[] pattern, boolean ignoreCase)
440 int prevOffset = fOffset;
441 int prevLength = fCurrentLength;
442 for (int i = 0; i < pattern.length; i++)
446 if (c == ICharacterScanner.EOF
447 || !letterEquals(c, pattern[i], ignoreCase))
449 fOffset = prevOffset;
450 fCurrentLength = prevLength;
458 private boolean letterEquals(int test, char letter, boolean ignoreCase)
464 && Character.isLowerCase(letter)
465 && test == Character.toUpperCase(letter))
469 && Character.isUpperCase(letter)
470 && test == Character.toLowerCase(letter))
477 * Checks wether the offset is in a <code>String</code> and the specified
478 * contenttype is the current content type.
479 * Strings are delimited, mutual exclusive, by a " or by a '.
481 * @param contentType The contenttype to check.
482 * @return <code>true</code> if the current offset is in a string else
485 private boolean isInString(String contentType)
487 if(fContentType == contentType)
488 return (fInString || fInDoubString);