1) Moved net.sourceforge.phpeclipse.ui\src\net\sourceforge\phpdt back to net.sourcefo...
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / ui / text / PHPCodeReader.java
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/PHPCodeReader.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/PHPCodeReader.java
new file mode 100644 (file)
index 0000000..96d65c8
--- /dev/null
@@ -0,0 +1,330 @@
+package net.sourceforge.phpdt.internal.ui.text;
+
+/*
+ * (c) Copyright IBM Corp. 2000, 2001.
+ * All Rights Reserved.
+ */
+
+import java.io.IOException;
+
+import net.sourceforge.phpdt.internal.corext.phpdoc.SingleCharReader;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+
+/**
+ * Reads from a document either forwards or backwards. May be configured to skip
+ * comments and strings.
+ */
+public class PHPCodeReader extends SingleCharReader {
+
+       /** The EOF character */
+       public static final int EOF = -1;
+       private boolean fSkipComments = false;
+       private boolean fSkipStrings  = false;
+       private boolean fForward      = false;
+       
+       private IDocument fDocument;
+       
+       private int fOffset;                           // The current text position within the editor's text
+       private int fEnd              = -1;
+       private int fCachedLineNumber = -1;            // Holds the last line we checked for single line comments
+
+       public PHPCodeReader() {
+       }
+
+       /**
+        * Returns the offset of the last read character. Should only be called
+        * after read has been called.
+        */
+       public int getOffset() {
+               return fForward ? fOffset - 1 : fOffset;
+       }
+
+       public void configureForwardReader(IDocument document, int offset,
+                       int length, boolean skipComments, boolean skipStrings)
+                       throws IOException {
+               fDocument = document;
+               fOffset = offset;
+               fSkipComments = skipComments;
+               fSkipStrings = skipStrings;
+
+               fForward = true;
+               fEnd = Math.min(fDocument.getLength(), fOffset + length);
+       }
+
+       public void configureBackwardReader(IDocument document, int offset,
+                       boolean skipComments, boolean skipStrings) throws IOException {
+               fDocument = document;
+               fOffset = offset;
+               fSkipComments = skipComments;
+               fSkipStrings = skipStrings;
+
+               fForward = false;
+               try {
+                       fCachedLineNumber = fDocument.getLineOfOffset(fOffset);
+               } catch (BadLocationException x) {
+                       throw new IOException(x.getMessage());
+               }
+       }
+
+       /*
+        * @see Reader#close()
+        */
+       public void close() throws IOException {
+               fDocument = null;
+       }
+
+       /*
+        * @see SingleCharReader#read()
+        */
+       public int read() throws IOException {
+               try {
+                       return fForward ? readForwards() : readBackwards();
+               } catch (BadLocationException x) {
+                       throw new IOException(x.getMessage());
+               }
+       }
+
+       private int gotoCommentEnd (int nTextPos) throws BadLocationException {
+               while (nTextPos < fEnd) {
+                       char current = fDocument.getChar (nTextPos++);
+                       
+                       if (current == '*') {
+                               if ((nTextPos < fEnd) && 
+                                   (fDocument.getChar (nTextPos) == '/')) {
+                                       ++nTextPos;
+                                       
+                                       return nTextPos;
+                               }
+                       }
+               }
+               
+               return nTextPos;
+       }
+
+       /**
+        * 
+        * @param delimiter
+        * @throws BadLocationException
+        */
+       private int gotoStringEnd (int nTextPos, char delimiter) throws BadLocationException {
+               while (nTextPos < fEnd) {               // If long as we are not at the end of text
+                       char current = fDocument.getChar (nTextPos++);
+                       
+                       if (current == '\\') {                          // ignore escaped characters
+                               ++nTextPos;
+                       } 
+                       else if (current == delimiter) {
+                               return nTextPos;
+                       }
+               }
+               
+               return nTextPos;                        // End position
+       }
+
+       /**
+        * 
+        * @param nTextPos               The current text position
+        * 
+        * @return                       The position of the start of next line
+        * 
+        * @throws BadLocationException
+        */
+       private int gotoLineEnd (int nTextPos) throws BadLocationException {
+               int line = fDocument.getLineOfOffset (nTextPos); // Get the line number of the current text position
+               
+               return fDocument.getLineOffset (line + 1);
+       }
+
+       private int readForwards () throws BadLocationException {
+               while (fOffset < fEnd) {
+                       char current = fDocument.getChar(fOffset++);
+
+                       switch (current) {
+                           case '"':
+                           case '\'':
+                               if (fSkipStrings) {
+                                   fOffset = gotoStringEnd (fOffset, current);
+                                   continue;
+                               }
+                               return current;
+                               
+                           case '#':
+                               if (fSkipComments && fOffset < fEnd) {
+                                   fOffset = gotoLineEnd (fOffset);
+                                   continue;
+                               }
+                               return current;
+
+                           case '/':
+                               if (fSkipComments && fOffset < fEnd) {
+                                   char next = fDocument.getChar(fOffset);
+                                   
+                                   if (next == '*') {                                  // A comment starts, advance to the comment end
+                                       ++fOffset;
+                                       fOffset = gotoCommentEnd (fOffset);
+                                       continue;
+                                   } else if (next == '/') {                   // '//'-comment starts, advance to the line end
+                                       fOffset = gotoLineEnd (fOffset);
+                                       continue;
+                                   }
+                               }    
+                               return current;
+                       }
+
+                       return current;
+               }
+
+               return EOF;
+       }
+
+       /**
+        * Check whether the current line contains a single line comment.
+        * If it contains a single line comment (// or #), than set fOffset (the global character index)
+        * to the character just before the single line comment.
+        * 
+        * @throws BadLocationException
+        */
+       
+       private void handleSingleLineComment () throws BadLocationException {
+           char current;
+               int  line = fDocument.getLineOfOffset (fOffset);         // Get the line number which belongs to the current text position fOffset
+               
+               if (line < fCachedLineNumber) {                          // If we didn't parse this line already
+                       fCachedLineNumber = line;                            // Remember this line for the next time (so we don't search again!)   
+                       int nOffset       = fDocument.getLineOffset (line);  // Get the start position of current line      
+                       
+                       while (nOffset < fOffset) {                          // As long as the text position is within the current line 
+                               current = fDocument.getChar (nOffset);           // Get the character from the current text position
+
+                               switch (current) {
+                                   case '/':
+                                       if (fDocument.getChar (nOffset + 1) == '/') { // If the following character is '/'
+                                           fOffset = nOffset - 1;
+                                           
+                                           return;
+                                       }
+                                       break;    
+                                   
+                                   case '#':
+                        fOffset = nOffset - 1;
+                        return;
+                                   
+                                   case '"':                                           // It's a string start quote
+                                   case '\'':
+                                       nOffset++;                                      // Set to next character
+                                       
+                                       while (nOffset < fOffset) {                     // As long as we are within the same line
+                                           char cChar = fDocument.getChar (nOffset++);
+                                           
+                                           if (cChar == '\\') {                        // Ignore escaped characters
+                                               ++nOffset;
+                                           } 
+                                           else if (cChar == current) {                // If end of string found 
+                                               break;
+                                           }
+                                       }
+                                       break;
+                               }
+                               
+                               nOffset++;                                              // Go for the next character
+                       }
+               }
+       }
+
+       /**
+        * We search the for the block comment start sequence "/*"
+        * 
+        * The returned value points to the '/'
+        * 
+        * @throws BadLocationException
+        * 
+        * @return The new text position
+        */
+       
+       private int gotoCommentStart (int nTextPos) throws BadLocationException {
+               while (0 < nTextPos) {                                // As long as we are not at the start of the editor text
+                   char current = fDocument.getChar (nTextPos--);    // Get the character from the current text position        
+                       
+                       if ((current == '*') &&                           // If current character is a '*' 
+                           (0 <= nTextPos) &&                            // and if we are not yet at the start of the editor text 
+                           (fDocument.getChar (nTextPos) == '/')) {      // and the previous character is a '/', 
+                               return nTextPos;                              // We found the block comment start "/*"
+                       }
+               }
+               
+               return nTextPos;
+       }
+
+       /**
+        * The string closing quote has been found, when reading the editor text backwards.
+        * So we have to search for the start of the string
+        * 
+        * The returned value points to '"' or '''
+        * 
+        * @param delimiter The string double quote '"' or single ''' quote we search for
+        * 
+        * @throws BadLocationException
+        */
+       private int gotoStringStart (int nTextPos, char delimiter) throws BadLocationException {
+               while (0 < nTextPos) {                              // As long as we are not at the start of the editor text
+                       char current = fDocument.getChar (nTextPos);    // Get the character from the current text position 
+                                                                       
+                       if (current == delimiter) {                     // If we found the same character ('"' or ''') again, we have found the string start
+                               if (!(0 <= nTextPos &&                        
+                                     fDocument.getChar (nTextPos - 1) == '\\')) // If the character before the string quote is not an '/' 
+                               return nTextPos;                                 // we found the string start
+                       }
+                                                                           
+                       --nTextPos;                                          // Go one character back
+               }
+               
+               return nTextPos;
+       }
+
+       /**
+        * Read the editor text backwards
+        * 
+        */
+       
+       private int readBackwards() throws BadLocationException {
+           char current;                                                // The character on position fOffset
+           
+               while (0 < fOffset) {                                        // As long as we are not at the beginning of the editor text
+                       --fOffset;                                               // Step back one character
+
+                       handleSingleLineComment ();                              // Search for a single line comment within the current line
+                                                                                // If there is a single line comment, fOffset is set to position just before the single line comment
+
+                       current = fDocument.getChar (fOffset);                   // Read the current character
+                       switch (current) {                                       // Process the current character
+                           case '/':                                            // Is it a single line comment? 
+                               if (fSkipComments &&                             // When comments should be skipped when parsing
+                                   fOffset > 1) {                               // and if there is indeed an additional character before that '/'
+                                   char prev = fDocument.getChar (fOffset - 1); // Look at the character in front of the '/'
+                                   
+                                   if (prev == '*') {                           // If '*' than a block comment ends here, advance to the comment start
+                                       fOffset -= 2;                            // Set character pointer to character before "*/"
+                                       fOffset  = gotoCommentStart (fOffset);   // and search for the starting "/*" of the block comment
+                                       continue;
+                                   }
+                               }
+                               return current;                                  // No block comment end, so return the current character
+                               
+                           case '"':                                            // Is it a string double quote closing '"'?                                                
+                           case '\'':                                           // or a string single quote closing '''?
+                               if (fSkipStrings) {                              // If we should skip strings when parsing
+                                   --fOffset;                                   // Set pointer one before the string closing quote 
+                                   fOffset = gotoStringStart (fOffset, current);// and search the start of string ('"' or ''')
+                                   continue;
+                               }
+                               return current;                                  // No string skip, so return the current character
+                       }
+
+                       return current;                                          // No string and no comment
+               }
+
+               return EOF;                                                  // When the start of the text has been found
+       }
+}