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 8e2485d..52f8def 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 @@ -6,37 +6,41 @@ * Created on 05.03.2003 * * @author Stefan Langer (musk) - * @version $Revision: 1.10 $ + * @version $Revision: 1.19 $ */ package net.sourceforge.phpeclipse.phpeditor.php; -import java.util.*; -import org.eclipse.jface.text.*; -import org.eclipse.jface.text.rules.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jface.text.Assert; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.ITypedRegion; +import org.eclipse.jface.text.rules.ICharacterScanner; +import org.eclipse.jface.text.rules.IPartitionTokenScanner; +import org.eclipse.jface.text.rules.IToken; +import org.eclipse.jface.text.rules.Token; /** * */ 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 static final boolean DEBUG = false; + private boolean fInString = false; + private boolean fInDoubString = false; private IDocument fDocument = null; private int fOffset = -1; -// private int fLastOffset = -1; private String fContentType = IPHPPartitionScannerConstants.HTML; - - private boolean partitionBorder = false; + private String fPrevContentType = IPHPPartitionScannerConstants.HTML; + private boolean partitionBorder = false; private int fTokenOffset; private int fEnd = -1; private int fLength; - //private int fState = HTML; + private int fCurrentLength; private Map tokens = new HashMap(); public PHPPartitionScanner() @@ -53,35 +57,102 @@ public class PHPPartitionScanner implements IPartitionTokenScanner 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!"); - return token; + fLength = fCurrentLength; + if (DEBUG) + { + + try + { + if (fLength <= 0) + { + int line = fDocument.getLineOfOffset(fOffset); + System.err.println( + "Error at " + + line + + " offset:" + + String.valueOf( + fOffset - fDocument.getLineOffset(line))); + } + } + catch (BadLocationException e) + { // should never happen + // TODO Write stacktrace to log + e.printStackTrace(); + } + } + Assert.isTrue(fLength > 0, "Partition length <= 0!"); + fCurrentLength = 0; + // String can never cross partition borders so reset string detection + fInString = false; + fInDoubString = false; + 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=" + + type + + " 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(this.tokens.containsKey(contentType)) - fContentType = contentType; - if (partitionOffset > -1) + /* (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) { - partitionBorder = false; - fTokenOffset = partitionOffset; + if (DEBUG) + { + System.out.println( + "PartialRange: contentType=" + + contentType + + " partitionOffset=" + + partitionOffset); + } + + try + { + if (partitionOffset > -1) + { + partitionBorder = false; + // because of strings we have to parse the whole partition + this.setRange( + document, + partitionOffset, + offset - partitionOffset + length); + // sometimes we get a wrong partition so we retrieve the partition + // directly from the document + fContentType = fDocument.getContentType(partitionOffset); + } + else + this.setRange(document, offset, length); + + } + catch (BadLocationException e) + { + // should never happen + // TODO print stack trace to log + // fall back just scan the whole document again + this.setRange(document, 0, fDocument.getLength()); + } + } -} /* (non-Javadoc) * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenLength() @@ -95,8 +166,8 @@ public void setPartialRange( * @see org.eclipse.jface.text.rules.ITokenScanner#getTokenOffset() */ public int getTokenOffset() - { - return fTokenOffset; + { + return fTokenOffset; } /* (non-Javadoc) @@ -127,14 +198,20 @@ public void setPartialRange( switch (c) { case '<' : - if (fContentType != IPHPPartitionScannerConstants.PHP_MULTILINE_COMMENT && checkPattern(new char[] { '?', 'p', 'h', 'p' }, true)) + if (!isInString(IPHPPartitionScannerConstants.PHP) + && fContentType + != IPHPPartitionScannerConstants.PHP_MULTILINE_COMMENT + && checkPattern(new char[] { '?', 'p', 'h', 'p' }, true)) { - if (fContentType != IPHPPartitionScannerConstants.PHP - && fOffset - 5 > 0) + && fCurrentLength > 5) { - fOffset -= 5; + unread(5); IToken token = getToken(fContentType); + // save previouse contenttype + //TODO build stack for previouse contenttype + fPrevContentType = fContentType; + fContentType = IPHPPartitionScannerConstants.PHP; return token; @@ -144,16 +221,41 @@ public void setPartialRange( // remember offset of this partition fTokenOffset = fOffset - 5; + fCurrentLength = 5; } - else if (checkPattern(new char[] { '!', '-', '-' })) + else if ( + !isInString(IPHPPartitionScannerConstants.PHP) + && fContentType + != IPHPPartitionScannerConstants + .PHP_MULTILINE_COMMENT + && checkPattern(new char[] { '?' }, false)) { - // return previouse partition + if (fContentType != IPHPPartitionScannerConstants.PHP + && fCurrentLength > 2) + { + unread(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; + fCurrentLength = 2; + } + else if ( + !isInString(IPHPPartitionScannerConstants.PHP) + && checkPattern(new char[] { '!', '-', '-' })) + { // return previouse partition if (fContentType != IPHPPartitionScannerConstants .HTML_MULTILINE_COMMENT - && fOffset - 4 > 0) + && fCurrentLength > 4) { - fOffset -= 4; + unread(4); IToken token = getToken(fContentType); fContentType = IPHPPartitionScannerConstants @@ -164,26 +266,34 @@ public void setPartialRange( fContentType = IPHPPartitionScannerConstants .HTML_MULTILINE_COMMENT; - + fTokenOffset = fOffset - 4; + fCurrentLength = 4; } break; case '?' : - if (fContentType == IPHPPartitionScannerConstants.PHP) + if (!isInString(IPHPPartitionScannerConstants.PHP) + && fContentType == IPHPPartitionScannerConstants.PHP) { if ((c = read()) == '>') - { - fContentType = IPHPPartitionScannerConstants.HTML; + { + if (fPrevContentType != null) + fContentType = fPrevContentType; + else + fContentType = + IPHPPartitionScannerConstants.HTML; partitionBorder = true; return getToken(IPHPPartitionScannerConstants.PHP); } - else if(c != ICharacterScanner.EOF) + else if (c != ICharacterScanner.EOF) unread(); } break; case '-' : - if (fContentType - == IPHPPartitionScannerConstants.HTML_MULTILINE_COMMENT + if (!isInString(IPHPPartitionScannerConstants.PHP) + && fContentType + == IPHPPartitionScannerConstants + .HTML_MULTILINE_COMMENT && checkPattern(new char[] { '-', '>' })) { fContentType = IPHPPartitionScannerConstants.HTML; @@ -194,17 +304,16 @@ public void setPartialRange( } break; case '/' : - if ((c=read()) == '*') + if (!isInString(IPHPPartitionScannerConstants.PHP) && (c = read()) == '*') { // MULTINE COMMENT JAVASCRIPT, CSS, PHP if (fContentType == IPHPPartitionScannerConstants.PHP - && fOffset - 2 > 0) + && fCurrentLength > 2) { - fOffset -= 2; + unread(2); IToken token = getToken(fContentType); fContentType = IPHPPartitionScannerConstants .PHP_MULTILINE_COMMENT; - return token; } else if ( @@ -214,14 +323,15 @@ public void setPartialRange( { fTokenOffset = fOffset - 2; + fCurrentLength = 2; } } - else if(c != ICharacterScanner.EOF) + else if (!isInString(IPHPPartitionScannerConstants.PHP) && c != ICharacterScanner.EOF) unread(); break; case '*' : - if ((c = read()) == '/') + if (!isInString(IPHPPartitionScannerConstants.PHP) && (c = read()) == '/') { if (fContentType == IPHPPartitionScannerConstants @@ -246,13 +356,20 @@ public void setPartialRange( { } } - else if(c != ICharacterScanner.EOF) + else if (!isInString(IPHPPartitionScannerConstants.PHP) && c != ICharacterScanner.EOF) unread(); break; + case '\'' : + if (!fInDoubString) + fInString = !fInString; + break; + case '"' : + // toggle String mode + if (!fInString) + fInDoubString = !fInDoubString; + break; } - } - - // end of file reached but we have to return the + } // end of file reached but we have to return the // last partition. return getToken(fContentType); } @@ -261,23 +378,34 @@ public void setPartialRange( */ 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; + fCurrentLength = 0; + fLength = 0; fEnd = fOffset + length; - //partitionBorder = false; + fInString = false; + fInDoubString = false; + fContentType = IPHPPartitionScannerConstants.HTML; +// String[] prev = getPartitionStack(offset); } private int read() { try { - if (fOffset < fEnd) + if (fOffset < fEnd) { - return fDocument.getChar(fOffset++); + fCurrentLength++; + return fDocument.getChar(fOffset++); } - return ICharacterScanner.EOF; + return ICharacterScanner.EOF; } catch (BadLocationException e) { @@ -291,6 +419,13 @@ public void setPartialRange( private void unread() { --fOffset; + --fCurrentLength; + } + + private void unread(int num) + { + fOffset -= num; + fCurrentLength -= num; } private boolean checkPattern(char[] pattern) @@ -308,31 +443,93 @@ public void setPartialRange( */ private boolean checkPattern(char[] pattern, boolean ignoreCase) { - int prevOffset = fOffset; + int prevOffset = fOffset; + int prevLength = fCurrentLength; for (int i = 0; i < pattern.length; i++) { int c = read(); - - if(c == ICharacterScanner.EOF || !letterEquals(c, pattern[i], ignoreCase)) + + if (c == ICharacterScanner.EOF + || !letterEquals(c, pattern[i], ignoreCase)) { - fOffset = prevOffset; + fOffset = prevOffset; + fCurrentLength = prevLength; 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; + 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; + } + + /** + * Checks wether the offset is in a String and the specified + * contenttype is the current content type. + * Strings are delimited, mutual exclusive, by a " or by a '. + * + * @param contentType The contenttype to check. + * @return true if the current offset is in a string else + * returns false. + */ + private boolean isInString(String contentType) + { + if(fContentType == contentType) + return (fInString || fInDoubString); + else + return false; + } + + /** + * Returns the previouse partition stack for the given offset. + * + * @param offset The offset to return the previouse partitionstack for. + * + * @return The stack as a string array. + */ + private String[] getPartitionStack(int offset) + { + ArrayList types = new ArrayList(); + int tmpOffset = 0; + try + { + ITypedRegion region = fDocument.getPartition(offset); + tmpOffset = region.getOffset(); + while(tmpOffset-1 > 0) + { + region = fDocument.getPartition(tmpOffset-1); + tmpOffset = region.getOffset(); + types.add(0, region.getType()); + } + } + catch (BadLocationException e) + { + if(DEBUG) + { + e.printStackTrace(); + } + } + + String[] retVal = new String[types.size()]; - return false; + retVal = (String[])types.toArray(retVal); + return retVal; } }