/** * 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 * Created on 05.03.2003 * * @author Stefan Langer (musk) * @version $Revision: 1.10 $ */ package net.sourceforge.phpeclipse.phpeditor.php; import java.util.*; import org.eclipse.jface.text.*; import org.eclipse.jface.text.rules.*; /** * */ public class PHPPartitionScanner implements IPartitionTokenScanner { // private final int HTML = 0; // private final int PHP = 1; // private final int JS = 2; // private final int CSS = 4; // private final int COMMENT = 5; // private final int HTMLCOMMENT = 6; private IDocument fDocument = null; private int fOffset = -1; // private int fLastOffset = -1; private String fContentType = IPHPPartitionScannerConstants.HTML; private boolean partitionBorder = false; private int fTokenOffset; private int fEnd = -1; private int fLength; //private int fState = HTML; private Map tokens = new HashMap(); public PHPPartitionScanner() { this.tokens.put( IPHPPartitionScannerConstants.PHP, new Token(IPHPPartitionScannerConstants.PHP)); this.tokens.put( IPHPPartitionScannerConstants.PHP_MULTILINE_COMMENT, new Token(IPHPPartitionScannerConstants.PHP_MULTILINE_COMMENT)); this.tokens.put( IPHPPartitionScannerConstants.HTML, new Token(IPHPPartitionScannerConstants.HTML)); this.tokens.put( IPHPPartitionScannerConstants.HTML_MULTILINE_COMMENT, new Token(IPHPPartitionScannerConstants.HTML_MULTILINE_COMMENT)); } private IToken getToken(String type) { fLength = fOffset-fTokenOffset; IToken token = (IToken)this.tokens.get(type); Assert.isNotNull(token, "Token for type \"" + type + "\" not found!"); return token; } /* (non-Javadoc) * @see org.eclipse.jface.text.rules.IPartitionTokenScanner#setPartialRange(org.eclipse.jface.text.IDocument, int, int, java.lang.String, int) */ public void setPartialRange( IDocument document, int offset, int length, String contentType, int partitionOffset) { this.setRange(document, offset, length); if(this.tokens.containsKey(contentType)) fContentType = contentType; if (partitionOffset > -1) { partitionBorder = false; fTokenOffset = partitionOffset; } } /* (non-Javadoc) * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenLength() */ public int getTokenLength() { return fLength; } /* (non-Javadoc) * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenOffset() */ public int getTokenOffset() { return fTokenOffset; } /* (non-Javadoc) * @see org.eclipse.jface.text.rules.ITokenScanner#nextToken() */ public IToken nextToken() { int c; // check if we are not allready at the end of the // file if ((c = read()) == ICharacterScanner.EOF) { partitionBorder = false; return Token.EOF; } else unread(); if (partitionBorder) { fTokenOffset = fOffset; partitionBorder = false; } while ((c = read()) != ICharacterScanner.EOF) { switch (c) { case '<' : if (fContentType != IPHPPartitionScannerConstants.PHP_MULTILINE_COMMENT && checkPattern(new char[] { '?', 'p', 'h', 'p' }, true)) { if (fContentType != IPHPPartitionScannerConstants.PHP && fOffset - 5 > 0) { fOffset -= 5; IToken token = getToken(fContentType); fContentType = IPHPPartitionScannerConstants.PHP; return token; } else fContentType = IPHPPartitionScannerConstants.PHP; // remember offset of this partition fTokenOffset = fOffset - 5; } else if (checkPattern(new char[] { '!', '-', '-' })) { // return previouse partition if (fContentType != IPHPPartitionScannerConstants .HTML_MULTILINE_COMMENT && fOffset - 4 > 0) { fOffset -= 4; IToken token = getToken(fContentType); fContentType = IPHPPartitionScannerConstants .HTML_MULTILINE_COMMENT; return token; } else fContentType = IPHPPartitionScannerConstants .HTML_MULTILINE_COMMENT; fTokenOffset = fOffset - 4; } break; case '?' : if (fContentType == IPHPPartitionScannerConstants.PHP) { if ((c = read()) == '>') { fContentType = IPHPPartitionScannerConstants.HTML; partitionBorder = true; return getToken(IPHPPartitionScannerConstants.PHP); } else if(c != ICharacterScanner.EOF) unread(); } break; case '-' : if (fContentType == IPHPPartitionScannerConstants.HTML_MULTILINE_COMMENT && checkPattern(new char[] { '-', '>' })) { fContentType = IPHPPartitionScannerConstants.HTML; partitionBorder = true; return getToken( IPHPPartitionScannerConstants .HTML_MULTILINE_COMMENT); } break; case '/' : if ((c=read()) == '*') { // MULTINE COMMENT JAVASCRIPT, CSS, PHP if (fContentType == IPHPPartitionScannerConstants.PHP && fOffset - 2 > 0) { fOffset -= 2; IToken token = getToken(fContentType); fContentType = IPHPPartitionScannerConstants .PHP_MULTILINE_COMMENT; return token; } else if ( fContentType == IPHPPartitionScannerConstants .PHP_MULTILINE_COMMENT) { fTokenOffset = fOffset - 2; } } else if(c != ICharacterScanner.EOF) unread(); break; case '*' : if ((c = read()) == '/') { if (fContentType == IPHPPartitionScannerConstants .PHP_MULTILINE_COMMENT) { fContentType = IPHPPartitionScannerConstants.PHP; partitionBorder = true; return getToken( IPHPPartitionScannerConstants .PHP_MULTILINE_COMMENT); } else if ( fContentType == IPHPPartitionScannerConstants .CSS_MULTILINE_COMMENT) { } else if ( fContentType == IPHPPartitionScannerConstants .JS_MULTILINE_COMMENT) { } } else if(c != ICharacterScanner.EOF) unread(); break; } } // end of file reached but we have to return the // last partition. return getToken(fContentType); } /* (non-Javadoc) * @see org.eclipse.jface.text.rules.ITokenScanner#setRange(org.eclipse.jface.text.IDocument, int, int) */ public void setRange(IDocument document, int offset, int length) { fDocument = document; fOffset = offset; fTokenOffset = offset; fLength = 0; fEnd = fOffset + length; //partitionBorder = false; } private int read() { try { if (fOffset < fEnd) { return fDocument.getChar(fOffset++); } return ICharacterScanner.EOF; } catch (BadLocationException e) { // should never happen // TODO write stacktrace to log fOffset = fEnd; return ICharacterScanner.EOF; } } private void unread() { --fOffset; } private boolean checkPattern(char[] pattern) { return checkPattern(pattern, false); } /** * Check if next character sequence read from document is equals to * the provided pattern. Pattern is read from left to right until the * first character read doesn't match. If this happens all read characters are * unread. * @param pattern The pattern to check. * @return true if pattern is equals else returns false. */ private boolean checkPattern(char[] pattern, boolean ignoreCase) { int prevOffset = fOffset; for (int i = 0; i < pattern.length; i++) { int c = read(); if(c == ICharacterScanner.EOF || !letterEquals(c, pattern[i], ignoreCase)) { fOffset = prevOffset; return false; } } return true; } private boolean letterEquals(int test, char letter, boolean ignoreCase) { if(test == letter) return true; else if(ignoreCase && Character.isLowerCase(letter) && test == Character.toUpperCase(letter)) return true; else if(ignoreCase && Character.isUpperCase(letter) && test == Character.toLowerCase(letter)) return true; return false; } }