fixed bug in template expansion
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / phpeditor / PHPContentOutlinePage.java
index e081aea..86b9977 100644 (file)
@@ -12,13 +12,11 @@ Contributors:
     Klaus Hartlage - www.eclipseproject.de
 **********************************************************************/
 
-import java.text.MessageFormat;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.BadPositionCategoryException;
 import org.eclipse.jface.text.DefaultPositionUpdater;
@@ -32,242 +30,367 @@ import org.eclipse.jface.viewers.LabelProvider;
 import org.eclipse.jface.viewers.SelectionChangedEvent;
 import org.eclipse.jface.viewers.TreeViewer;
 import org.eclipse.jface.viewers.Viewer;
-
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
 import org.eclipse.ui.texteditor.IDocumentProvider;
 import org.eclipse.ui.texteditor.ITextEditor;
 import org.eclipse.ui.views.contentoutline.ContentOutlinePage;
 
 /**
- * A content outline page which always represents the content of the
- * connected editor in 10 segments.
+ * A content outline page which always represents the functions of the
+ * connected PHPEditor.
  */
 public class PHPContentOutlinePage extends ContentOutlinePage {
+  private static final String ERROR = "error"; //$NON-NLS-1$
+  private static final String WARNING = "warning"; //$NON-NLS-1$
+  /**
+   * A segment element.
+   */
+  protected static class Segment {
+    public String name;
+    public Position position;
+
+    public Segment(String name, Position position) {
+      this.name = name;
+      this.position = position;
+    }
+
+    public String toString() {
+      return name;
+    }
+  };
+
+  protected static class SegmentComparator implements Comparator {
+    public int compare(Object o1, Object o2) {
+      return ((Segment) o1).name.compareToIgnoreCase(((Segment) o2).name);
+    }
+  }
+
+  /**
+   * Divides the editor's document into ten segments and provides elements for them.
+   */
+  protected class ContentProvider implements ITreeContentProvider {
+
+    protected final static String SEGMENTS = "__php_segments"; //$NON-NLS-1$
+    protected IPositionUpdater fPositionUpdater = new DefaultPositionUpdater(SEGMENTS);
+    protected List fContent = new ArrayList(10);
+    protected List fVariables = new ArrayList(100);
+
+    private String getIdentifier(String text, int firstIndex) {
+      int i = firstIndex;
+      char c;
+      int textLength = text.length();
+      StringBuffer identifier = new StringBuffer();
+      while (i < textLength) {
+        c = text.charAt(i++);
+        if (Character.isJavaIdentifierPart(c) || (c == '$')) {
+          identifier.append(c);
+        } else if ((i == firstIndex + 1) && (c == '$')) {
+          identifier.append(c);
+        } else {
+          return identifier.toString();
+        }
+      }
+      return null;
+    }
+
+    protected void parse(IDocument document) {
+
+      int lines = document.getNumberOfLines();
+      int increment = Math.max(Math.round((float) (lines / 10)), 10);
 
-       /**
-        * A segment element.
-        */
-       protected static class Segment {
-               public String name;
-               public Position position;
-
-               public Segment(String name, Position position) {
-                       this.name = name;
-                       this.position = position;
-               }
-
-               public String toString() {
-                       return name;
-               }
-       };
-
-       /**
-        * Divides the editor's document into ten segments and provides elements for them.
-        */
-       protected class ContentProvider implements ITreeContentProvider {
-
-               protected final static String SEGMENTS = "__php_segments"; //$NON-NLS-1$
-               protected IPositionUpdater fPositionUpdater = new DefaultPositionUpdater(SEGMENTS);
-               protected List fContent = new ArrayList(10);
-
-               protected void parse(IDocument document) {
-
-                       int lines = document.getNumberOfLines();
-                       int increment = Math.max(Math.round((float) (lines / 10)), 10);
-                       
       String text = document.get();
-                       int lastIndex = 0;
-      int i=0;
-                       lastIndex = text.indexOf("function ", lastIndex);
-                       while (lastIndex > 0) {
-
-                               try {
-          i = lastIndex+9;
-          while ((i<text.length())&&Character.isJavaIdentifierPart(text.charAt(i))) {
-            i++;
-          } 
-                                       Position p = new Position(lastIndex, i-lastIndex);
-                                       document.addPosition(SEGMENTS, p);
-                                       fContent.add(new Segment(text.substring(lastIndex,i), p));
-     //     MessageFormat.format("function", new Object[] { new Integer(lastIndex)}), p)); //$NON-NLS-1$
-                                       lastIndex = text.indexOf("function", lastIndex+1);
-                               } catch (BadLocationException e) {
-                               } catch (BadPositionCategoryException e) {
-                               }
-
-                       }
-
-                       //                      for (int line = 0; line < lines; line += increment) {
-                       //
-                       //                              int length = increment;
-                       //                              if (line + increment > lines)
-                       //                                      length = lines - line;
-                       //
-                       //                              try {
-                       //
-                       //                                      int offset = document.getLineOffset(line);
-                       //                                      int end = document.getLineOffset(line + length);
-                       //                                      length = end - offset;
-                       //                                      Position p = new Position(offset, length);
-                       //                                      document.addPosition(SEGMENTS, p);
-                       //                                      fContent.add(new Segment(MessageFormat.format(PHPEditorMessages.getString("OutlinePage.segment.title_pattern"), new Object[] { new Integer(offset)}), p)); //$NON-NLS-1$
-                       //
-                       //                              } catch (BadPositionCategoryException x) {
-                       //                              } catch (BadLocationException x) {
-                       //                              }
-                       //                      }
-               }
-
-               /*
-                * @see IContentProvider#inputChanged(Viewer, Object, Object)
-                */
-               public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
-                       if (oldInput != null) {
-                               IDocument document = fDocumentProvider.getDocument(oldInput);
-                               if (document != null) {
-                                       try {
-                                               document.removePositionCategory(SEGMENTS);
-                                       } catch (BadPositionCategoryException x) {
-                                       }
-                                       document.removePositionUpdater(fPositionUpdater);
-                               }
-                       }
-
-                       fContent.clear();
-
-                       if (newInput != null) {
-                               IDocument document = fDocumentProvider.getDocument(newInput);
-                               if (document != null) {
-                                       document.addPositionCategory(SEGMENTS);
-                                       document.addPositionUpdater(fPositionUpdater);
-
-                                       parse(document);
-                               }
-                       }
-               }
-
-               /*
-                * @see IContentProvider#dispose
-                */
-               public void dispose() {
-                       if (fContent != null) {
-                               fContent.clear();
-                               fContent = null;
-                       }
-               }
-
-               /*
-                * @see IContentProvider#isDeleted(Object)
-                */
-               public boolean isDeleted(Object element) {
-                       return false;
-               }
-
-               /*
-                * @see IStructuredContentProvider#getElements(Object)
-                */
-               public Object[] getElements(Object element) {
-                       return fContent.toArray();
-               }
-
-               /*
-                * @see ITreeContentProvider#hasChildren(Object)
-                */
-               public boolean hasChildren(Object element) {
-                       return element == fInput;
-               }
-
-               /*
-                * @see ITreeContentProvider#getParent(Object)
-                */
-               public Object getParent(Object element) {
-                       if (element instanceof Segment)
-                               return fInput;
-                       return null;
-               }
-
-               /*
-                * @see ITreeContentProvider#getChildren(Object)
-                */
-               public Object[] getChildren(Object element) {
-                       if (element == fInput)
-                               return fContent.toArray();
-                       return new Object[0];
-               }
-       };
-
-       protected Object fInput;
-       protected IDocumentProvider fDocumentProvider;
-       protected ITextEditor fTextEditor;
-
-       /**
-        * Creates a content outline page using the given provider and the given editor.
-        */
-       public PHPContentOutlinePage(IDocumentProvider provider, ITextEditor editor) {
-               super();
-               fDocumentProvider = provider;
-               fTextEditor = editor;
-       }
-
-       /* (non-Javadoc)
-        * Method declared on ContentOutlinePage
-        */
-       public void createControl(Composite parent) {
-
-               super.createControl(parent);
-
-               TreeViewer viewer = getTreeViewer();
-               viewer.setContentProvider(new ContentProvider());
-               viewer.setLabelProvider(new LabelProvider());
-               viewer.addSelectionChangedListener(this);
-
-               if (fInput != null)
-                       viewer.setInput(fInput);
-       }
-
-       /* (non-Javadoc)
-        * Method declared on ContentOutlinePage
-        */
-       public void selectionChanged(SelectionChangedEvent event) {
-
-               super.selectionChanged(event);
-
-               ISelection selection = event.getSelection();
-               if (selection.isEmpty())
-                       fTextEditor.resetHighlightRange();
-               else {
-                       Segment segment = (Segment) ((IStructuredSelection) selection).getFirstElement();
-                       int start = segment.position.getOffset();
-                       int length = segment.position.getLength();
-                       try {
-                               fTextEditor.setHighlightRange(start, length, true);
-                       } catch (IllegalArgumentException x) {
-                               fTextEditor.resetHighlightRange();
-                       }
-               }
-       }
-
-       /**
-        * Sets the input of the outline page
-        */
-       public void setInput(Object input) {
-               fInput = input;
-               update();
-       }
-
-       /**
-        * Updates the outline page.
-        */
-       public void update() {
-               TreeViewer viewer = getTreeViewer();
-
-               if (viewer != null) {
-                       Control control = viewer.getControl();
-                       if (control != null && !control.isDisposed()) {
-                               control.setRedraw(false);
-                               viewer.setInput(fInput);
-                               viewer.expandAll();
-                               control.setRedraw(true);
-                       }
-               }
-       }
+      int lastIndex = 0;
+      int i = 0;
+      //      lastIndex = text.indexOf("function ", lastIndex);
+      //      while (lastIndex > 0) {
+      //
+      //        try {
+      //          i = lastIndex + 9;
+      //          while ((i < text.length()) && Character.isJavaIdentifierPart(text.charAt(i))) {
+      //            i++;
+      //          }
+      //          Position p = new Position(lastIndex, i - lastIndex);
+      //          document.addPosition(SEGMENTS, p);
+      //          fContent.add(new Segment(text.substring(lastIndex, i), p));
+      //          //     MessageFormat.format("function", new Object[] { new Integer(lastIndex)}), p)); //$NON-NLS-1$
+      //          lastIndex = text.indexOf("function", lastIndex + 1);
+      //        } catch (BadLocationException e) {
+      //        } catch (BadPositionCategoryException e) {
+      //        }
+      //
+      //      }
+
+      boolean lineCommentMode = false;
+      boolean multiLineCommentMode = false;
+      boolean stringMode = false;
+      boolean functionMode = false;
+      String identifier;
+      int c;
+      int c2;
+
+      int textLength = text.length() - 10;
+      while (i < textLength) {
+        c = text.charAt(i++);
+        if (c == '\n') {
+          lineCommentMode = false;
+          // read until end of line
+        } else if (c == '#') {
+          // read until end of line
+          lineCommentMode = true;
+          continue;
+        } else if (c == '/') {
+          c2 = text.charAt(i++);
+          if (c2 == '/') {
+            lineCommentMode = true;
+            continue;
+          } else if (c2 == '*') {
+            multiLineCommentMode = true;
+            continue;
+          } else {
+            i--;
+          }
+        } else if (c == '*' && multiLineCommentMode) {
+          c2 = text.charAt(i++);
+          if (c2 == '/') {
+            multiLineCommentMode = false;
+            continue;
+          } else {
+            i--;
+          }
+        } else if (c == '\\' && stringMode) {
+          c2 = text.charAt(i++);
+          if (c2 == '"') {
+            continue;
+          } else {
+            i--;
+          }
+        } else if (c == '"') {
+          if (stringMode) {
+            stringMode = false;
+          } else {
+            stringMode = true;
+          }
+          continue;
+        }
+        if (lineCommentMode || multiLineCommentMode || stringMode) {
+          continue;
+        }
+
+        if (functionMode && Character.isJavaIdentifierPart((char) c)) {
+          functionMode = false;
+          lastIndex = i - 1;
+          identifier = getIdentifier(text, lastIndex);
+          try {
+            i += identifier.length() - 1;
+            Position p = new Position(lastIndex, i - lastIndex);
+            document.addPosition(SEGMENTS, p);
+            fContent.add(new Segment(text.substring(lastIndex, i), p));
+            //     MessageFormat.format("function", new Object[] { new Integer(lastIndex)}), p)); //$NON-NLS-1$
+            //    lastIndex = text.indexOf("function", lastIndex + 1);
+          } catch (BadLocationException e) {
+          } catch (BadPositionCategoryException e) {
+          }
+
+        } else if (c == 'f') {
+          identifier = getIdentifier(text, i - 1);
+          if (identifier.equals("function")) {
+            functionMode = true;
+            i += 8;
+          }
+        } else if (c == '$') {
+          // get the variable name
+          identifier = getIdentifier(text, i - 1);
+          fVariables.add(identifier);
+        }
+
+      }
+      Collections.sort(fContent, new SegmentComparator());
+      Collections.sort(fVariables);
+
+      //                       for (int line = 0; line < lines; line += increment) {
+      //
+      //                               int length = increment;
+      //                               if (line + increment > lines)
+      //                                       length = lines - line;
+      //
+      //                               try {
+      //
+      //                                       int offset = document.getLineOffset(line);
+      //                                       int end = document.getLineOffset(line + length);
+      //                                       length = end - offset;
+      //                                       Position p = new Position(offset, length);
+      //                                       document.addPosition(SEGMENTS, p);
+      //                                       fContent.add(new Segment(MessageFormat.format(PHPEditorMessages.getString("OutlinePage.segment.title_pattern"), new Object[] { new Integer(offset)}), p)); //$NON-NLS-1$
+      //
+      //                               } catch (BadPositionCategoryException x) {
+      //                               } catch (BadLocationException x) {
+      //                               }
+      //                       }
+    }
+
+    /*
+     * @see IContentProvider#inputChanged(Viewer, Object, Object)
+     */
+    public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+      if (oldInput != null) {
+        IDocument document = fDocumentProvider.getDocument(oldInput);
+        if (document != null) {
+          try {
+            document.removePositionCategory(SEGMENTS);
+          } catch (BadPositionCategoryException x) {
+          }
+          document.removePositionUpdater(fPositionUpdater);
+        }
+      }
+
+      fContent.clear();
+      fVariables.clear();
+
+      if (newInput != null) {
+        IDocument document = fDocumentProvider.getDocument(newInput);
+        if (document != null) {
+          document.addPositionCategory(SEGMENTS);
+          document.addPositionUpdater(fPositionUpdater);
+
+          parse(document);
+        }
+      }
+    }
+
+    /*
+     * @see IContentProvider#dispose
+     */
+    public void dispose() {
+      if (fContent != null) {
+        fContent.clear();
+        fContent = null;
+      }
+      if (fVariables != null) {
+        fVariables.clear();
+        fVariables = null;
+      }
+    }
+
+    /*
+     * @see IContentProvider#isDeleted(Object)
+     */
+    public boolean isDeleted(Object element) {
+      return false;
+    }
+
+    /*
+     * @see IStructuredContentProvider#getElements(Object)
+     */
+    public Object[] getElements(Object element) {
+      return fContent.toArray();
+    }
+
+    /**
+     * returns all PHP variables
+     */
+    public Object[] getVariables() {
+      return fVariables.toArray();
+    }
+    /*
+     * @see ITreeContentProvider#hasChildren(Object)
+     */
+    public boolean hasChildren(Object element) {
+      return element == fInput;
+    }
+
+    /*
+     * @see ITreeContentProvider#getParent(Object)
+     */
+    public Object getParent(Object element) {
+      if (element instanceof Segment)
+        return fInput;
+      return null;
+    }
+
+    /*
+     * @see ITreeContentProvider#getChildren(Object)
+     */
+    public Object[] getChildren(Object element) {
+      if (element == fInput)
+        return fContent.toArray();
+      return new Object[0];
+    }
+  };
+
+  protected Object fInput;
+  protected IDocumentProvider fDocumentProvider;
+  protected ITextEditor fTextEditor;
+
+  /**
+   * Creates a content outline page using the given provider and the given editor.
+   */
+  public PHPContentOutlinePage(IDocumentProvider provider, ITextEditor editor) {
+    super();
+    fDocumentProvider = provider;
+    fTextEditor = editor;
+  }
+
+  /* (non-Javadoc)
+   * Method declared on ContentOutlinePage
+   */
+  public void createControl(Composite parent) {
+
+    super.createControl(parent);
+
+    TreeViewer viewer = getTreeViewer();
+    viewer.setContentProvider(new ContentProvider());
+    viewer.setLabelProvider(new LabelProvider());
+    viewer.addSelectionChangedListener(this);
+
+    if (fInput != null)
+      viewer.setInput(fInput);
+  }
+
+  /* (non-Javadoc)
+   * Method declared on ContentOutlinePage
+   */
+  public void selectionChanged(SelectionChangedEvent event) {
+
+    super.selectionChanged(event);
+
+    ISelection selection = event.getSelection();
+    if (selection.isEmpty())
+      fTextEditor.resetHighlightRange();
+    else {
+      Segment segment = (Segment) ((IStructuredSelection) selection).getFirstElement();
+      int start = segment.position.getOffset();
+      int length = segment.position.getLength();
+      try {
+        fTextEditor.setHighlightRange(start, length, true);
+      } catch (IllegalArgumentException x) {
+        fTextEditor.resetHighlightRange();
+      }
+    }
+  }
+
+  /**
+   * Sets the input of the outline page
+   */
+  public void setInput(Object input) {
+    fInput = input;
+    update();
+  }
+
+  /**
+   * Updates the outline page.
+   */
+  public void update() {
+    TreeViewer viewer = getTreeViewer();
+
+    if (viewer != null) {
+      Control control = viewer.getControl();
+      if (control != null && !control.isDisposed()) {
+        control.setRedraw(false);
+        viewer.setInput(fInput);
+        viewer.expandAll();
+        control.setRedraw(true);
+      }
+    }
+  }
 }