Implemented a simple occurrences finder for Variables ($...) and Identifiers;
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / phpeditor / PHPEditor.java
index 5f57887..7ecba2c 100644 (file)
@@ -33,7 +33,11 @@ import net.sourceforge.phpdt.core.ISourceRange;
 import net.sourceforge.phpdt.core.ISourceReference;
 import net.sourceforge.phpdt.core.JavaCore;
 import net.sourceforge.phpdt.core.JavaModelException;
+import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
+import net.sourceforge.phpdt.core.compiler.InvalidInputException;
 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
+import net.sourceforge.phpdt.internal.compiler.parser.SyntaxError;
+import net.sourceforge.phpdt.internal.core.CompilationUnit;
 import net.sourceforge.phpdt.internal.ui.actions.CompositeActionGroup;
 import net.sourceforge.phpdt.internal.ui.actions.FoldingActionGroup;
 import net.sourceforge.phpdt.internal.ui.actions.SelectionConverter;
@@ -41,11 +45,14 @@ import net.sourceforge.phpdt.internal.ui.text.CustomSourceInformationControl;
 import net.sourceforge.phpdt.internal.ui.text.DocumentCharacterIterator;
 import net.sourceforge.phpdt.internal.ui.text.HTMLTextPresenter;
 import net.sourceforge.phpdt.internal.ui.text.IPHPPartitions;
+import net.sourceforge.phpdt.internal.ui.text.JavaWordFinder;
 import net.sourceforge.phpdt.internal.ui.text.JavaWordIterator;
 import net.sourceforge.phpdt.internal.ui.text.PHPPairMatcher;
 import net.sourceforge.phpdt.internal.ui.text.PreferencesAdapter;
 import net.sourceforge.phpdt.internal.ui.text.java.JavaExpandHover;
+import net.sourceforge.phpdt.internal.ui.viewsupport.ISelectionListenerWithAST;
 import net.sourceforge.phpdt.internal.ui.viewsupport.IViewPartInputProvider;
+import net.sourceforge.phpdt.internal.ui.viewsupport.SelectionListenerWithASTManager;
 import net.sourceforge.phpdt.ui.IContextMenuConstants;
 import net.sourceforge.phpdt.ui.JavaUI;
 import net.sourceforge.phpdt.ui.PreferenceConstants;
@@ -63,6 +70,7 @@ import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
 import org.eclipse.core.runtime.Preferences;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.jobs.Job;
@@ -77,10 +85,12 @@ import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.DefaultInformationControl;
 import org.eclipse.jface.text.DocumentEvent;
 import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IDocumentExtension4;
 import org.eclipse.jface.text.IDocumentListener;
 import org.eclipse.jface.text.IInformationControl;
 import org.eclipse.jface.text.IInformationControlCreator;
 import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ISelectionValidator;
 import org.eclipse.jface.text.ISynchronizable;
 import org.eclipse.jface.text.ITextHover;
 import org.eclipse.jface.text.ITextInputListener;
@@ -99,6 +109,7 @@ import org.eclipse.jface.text.TextSelection;
 import org.eclipse.jface.text.TextUtilities;
 import org.eclipse.jface.text.information.IInformationProvider;
 import org.eclipse.jface.text.information.InformationPresenter;
+import org.eclipse.jface.text.link.LinkedModeModel;
 import org.eclipse.jface.text.reconciler.IReconciler;
 import org.eclipse.jface.text.source.Annotation;
 import org.eclipse.jface.text.source.AnnotationRulerColumn;
@@ -151,13 +162,16 @@ import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
 import org.eclipse.ui.IPageLayout;
 import org.eclipse.ui.IPartService;
 import org.eclipse.ui.ISelectionListener;
 import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWindowListener;
 import org.eclipse.ui.IWorkbenchPage;
 import org.eclipse.ui.IWorkbenchPart;
 import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.actions.ActionContext;
 import org.eclipse.ui.actions.ActionGroup;
 import org.eclipse.ui.editors.text.DefaultEncodingSupport;
@@ -2305,7 +2319,7 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
                        ISourceViewer viewer = getSourceViewer();
                        int widget = -1;
                        while (position != BreakIterator.DONE && widget == -1) { // TODO:
-                                                                                                                                                                                                                                                               // optimize
+                               // optimize
                                position = fIterator.following(position);
                                if (position != BreakIterator.DONE)
                                        widget = modelOffset2WidgetOffset(viewer, position);
@@ -2486,7 +2500,7 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
                        ISourceViewer viewer = getSourceViewer();
                        int widget = -1;
                        while (position != BreakIterator.DONE && widget == -1) { // TODO:
-                                                                                                                                                                                                                                                               // optimize
+                               // optimize
                                position = fIterator.preceding(position);
                                if (position != BreakIterator.DONE)
                                        widget = modelOffset2WidgetOffset(viewer, position);
@@ -2657,25 +2671,40 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
         *
         * @since 3.0
         */
-       class OccurrencesFinderJob extends Job implements IDocumentListener {
+       class OccurrencesFinderJob extends Job {
 
                private IDocument fDocument;
 
-               private boolean fCancelled = false;
+               private ISelection fSelection;
+
+               private ISelectionValidator fPostSelectionValidator;
+
+               private boolean fCanceled = false;
 
                private IProgressMonitor fProgressMonitor;
 
                private Position[] fPositions;
 
-               public OccurrencesFinderJob(IDocument document, Position[] positions) {
-                       super("Occurrences Marker"); //$NON-NLS-1$
+               public OccurrencesFinderJob(IDocument document, Position[] positions, ISelection selection) {
+                       super(PHPEditorMessages.JavaEditor_markOccurrences_job_name);
                        fDocument = document;
+                       fSelection = selection;
                        fPositions = positions;
-                       fDocument.addDocumentListener(this);
+
+                       if (getSelectionProvider() instanceof ISelectionValidator)
+                               fPostSelectionValidator = (ISelectionValidator) getSelectionProvider();
+               }
+
+               // cannot use cancel() because it is declared final
+               void doCancel() {
+                       fCanceled = true;
+                       cancel();
                }
 
-               private boolean isCancelled() {
-                       return fCancelled || fProgressMonitor.isCanceled();
+               private boolean isCanceled() {
+                       return fCanceled || fProgressMonitor.isCanceled() || fPostSelectionValidator != null
+                                       && !(fPostSelectionValidator.isValid(fSelection) || fForcedMarkOccurrencesSelection == fSelection)
+                                       || LinkedModeModel.hasInstalledModel(fDocument);
                }
 
                /*
@@ -2685,76 +2714,110 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
 
                        fProgressMonitor = progressMonitor;
 
-                       try {
-
-                               if (isCancelled())
-                                       return Status.CANCEL_STATUS;
+                       if (isCanceled())
+                               return Status.CANCEL_STATUS;
 
-                               ITextViewer textViewer = getViewer();
-                               if (textViewer == null)
-                                       return Status.CANCEL_STATUS;
+                       ITextViewer textViewer = getViewer();
+                       if (textViewer == null)
+                               return Status.CANCEL_STATUS;
 
-                               IDocument document = textViewer.getDocument();
-                               if (document == null)
-                                       return Status.CANCEL_STATUS;
+                       IDocument document = textViewer.getDocument();
+                       if (document == null)
+                               return Status.CANCEL_STATUS;
 
-                               IDocumentProvider documentProvider = getDocumentProvider();
-                               if (documentProvider == null)
-                                       return Status.CANCEL_STATUS;
+                       IDocumentProvider documentProvider = getDocumentProvider();
+                       if (documentProvider == null)
+                               return Status.CANCEL_STATUS;
 
-                               IAnnotationModel annotationModel = documentProvider.getAnnotationModel(getEditorInput());
-                               if (annotationModel == null)
-                                       return Status.CANCEL_STATUS;
+                       IAnnotationModel annotationModel = documentProvider.getAnnotationModel(getEditorInput());
+                       if (annotationModel == null)
+                               return Status.CANCEL_STATUS;
 
-                               // Add occurrence annotations
-                               int length = fPositions.length;
-                               Map annotationMap = new HashMap(length);
-                               for (int i = 0; i < length; i++) {
+                       // Add occurrence annotations
+                       int length = fPositions.length;
+                       Map annotationMap = new HashMap(length);
+                       for (int i = 0; i < length; i++) {
 
-                                       if (isCancelled())
-                                               return Status.CANCEL_STATUS;
+                               if (isCanceled())
+                                       return Status.CANCEL_STATUS;
 
-                                       String message;
-                                       Position position = fPositions[i];
+                               String message;
+                               Position position = fPositions[i];
 
-                                       // Create & add annotation
-                                       try {
-                                               message = document.get(position.offset, position.length);
-                                       } catch (BadLocationException ex) {
-                                               // Skip this match
-                                               continue;
-                                       }
-                                       annotationMap.put(new Annotation("net.sourceforge.phpdt.ui.occurrences", false, message), //$NON-NLS-1$
-                                                       position);
+                               // Create & add annotation
+                               try {
+                                       message = document.get(position.offset, position.length);
+                               } catch (BadLocationException ex) {
+                                       // Skip this match
+                                       continue;
                                }
+                               annotationMap.put(new Annotation("net.sourceforge.phpdt.ui.occurrences", false, message), //$NON-NLS-1$
+                                               position);
+                       }
 
-                               if (isCancelled())
-                                       return Status.CANCEL_STATUS;
+                       if (isCanceled())
+                               return Status.CANCEL_STATUS;
 
-                               synchronized (annotationModel) {
-                                       if (annotationModel instanceof IAnnotationModelExtension) {
-                                               ((IAnnotationModelExtension) annotationModel).replaceAnnotations(fOccurrenceAnnotations, annotationMap);
-                                       } else {
-                                               removeOccurrenceAnnotations();
-                                               Iterator iter = annotationMap.entrySet().iterator();
-                                               while (iter.hasNext()) {
-                                                       Map.Entry mapEntry = (Map.Entry) iter.next();
-                                                       annotationModel.addAnnotation((Annotation) mapEntry.getKey(), (Position) mapEntry.getValue());
-                                               }
+                       synchronized (getLockObject(annotationModel)) {
+                               if (annotationModel instanceof IAnnotationModelExtension) {
+                                       ((IAnnotationModelExtension) annotationModel).replaceAnnotations(fOccurrenceAnnotations, annotationMap);
+                               } else {
+                                       removeOccurrenceAnnotations();
+                                       Iterator iter = annotationMap.entrySet().iterator();
+                                       while (iter.hasNext()) {
+                                               Map.Entry mapEntry = (Map.Entry) iter.next();
+                                               annotationModel.addAnnotation((Annotation) mapEntry.getKey(), (Position) mapEntry.getValue());
                                        }
-                                       fOccurrenceAnnotations = (Annotation[]) annotationMap.keySet().toArray(new Annotation[annotationMap.keySet().size()]);
                                }
-                       } finally {
-                               fDocument.removeDocumentListener(this);
+                               fOccurrenceAnnotations = (Annotation[]) annotationMap.keySet().toArray(new Annotation[annotationMap.keySet().size()]);
                        }
+
                        return Status.OK_STATUS;
                }
+       }
+
+       /**
+        * Cancels the occurrences finder job upon document changes.
+        *
+        * @since 3.0
+        */
+       class OccurrencesFinderJobCanceler implements IDocumentListener, ITextInputListener {
+
+               public void install() {
+                       ISourceViewer sourceViewer = getSourceViewer();
+                       if (sourceViewer == null)
+                               return;
+
+                       StyledText text = sourceViewer.getTextWidget();
+                       if (text == null || text.isDisposed())
+                               return;
+
+                       sourceViewer.addTextInputListener(this);
+
+                       IDocument document = sourceViewer.getDocument();
+                       if (document != null)
+                               document.addDocumentListener(this);
+               }
+
+               public void uninstall() {
+                       ISourceViewer sourceViewer = getSourceViewer();
+                       if (sourceViewer != null)
+                               sourceViewer.removeTextInputListener(this);
+
+                       IDocumentProvider documentProvider = getDocumentProvider();
+                       if (documentProvider != null) {
+                               IDocument document = documentProvider.getDocument(getEditorInput());
+                               if (document != null)
+                                       document.removeDocumentListener(this);
+                       }
+               }
 
                /*
                 * @see org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged(org.eclipse.jface.text.DocumentEvent)
                 */
                public void documentAboutToBeChanged(DocumentEvent event) {
-                       fCancelled = true;
+                       if (fOccurrencesFinderJob != null)
+                               fOccurrencesFinderJob.doCancel();
                }
 
                /*
@@ -2762,6 +2825,70 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
                 */
                public void documentChanged(DocumentEvent event) {
                }
+
+               /*
+                * @see org.eclipse.jface.text.ITextInputListener#inputDocumentAboutToBeChanged(org.eclipse.jface.text.IDocument,
+                *      org.eclipse.jface.text.IDocument)
+                */
+               public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) {
+                       if (oldInput == null)
+                               return;
+
+                       oldInput.removeDocumentListener(this);
+               }
+
+               /*
+                * @see org.eclipse.jface.text.ITextInputListener#inputDocumentChanged(org.eclipse.jface.text.IDocument,
+                *      org.eclipse.jface.text.IDocument)
+                */
+               public void inputDocumentChanged(IDocument oldInput, IDocument newInput) {
+                       if (newInput == null)
+                               return;
+                       newInput.addDocumentListener(this);
+               }
+       }
+
+       /**
+        * Internal activation listener.
+        *
+        * @since 3.0
+        */
+       private class ActivationListener implements IWindowListener {
+
+               /*
+                * @see org.eclipse.ui.IWindowListener#windowActivated(org.eclipse.ui.IWorkbenchWindow)
+                * @since 3.1
+                */
+               public void windowActivated(IWorkbenchWindow window) {
+                       if (window == getEditorSite().getWorkbenchWindow() && fMarkOccurrenceAnnotations && isActivePart()) {
+                               fForcedMarkOccurrencesSelection = getSelectionProvider().getSelection();
+                               SelectionListenerWithASTManager.getDefault().forceSelectionChange(PHPEditor.this,
+                                               (ITextSelection) fForcedMarkOccurrencesSelection);
+                       }
+               }
+
+               /*
+                * @see org.eclipse.ui.IWindowListener#windowDeactivated(org.eclipse.ui.IWorkbenchWindow)
+                * @since 3.1
+                */
+               public void windowDeactivated(IWorkbenchWindow window) {
+                       if (window == getEditorSite().getWorkbenchWindow() && fMarkOccurrenceAnnotations && isActivePart())
+                               removeOccurrenceAnnotations();
+               }
+
+               /*
+                * @see org.eclipse.ui.IWindowListener#windowClosed(org.eclipse.ui.IWorkbenchWindow)
+                * @since 3.1
+                */
+               public void windowClosed(IWorkbenchWindow window) {
+               }
+
+               /*
+                * @see org.eclipse.ui.IWindowListener#windowOpened(org.eclipse.ui.IWorkbenchWindow)
+                * @since 3.1
+                */
+               public void windowOpened(IWorkbenchWindow window) {
+               }
        }
 
        /**
@@ -2773,7 +2900,15 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
                        doSelectionChanged(event);
                }
        }
-
+       /**
+        * The internal shell activation listener for updating occurrences.
+        * @since 3.0
+        */
+       private ActivationListener fActivationListener= new ActivationListener();
+       private ISelectionListenerWithAST fPostSelectionListenerWithAST;
+       private OccurrencesFinderJob fOccurrencesFinderJob;
+       /** The occurrences finder job canceler */
+       private OccurrencesFinderJobCanceler fOccurrencesFinderJobCanceler;
        /**
         * Holds the current occurrence annotations.
         *
@@ -2781,7 +2916,45 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
         */
        private Annotation[] fOccurrenceAnnotations = null;
 
-       private Job fOccurrencesFinderJob;
+       /**
+        * Tells whether all occurrences of the element at the current caret location
+        * are automatically marked in this editor.
+        *
+        * @since 3.0
+        */
+       private boolean fMarkOccurrenceAnnotations;
+
+       /**
+        * The selection used when forcing occurrence marking through code.
+        *
+        * @since 3.0
+        */
+       private ISelection fForcedMarkOccurrencesSelection;
+
+       /**
+        * The document modification stamp at the time when the last occurrence
+        * marking took place.
+        *
+        * @since 3.1
+        */
+       private long fMarkOccurrenceModificationStamp = IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP;
+
+       /**
+        * The region of the word under the caret used to when computing the current
+        * occurrence markings.
+        *
+        * @since 3.1
+        */
+       private IRegion fMarkOccurrenceTargetRegion;
+
+       /**
+        * Tells whether the occurrence annotations are sticky i.e. whether they stay
+        * even if there's no valid Java element at the current caret position. Only
+        * valid if {@link #fMarkOccurrenceAnnotations} is <code>true</code>.
+        *
+        * @since 3.0
+        */
+       private boolean fStickyOccurrenceAnnotations;
 
        /** Preference key for showing the line number ruler */
        // private final static String LINE_NUMBER_RULER =
@@ -2961,24 +3134,17 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
                // setSourceViewerConfiguration(new
                // JavaSourceViewerConfiguration(textTools.getColorManager(), store,
                // this, IJavaPartitions.JAVA_PARTITIONING));
-               // fMarkOccurrenceAnnotations=
-               // store.getBoolean(PreferenceConstants.EDITOR_MARK_OCCURRENCES);
-               // fStickyOccurrenceAnnotations=
-               // store.getBoolean(PreferenceConstants.EDITOR_STICKY_OCCURRENCES);
-               // fMarkTypeOccurrences=
-               // store.getBoolean(PreferenceConstants.EDITOR_MARK_TYPE_OCCURRENCES);
-               // fMarkMethodOccurrences=
-               // store.getBoolean(PreferenceConstants.EDITOR_MARK_METHOD_OCCURRENCES);
-               // fMarkConstantOccurrences=
-               // store.getBoolean(PreferenceConstants.EDITOR_MARK_CONSTANT_OCCURRENCES);
-               // fMarkFieldOccurrences=
-               // store.getBoolean(PreferenceConstants.EDITOR_MARK_FIELD_OCCURRENCES);
-               // fMarkLocalVariableypeOccurrences=
-               // store.getBoolean(PreferenceConstants.EDITOR_MARK_LOCAL_VARIABLE_OCCURRENCES);
-               // fMarkExceptionOccurrences=
-               // store.getBoolean(PreferenceConstants.EDITOR_MARK_EXCEPTION_OCCURRENCES);
-               // fMarkMethodExitPoints=
-               // store.getBoolean(PreferenceConstants.EDITOR_MARK_METHOD_EXIT_POINTS);
+               fMarkOccurrenceAnnotations= store.getBoolean(PreferenceConstants.EDITOR_MARK_OCCURRENCES);
+               fStickyOccurrenceAnnotations= store.getBoolean(PreferenceConstants.EDITOR_STICKY_OCCURRENCES);
+//             fMarkTypeOccurrences= store.getBoolean(PreferenceConstants.EDITOR_MARK_TYPE_OCCURRENCES);
+//             fMarkMethodOccurrences= store.getBoolean(PreferenceConstants.EDITOR_MARK_METHOD_OCCURRENCES);
+//             fMarkConstantOccurrences= store.getBoolean(PreferenceConstants.EDITOR_MARK_CONSTANT_OCCURRENCES);
+//             fMarkFieldOccurrences= store.getBoolean(PreferenceConstants.EDITOR_MARK_FIELD_OCCURRENCES);
+//             fMarkLocalVariableypeOccurrences= store.getBoolean(PreferenceConstants.EDITOR_MARK_LOCAL_VARIABLE_OCCURRENCES);
+//             fMarkExceptions= store.getBoolean(PreferenceConstants.EDITOR_MARK_EXCEPTION_OCCURRENCES);
+//             fMarkImplementors= store.getBoolean(PreferenceConstants.EDITOR_MARK_IMPLEMENTORS);
+//             fMarkMethodExitPoints= store.getBoolean(PreferenceConstants.EDITOR_MARK_METHOD_EXIT_POINTS);
+
        }
 
        /*
@@ -3094,8 +3260,12 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
                if (PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_DISABLE_OVERWRITE_MODE))
                        enableOverwriteMode(false);
 
+               if (fMarkOccurrenceAnnotations)
+                       installOccurrencesFinder();
+
+               PlatformUI.getWorkbench().addWindowListener(fActivationListener);
+
                setWordWrap();
-               // getEditorSite().getShell().addShellListener(fActivationListener);
        }
 
        private void setWordWrap() {
@@ -3406,6 +3576,17 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
                if (isBrowserLikeLinks())
                        disableBrowserLikeLinks();
 
+//      cancel possible running computation
+               fMarkOccurrenceAnnotations= false;
+               uninstallOccurrencesFinder();
+
+               uninstallOverrideIndicator();
+
+               if (fActivationListener != null) {
+                       PlatformUI.getWorkbench().removeWindowListener(fActivationListener);
+                       fActivationListener= null;
+               }
+
                if (fEncodingSupport != null) {
                        fEncodingSupport.dispose();
                        fEncodingSupport = null;
@@ -4020,32 +4201,40 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
                                return;
                        }
 
+                       if (PreferenceConstants.EDITOR_DISABLE_OVERWRITE_MODE.equals(property)) {
+                               if (event.getNewValue() instanceof Boolean) {
+                                       Boolean disable = (Boolean) event.getNewValue();
+                                       enableOverwriteMode(!disable.booleanValue());
+                               }
+                               return;
+                       }
+
+                       boolean newBooleanValue= false;
+                       Object newValue= event.getNewValue();
+                       if (newValue != null)
+                               newBooleanValue= Boolean.valueOf(newValue.toString()).booleanValue();
+
                        if (PreferenceConstants.EDITOR_SYNC_OUTLINE_ON_CURSOR_MOVE.equals(property)) {
-                               if ((event.getNewValue() instanceof Boolean) && ((Boolean) event.getNewValue()).booleanValue())
+                               if (newBooleanValue)
                                        selectionChanged();
                                return;
                        }
 
-                       if (PreferenceConstants.EDITOR_DISABLE_OVERWRITE_MODE.equals(property)) {
-                               if (event.getNewValue() instanceof Boolean) {
-                                       Boolean disable = (Boolean) event.getNewValue();
-                                       enableOverwriteMode(!disable.booleanValue());
+                       if (PreferenceConstants.EDITOR_MARK_OCCURRENCES.equals(property)) {
+                               if (newBooleanValue != fMarkOccurrenceAnnotations) {
+                                       fMarkOccurrenceAnnotations= newBooleanValue;
+                                       if (!fMarkOccurrenceAnnotations)
+                                               uninstallOccurrencesFinder();
+                                       else
+                                               installOccurrencesFinder();
                                }
                                return;
                        }
 
-                       // if (PreferenceConstants.EDITOR_MARK_OCCURRENCES.equals(property))
-                       // {
-                       // if (event.getNewValue() instanceof Boolean) {
-                       // boolean markOccurrenceAnnotations=
-                       // ((Boolean)event.getNewValue()).booleanValue();
-                       // if (markOccurrenceAnnotations != fMarkOccurrenceAnnotations) {
-                       // fMarkOccurrenceAnnotations= markOccurrenceAnnotations;
-                       // if (!fMarkOccurrenceAnnotations)
-                       // uninstallOccurrencesFinder();
-                       // else
-                       // installOccurrencesFinder();
-                       // }
+                       if (PreferenceConstants.EDITOR_STICKY_OCCURRENCES.equals(property)) {
+                               fStickyOccurrenceAnnotations= newBooleanValue;
+                               return;
+                       }
                        // }
                        // }
                        // if
@@ -4056,14 +4245,7 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
                        // ((Boolean)event.getNewValue()).booleanValue();
                        // if (stickyOccurrenceAnnotations != fStickyOccurrenceAnnotations)
                        // {
-                       // fStickyOccurrenceAnnotations= stickyOccurrenceAnnotations;
-                       // // if (!fMarkOccurrenceAnnotations)
-                       // // uninstallOccurrencesFinder();
-                       // // else
-                       // // installOccurrencesFinder();
-                       // }
-                       // }
-                       // }
+
 
                        ((PHPSourceViewerConfiguration) getSourceViewerConfiguration()).handlePropertyChangeEvent(event);
 
@@ -4670,8 +4852,8 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
                                continue;
 
                        if (forward && p.offset == offset || !forward && p.offset + p.getLength() == offset + length) {// ||
-                                                                                                                                                                                                                                                                                                                                                                                                                       // p.includes(offset))
-                                                                                                                                                                                                                                                                                                                                                                                                                       // {
+                               // p.includes(offset))
+                               // {
                                if (containingAnnotation == null
                                                || (forward && p.length >= containingAnnotationPosition.length || !forward
                                                                && p.length >= containingAnnotationPosition.length)) {
@@ -5078,26 +5260,6 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
                return nextError;
        }
 
-       void removeOccurrenceAnnotations() {
-               IDocumentProvider documentProvider = getDocumentProvider();
-               if (documentProvider == null)
-                       return;
-
-               IAnnotationModel annotationModel = documentProvider.getAnnotationModel(getEditorInput());
-               if (annotationModel == null || fOccurrenceAnnotations == null)
-                       return;
-
-               synchronized (annotationModel) {
-                       if (annotationModel instanceof IAnnotationModelExtension) {
-                               ((IAnnotationModelExtension) annotationModel).replaceAnnotations(fOccurrenceAnnotations, null);
-                       } else {
-                               for (int i = 0, length = fOccurrenceAnnotations.length; i < length; i++)
-                                       annotationModel.removeAnnotation(fOccurrenceAnnotations[i]);
-                       }
-                       fOccurrenceAnnotations = null;
-               }
-       }
-
        protected void uninstallOverrideIndicator() {
                // if (fOverrideIndicatorManager != null) {
                // fOverrideIndicatorManager.removeAnnotations();
@@ -5173,7 +5335,7 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
 
        protected boolean isPrefQuickDiffAlwaysOn() {
                return false; // never show change ruler for the non-editable java editor.
-                                                                       // Overridden in subclasses like PHPUnitEditor
+               // Overridden in subclasses like PHPUnitEditor
        }
 
        /*
@@ -5386,7 +5548,7 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
        public ShowInContext getShowInContext() {
                FileEditorInput fei = (FileEditorInput) getEditorInput();
                ShowInContext context = BrowserUtil.getShowInContext(fei.getFile(), false, "");
-               if (context!=null) {
+               if (context != null) {
                        return context;
                }
                return new ShowInContext(fei.getFile(), null);
@@ -5395,4 +5557,168 @@ public abstract class PHPEditor extends AbstractDecoratedTextEditor implements I
        public String[] getShowInTargetIds() {
                return new String[] { BrowserView.ID_BROWSER };
        }
+
+       /**
+        * Updates the occurrences annotations based on the current selection.
+        *
+        * @param selection
+        *          the text selection
+        * @param astRoot
+        *          the compilation unit AST
+        * @since 3.0
+        */
+       protected void updateOccurrenceAnnotations(ITextSelection selection) {//, CompilationUnit astRoot) {
+
+               if (fOccurrencesFinderJob != null)
+                       fOccurrencesFinderJob.cancel();
+
+               if (!fMarkOccurrenceAnnotations)
+                       return;
+
+//             if (astRoot == null || selection == null)
+               if (selection == null)
+                       return;
+
+               IDocument document = getSourceViewer().getDocument();
+               if (document == null)
+                       return;
+
+               if (document instanceof IDocumentExtension4) {
+                       int offset = selection.getOffset();
+                       long currentModificationStamp = ((IDocumentExtension4) document).getModificationStamp();
+                       if (fMarkOccurrenceTargetRegion != null && currentModificationStamp == fMarkOccurrenceModificationStamp) {
+                               if (fMarkOccurrenceTargetRegion.getOffset() <= offset
+                                               && offset <= fMarkOccurrenceTargetRegion.getOffset() + fMarkOccurrenceTargetRegion.getLength())
+                                       return;
+                       }
+                       fMarkOccurrenceTargetRegion = JavaWordFinder.findWord(document, offset);
+                       fMarkOccurrenceModificationStamp = currentModificationStamp;
+               }
+
+               List matches = null;
+
+               if (matches == null) {
+                       try {
+                               matches = new ArrayList();
+
+                               Scanner fScanner = new Scanner();
+                               fScanner.setSource(document.get().toCharArray());
+                               fScanner.setPHPMode(false);
+                               char[] word;
+
+                               word = document.get(fMarkOccurrenceTargetRegion.getOffset(), fMarkOccurrenceTargetRegion.getLength()).toCharArray();
+
+                               int fToken = ITerminalSymbols.TokenNameEOF;
+                               try {
+                                       fToken = fScanner.getNextToken();
+                                       while (fToken != ITerminalSymbols.TokenNameEOF) { // && fToken !=
+                                               // TokenNameERROR) {
+                                               if (fToken == ITerminalSymbols.TokenNameVariable || fToken == ITerminalSymbols.TokenNameIdentifier) {
+                                                       // global variable
+                                                       if (fScanner.equalsCurrentTokenSource(word)) {
+                                                               matches.add(new Region(fScanner.getCurrentTokenStartPosition(), fScanner.getCurrentTokenEndPosition()
+                                                                               - fScanner.getCurrentTokenStartPosition()+1));
+                                                       }
+                                               }
+                                               fToken = fScanner.getNextToken();
+                                       }
+                               } catch (InvalidInputException e) {
+                                       // ignore errors
+                               } catch (SyntaxError e) {
+                                       // ignore errors
+                               }
+
+                       } catch (BadLocationException e1) {
+                               // ignore errors
+                       }
+
+               }
+
+               if (matches == null || matches.size() == 0) {
+                       if (!fStickyOccurrenceAnnotations)
+                               removeOccurrenceAnnotations();
+                       return;
+               }
+
+               Position[] positions = new Position[matches.size()];
+               int i = 0;
+               for (Iterator each = matches.iterator(); each.hasNext();) {
+                       IRegion currentNode = (IRegion) each.next();
+                       positions[i++] = new Position(currentNode.getOffset(), currentNode.getLength());
+               }
+
+               fOccurrencesFinderJob = new OccurrencesFinderJob(document, positions, selection);
+               // fOccurrencesFinderJob.setPriority(Job.DECORATE);
+               // fOccurrencesFinderJob.setSystem(true);
+               // fOccurrencesFinderJob.schedule();
+               fOccurrencesFinderJob.run(new NullProgressMonitor());
+       }
+
+       protected void installOccurrencesFinder() {
+               fMarkOccurrenceAnnotations = true;
+
+               fPostSelectionListenerWithAST = new ISelectionListenerWithAST() {
+                       public void selectionChanged(IEditorPart part, ITextSelection selection) { //, CompilationUnit astRoot) {
+                               updateOccurrenceAnnotations(selection);//, astRoot);
+                       }
+               };
+               SelectionListenerWithASTManager.getDefault().addListener(this, fPostSelectionListenerWithAST);
+               if (getSelectionProvider() != null) {
+                       fForcedMarkOccurrencesSelection = getSelectionProvider().getSelection();
+                       SelectionListenerWithASTManager.getDefault().forceSelectionChange(this, (ITextSelection) fForcedMarkOccurrencesSelection);
+               }
+
+               if (fOccurrencesFinderJobCanceler == null) {
+                       fOccurrencesFinderJobCanceler = new OccurrencesFinderJobCanceler();
+                       fOccurrencesFinderJobCanceler.install();
+               }
+       }
+
+       protected void uninstallOccurrencesFinder() {
+               fMarkOccurrenceAnnotations = false;
+
+               if (fOccurrencesFinderJob != null) {
+                       fOccurrencesFinderJob.cancel();
+                       fOccurrencesFinderJob = null;
+               }
+
+               if (fOccurrencesFinderJobCanceler != null) {
+                       fOccurrencesFinderJobCanceler.uninstall();
+                       fOccurrencesFinderJobCanceler = null;
+               }
+
+               if (fPostSelectionListenerWithAST != null) {
+                       SelectionListenerWithASTManager.getDefault().removeListener(this, fPostSelectionListenerWithAST);
+                       fPostSelectionListenerWithAST = null;
+               }
+
+               removeOccurrenceAnnotations();
+       }
+
+       protected boolean isMarkingOccurrences() {
+               return fMarkOccurrenceAnnotations;
+       }
+
+       void removeOccurrenceAnnotations() {
+               fMarkOccurrenceModificationStamp = IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP;
+               fMarkOccurrenceTargetRegion = null;
+
+               IDocumentProvider documentProvider = getDocumentProvider();
+               if (documentProvider == null)
+                       return;
+
+               IAnnotationModel annotationModel = documentProvider.getAnnotationModel(getEditorInput());
+               if (annotationModel == null || fOccurrenceAnnotations == null)
+                       return;
+
+               synchronized (getLockObject(annotationModel)) {
+                       if (annotationModel instanceof IAnnotationModelExtension) {
+                               ((IAnnotationModelExtension) annotationModel).replaceAnnotations(fOccurrenceAnnotations, null);
+                       } else {
+                               for (int i = 0, length = fOccurrenceAnnotations.length; i < length; i++)
+                                       annotationModel.removeAnnotation(fOccurrenceAnnotations[i]);
+                       }
+                       fOccurrenceAnnotations = null;
+               }
+       }
 }
\ No newline at end of file