X-Git-Url: http://git.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/php/PHPPartitionScanner.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/php/PHPPartitionScanner.java index bebcc1f..54eaa7d 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/php/PHPPartitionScanner.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/php/PHPPartitionScanner.java @@ -1,554 +1,377 @@ -/********************************************************************** -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 - Klaus Hartlage - www.eclipseproject.de -**********************************************************************/ +/** + * 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.15 $ + */ package net.sourceforge.phpeclipse.phpeditor.php; -import java.io.CharArrayWriter; -import java.util.ArrayList; -import java.util.List; +import java.util.*; -import org.eclipse.jface.text.rules.ICharacterScanner; -import org.eclipse.jface.text.rules.IPredicateRule; -import org.eclipse.jface.text.rules.IToken; -import org.eclipse.jface.text.rules.IWordDetector; -import org.eclipse.jface.text.rules.MultiLineRule; -import org.eclipse.jface.text.rules.RuleBasedPartitionScanner; -import org.eclipse.jface.text.rules.Token; -import org.eclipse.jface.text.rules.WordRule; +import org.eclipse.jface.text.*; +import org.eclipse.jface.text.rules.*; /** - * This scanner recognizes the JavaDoc comments and Java multi line comments. + * */ -public class PHPPartitionScanner extends RuleBasedPartitionScanner { - - private final static String SKIP = "__skip"; //$NON-NLS-1$ - public final static String HTML_MULTILINE_COMMENT = "__html_multiline_comment"; //$NON-NLS-1$ - // public final static String JAVA_DOC= "__java_javadoc"; //$NON-NLS-1$ - public final static String PHP = "__php"; -// public final static String HTML = "__html"; - - public final static IToken php = new Token(PHP); -// public final static IToken html = new Token(HTML); - public final static IToken comment = new Token(HTML_MULTILINE_COMMENT); +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(); - protected final static char[] php0EndSequence = { '<', '?' }; - protected final static char[] php1EndSequence = { '<', '?', 'p', 'h', 'p' }; - protected final static char[] php2EndSequence = { '<', '?', 'P', 'H', 'P' }; - private StringBuffer test; - - public class PHPMultiLineRule extends MultiLineRule { + 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)); + } - public PHPMultiLineRule(String startSequence, String endSequence, IToken token) { - super(startSequence, endSequence, token); + 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; + } - public PHPMultiLineRule(String startSequence, String endSequence, IToken token, char escapeCharacter) { - super(startSequence, endSequence, token, escapeCharacter); +/* (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); } - - protected boolean endSequenceDetected(ICharacterScanner scanner) { - int c; - int c2; - - boolean lineCommentMode = false; - boolean multiLineCommentMode = false; - boolean stringMode = false; - - char[][] delimiters = scanner.getLegalLineDelimiters(); - while ((c = scanner.read()) != ICharacterScanner.EOF) { - if (lineCommentMode && (c == '\n')) { - lineCommentMode = false; - // read until end of line - } else if ((!stringMode) && (c == '#')) { - // read until end of line - lineCommentMode = true; - continue; - } else if ((!stringMode) && (!multiLineCommentMode) && (c == '/')) { - c2 = scanner.read(); - if (c2 == '/') { - lineCommentMode = true; - continue; - } else if (c2 == '*') { - multiLineCommentMode = true; - continue; - } else { - scanner.unread(); - } - } else if (c == '*' && multiLineCommentMode) { - c2 = scanner.read(); - if (c2 == '/') { - multiLineCommentMode = false; - continue; - } else { - scanner.unread(); - } - } else if (c == '\\' && stringMode) { - c2 = scanner.read(); - if (c2 == '"') { - continue; - } else { - scanner.unread(); - } - } else if ((!lineCommentMode) && (!multiLineCommentMode) && (c == '"')) { - if (stringMode) { - stringMode = false; - } else { - stringMode = true; - } - continue; + + if(offset == partitionOffset) + { + try + { + fContentType = fDocument.getContentType(offset); } - if (lineCommentMode || multiLineCommentMode || stringMode) { - continue; - } - - if (c == fEscapeCharacter) { - // Skip the escaped character. - scanner.read(); - } else if (fEndSequence.length > 0 && c == fEndSequence[0]) { - // Check if the specified end sequence has been found. - if (sequenceDetected(scanner, fEndSequence, true)) - return true; - } else if (fBreaksOnEOL) { - // Check for end of line since it can be used to terminate the pattern. - for (int i = 0; i < delimiters.length; i++) { - if (c == delimiters[i][0] && sequenceDetected(scanner, delimiters[i], false)) - return true; - } + catch (BadLocationException e) + { + //should never happen } - } - scanner.unread(); - return false; - } - } - -// public class HTMLMultiLineRule extends MultiLineRule { -// -// public HTMLMultiLineRule(String startSequence, String endSequence, IToken token) { -// super(startSequence, endSequence, token); -// } -// -// public HTMLMultiLineRule(String startSequence, String endSequence, IToken token, char escapeCharacter) { -// super(startSequence, endSequence, token, escapeCharacter); -// } -// -// protected boolean endSequenceDetected(ICharacterScanner scanner) { -// int c; -// -// char[][] delimiters = scanner.getLegalLineDelimiters(); -// while ((c = scanner.read()) != ICharacterScanner.EOF) { -// if (c == '<') { -// // scanner.unread(); -// if (sequenceDetected(scanner, php2EndSequence, true)) { -// // null is a legal value - * @param token the token which will be returned on success - * @param escapeCharacter any character following this one will be ignored - * @param indicates whether the end of the line also termines the pattern - */ - public HTMLPatternRule(IToken token) { - fToken = token; - fEscapeCharacter = (char)0; - fBreaksOnEOL = false; - } - - /** - * Sets a column constraint for this rule. If set, the rule's token - * will only be returned if the pattern is detected starting at the - * specified column. If the column is smaller then 0, the column - * constraint is considered removed. - * - * @param column the column in which the pattern starts - */ - public void setColumnConstraint(int column) { - if (column < 0) - column = UNDEFINED; - fColumn = column; - } - - /** - * Evaluates this rules without considering any column constraints. - * - * @param scanner the character scanner to be used - * @return the token resulting from this evaluation - */ - protected IToken doEvaluate(ICharacterScanner scanner) { - return doEvaluate(scanner, false); + } + else if (this.tokens.containsKey(contentType)) + fContentType = contentType; + // TODO Calculate previouse contenttype + if (partitionOffset > -1) + { + partitionBorder = false; + fTokenOffset = partitionOffset; } +} - /** - * Evaluates this rules without considering any column constraints. Resumes - * detection, i.e. look sonly for the end sequence required by this rule if the - * resume flag is set. - * - * @param scanner the character scanner to be used - * @param resume true if detection should be resumed, false otherwise - * @return the token resulting from this evaluation - * @since 2.0 - */ - protected IToken doEvaluate(ICharacterScanner scanner, boolean resume) { - - if (resume) { - - if (endSequenceDetected(scanner)) - return fToken; - - } else { + /* (non-Javadoc) + * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenLength() + */ + public int getTokenLength() { + return fLength; + } - int c = scanner.read(); - // if (c == fStartSequence[0]) { - // if (sequenceDetected(scanner, fStartSequence, false)) { - if (endSequenceDetected(scanner)) - return fToken; - // } - // } - } + /* (non-Javadoc) + * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenOffset() + */ + public int getTokenOffset() { + return fTokenOffset; + } - scanner.unread(); - return Token.UNDEFINED; +/* (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(); - /* - * @see IRule#evaluate - */ - public IToken evaluate(ICharacterScanner scanner) { - return evaluate(scanner, false); + if (partitionBorder) + { + fTokenOffset = fOffset; + partitionBorder = false; } - /** - * Returns whether the end sequence was detected. As the pattern can be considered - * ended by a line delimiter, the result of this method is true if the - * rule breaks on the end of the line, or if the EOF character is read. - * - * @param scanner the character scanner to be used - * @return true if the end sequence has been detected - */ - protected boolean endSequenceDetected(ICharacterScanner scanner) { - int c; - - char[][] delimiters = scanner.getLegalLineDelimiters(); - while ((c = scanner.read()) != ICharacterScanner.EOF) { - if (c == '<') { - // scanner.unread(); - if (sequenceDetected(scanner, php2EndSequence, true)) { - // 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 ( + fContentType + != IPHPPartitionScannerConstants.PHP_MULTILINE_COMMENT + && checkPattern(new char[] { '?' }, false)) + { + if (fContentType != IPHPPartitionScannerConstants.PHP + && fOffset - 2 > 0) + { + fOffset -= 2; + 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 - 2; + } + 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); } - - } - scanner.unread(); - return false; - } - - /** - * Returns whether the next characters to be read by the character scanner - * are an exact match with the given sequence. No escape characters are allowed - * within the sequence. If specified the sequence is considered to be found - * when reading the EOF character. - * - * @param scanner the character scanner to be used - * @param sequence the sequence to be detected - * @param eofAllowed indicated whether EOF terminates the pattern - * @return true if the given sequence has been detected - */ - protected boolean sequenceDetected(ICharacterScanner scanner, char[] sequence, boolean eofAllowed) { - for (int i = 1; i < sequence.length; i++) { - int c = scanner.read(); - if (c == ICharacterScanner.EOF && eofAllowed) { - return true; - } else if (c != sequence[i]) { - // Non-matching character detected, rewind the scanner back to the start. - scanner.unread(); - for (int j = i - 1; j > 0; j--) - scanner.unread(); - return false; - } - } - - return true; + /* (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); } - /* - * @see IPredicateRule#evaluate(ICharacterScanner, boolean) - * @since 2.0 - */ - public IToken evaluate(ICharacterScanner scanner, boolean resume) { - if (fColumn == UNDEFINED) - return doEvaluate(scanner, resume); - - int c = scanner.read(); - scanner.unread(); - // if (c == fStartSequence[0]) - return (fColumn == scanner.getColumn() ? doEvaluate(scanner, resume) : Token.UNDEFINED); - // else - // return Token.UNDEFINED; - } + fDocument = document; + fOffset = offset; + fTokenOffset = offset; + fLength = 0; + fEnd = fOffset + length; + //partitionBorder = false; + } - /* - * @see IPredicateRule#getSuccessToken() - * @since 2.0 - */ - public IToken getSuccessToken() { - return fToken; + 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; } } - /** - * Detector for empty comments. - */ - static class EmptyCommentDetector implements IWordDetector { - /* (non-Javadoc) - * Method declared on IWordDetector - */ - public boolean isWordStart(char c) { - return (c == '/'); - } + private void unread() { + --fOffset; + } - /* (non-Javadoc) - * Method declared on IWordDetector - */ - public boolean isWordPart(char c) { - return (c == '*' || c == '/'); - } - }; + 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. */ - static class WordPredicateRule extends WordRule implements IPredicateRule { - - private IToken fSuccessToken; - - public WordPredicateRule(IToken successToken) { - super(new EmptyCommentDetector()); - fSuccessToken = successToken; - addWord("/**/", fSuccessToken); - } - - /* - * @see org.eclipse.jface.text.rules.IPredicateRule#evaluate(ICharacterScanner, boolean) - */ - public IToken evaluate(ICharacterScanner scanner, boolean resume) { - return super.evaluate(scanner); - } - - /* - * @see org.eclipse.jface.text.rules.IPredicateRule#getSuccessToken() - */ - public IToken getSuccessToken() { - return fSuccessToken; + 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; + } } - }; - - /** - * Creates the partitioner and sets up the appropriate rules. - */ - public PHPPartitionScanner() { - super(); - - // IToken php = new Token(PHP); - // IToken html = new Token(HTML); - // IToken comment = new Token(HTML_MULTILINE_COMMENT); - List rules = new ArrayList(); - - // Add rule for single line comments. - // rules.add(new EndOfLineRule("//", Token.UNDEFINED)); - - // Add rule for strings and character constants. - // rules.add(new SingleLineRule("\"", "\"", Token.UNDEFINED, '\\')); - // rules.add(new SingleLineRule("'", "'", Token.UNDEFINED, '\\')); - - // Add special case word rule. -// rules.add(new WordPredicateRule(comment)); - - // Add rules for multi-line comments and javadoc. - //rules.add(new MultiLineRule("/**", "*/", javaDoc)); - // rules.add(new HTMLMultiLineRule("<", "", comment)); - rules.add(new PHPMultiLineRule("", php)); - rules.add(new PHPMultiLineRule("", php)); - rules.add(new PHPMultiLineRule("", php)); - rules.add(new PHPMultiLineRule("", php)); - rules.add(new PHPMultiLineRule("", php)); - rules.add(new PHPMultiLineRule("", php)); + return true; + } -// rules.add(new HTMLPatternRule(html)); // "<", "