/** * 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.11 $ */ 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 static final boolean DEBUG = false; private IDocument fDocument = null; private int fOffset = -1; private String fContentType = IPHPPartitionScannerConstants.HTML; private String fPrevContentType; private boolean partitionBorder = false; private int fTokenOffset; private int fEnd = -1; private int fLength; 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)); this.tokens.put( IDocument.DEFAULT_CONTENT_TYPE, new Token(IDocument.DEFAULT_CONTENT_TYPE)); } private IToken getToken(String type) { fLength = fOffset - fTokenOffset; IToken token = (IToken) this.tokens.get(type); Assert.isNotNull(token, "Token for type \"" + type + "\" not found!"); if (DEBUG) { System.out.println( "Partition: fTokenOffset=" + fTokenOffset + " fContentType=" + fContentType + " fLength=" + fLength); } 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 (DEBUG) { System.out.println( "PartialRange: contentType=" + contentType + " partitionOffset=" + partitionOffset); } if (this.tokens.containsKey(contentType)) fContentType = contentType; // TODO Calculate previouse 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); // save previouse contenttype fPrevContentType = 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()) == '>') { // TODO Actually calculate the previouse contenttype from the document if(fPrevContentType != null) fContentType = fPrevContentType; else 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) { if (DEBUG) { System.out.println( "SET RANGE: offset=" + offset + " length=" + 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; } }