org.cs3.pdt.editor.internal.editors.PLEditor.java Source code

Java tutorial

Introduction

Here is the source code for org.cs3.pdt.editor.internal.editors.PLEditor.java

Source

/*****************************************************************************
 * This file is part of the Prolog Development Tool (PDT)
 * 
 * Author: Lukas Degener (among others)
 * WWW: http://sewiki.iai.uni-bonn.de/research/pdt/start
 * Mail: pdt@lists.iai.uni-bonn.de
 * Copyright (C): 2004-2012, CS Dept. III, University of Bonn
 * 
 * All rights reserved. This program is  made available under the terms
 * of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 * 
 ****************************************************************************/

package org.cs3.pdt.editor.internal.editors;

import static org.cs3.prolog.connector.common.QueryUtils.bT;
import static org.cs3.prolog.connector.common.QueryUtils.quoteAtomIfNeeded;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;

import org.cs3.pdt.common.PDTCommonPlugin;
import org.cs3.pdt.common.PDTCommonPredicates;
import org.cs3.pdt.common.PDTCommonUtil;
import org.cs3.pdt.common.PrologProcessStartListener;
import org.cs3.pdt.common.metadata.Goal;
import org.cs3.pdt.connector.PDTConnectorPlugin;
import org.cs3.pdt.connector.service.ActivePrologProcessListener;
import org.cs3.pdt.connector.service.ConsultListener;
import org.cs3.pdt.connector.util.ExternalPrologFilesProjectUtils;
import org.cs3.pdt.connector.util.FileUtils;
import org.cs3.pdt.connector.util.UIUtils;
import org.cs3.pdt.editor.PDT;
import org.cs3.pdt.editor.PDTPlugin;
import org.cs3.pdt.editor.PDTPredicates;
import org.cs3.pdt.editor.internal.ImageRepository;
import org.cs3.pdt.editor.internal.actions.FindDefinitionsActionDelegate;
import org.cs3.pdt.editor.internal.actions.FindPredicateActionDelegate;
import org.cs3.pdt.editor.internal.actions.FindReferencesActionDelegate;
import org.cs3.pdt.editor.internal.actions.OpenCallHierarchyActionDelegte;
import org.cs3.pdt.editor.internal.actions.ToggleCommentAction;
import org.cs3.pdt.editor.internal.editors.breakpoints.PDTBreakpointHandler;
import org.cs3.pdt.editor.internal.views.lightweightOutline.NonNaturePrologOutline;
import org.cs3.pdt.editor.metadata.GoalProvider;
import org.cs3.pdt.editor.metadata.PredicateReadingUtilities;
import org.cs3.prolog.connector.common.Debug;
import org.cs3.prolog.connector.common.ParserUtils;
import org.cs3.prolog.connector.common.QueryUtils;
import org.cs3.prolog.connector.process.PrologProcess;
import org.cs3.prolog.connector.process.PrologProcessException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.ITypedRegion;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.text.information.InformationPresenter;
import org.eclipse.jface.text.link.LinkedModeModel;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.IAnnotationModelExtension;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CaretEvent;
import org.eclipse.swt.custom.CaretListener;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.editors.text.TextEditor;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
import org.eclipse.ui.texteditor.MarkerUtilities;
import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
import org.eclipse.ui.texteditor.TextEditorAction;
import org.eclipse.ui.views.contentoutline.ContentOutlinePage;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;

public class PLEditor extends TextEditor
        implements ConsultListener, ActivePrologProcessListener, PrologProcessStartListener {

    public static final String COMMAND_OPEN_PRIMARY_DEFINITION = "org.eclipse.pdt.ui.open.primary.definition";

    public static final String COMMAND_FIND_ALL_DEFINITIONS = "org.eclipse.pdt.ui.find.all.definitions";

    public static final String COMMAND_FIND_REFERENCES = "org.eclipse.pdt.ui.find.references";

    public static final String COMMAND_SHOW_QUICK_OUTLINE = "org.eclipse.pdt.ui.edit.text.prolog.show.quick.outline";

    public static final String COMMAND_SAVE_NO_CONSULT = "org.eclipse.pdt.ui.edit.save.no.reconsult";

    public static final String COMMAND_CONSULT = "org.eclipse.pdt.ui.edit.consult";

    public static final String COMMAND_TOGGLE_COMMENTS = "org.eclipse.pdt.ui.edit.text.prolog.toggle.comments";

    public static final String COMMAND_OPEN_CALL_HIERARCHY = "org.eclipse.pdt.ui.open.call.hierarchy";

    private ColorManager colorManager;

    private NonNaturePrologOutline fOutlinePage;

    protected final static char[] BRACKETS = { '(', ')', '[', ']' };

    private static final boolean EXPERIMENTAL_ADD_TASKS = true;

    private PLConfiguration configuration;

    @Override
    protected void initializeKeyBindingScopes() {
        setKeyBindingScopes(new String[] { PDT.CONTEXT_EDITING_PROLOG_CODE });
    }

    @Override
    public void doSave(IProgressMonitor progressMonitor) {
        if (shouldAbortSaving()) {
            return;
        }
        super.doSave(progressMonitor);

        boolean shouldConsult = Boolean
                .parseBoolean(PDTPlugin.getDefault().getPreferenceValue(PDT.PREF_CONSULT_ON_SAVE, "true"));

        if (shouldConsult) {
            Document document = (Document) getDocumentProvider().getDocument(getEditorInput());
            if (EXPERIMENTAL_ADD_TASKS && getEditorInput() instanceof FileEditorInput) {
                addTasks(((FileEditorInput) getEditorInput()).getFile(), document);
            }
            PDTCommonPlugin.getDefault().getPreferenceStore().setValue("console.no.focus", true);

            PrologProcess activePrologProcess = PDTCommonUtil.getActivePrologProcess();
            if (activePrologProcess.isUp()) {
                try {
                    List<Map<String, Object>> results = activePrologProcess
                            .queryAll(bT(PDTPredicates.FILE_TO_RELOAD_FOR_INCLUDED_FILE,
                                    quoteAtomIfNeeded(getPrologFileName()), "FileToReload"));
                    if (results.isEmpty()) {
                        loadCurrentFile();
                    } else {
                        ArrayList<IFile> filesToReload = new ArrayList<>();
                        try {
                            for (Map<String, Object> result : results) {
                                filesToReload
                                        .add(FileUtils.findFileForLocation(result.get("FileToReload").toString()));
                            }
                            PDTConnectorPlugin.getDefault().getPrologProcessService().consultFiles(filesToReload);
                        } catch (IOException e) {
                            loadCurrentFile();
                        }
                    }
                } catch (PrologProcessException e) {
                    loadCurrentFile();
                }
            } else {
                loadCurrentFile();
            }
        }

        PDTCommonPlugin.getDefault().notifyDecorators();
    }

    private void loadCurrentFile() {
        IFile currentIFile = getCurrentIFile();
        if (currentIFile != null) {
            PDTConnectorPlugin.getDefault().getPrologProcessService().consultFile(currentIFile);
        } else {
            PDTConnectorPlugin.getDefault().getPrologProcessService().consultFile(getPrologFileName());
        }
    }

    private void addTasks(IFile file, Document document) {
        try {
            int offset = 0;
            file.deleteMarkers(IMarker.TASK, true, IResource.DEPTH_ONE);
            while (offset < document.getLength()) {
                ITypedRegion region = document.getPartition(offset);
                if (isComment(region)) {
                    String content = document.get(offset, region.getLength());
                    addTaskMarker(file, document, offset, content, "TODO");
                    addTaskMarker(file, document, offset, content, "FIXME");
                }
                offset = region.getOffset() + region.getLength();
            }
        } catch (BadLocationException e) {
            Debug.report(e);
        } catch (CoreException e1) {
            Debug.report(e1);
        }

    }

    private void addTaskMarker(IFile file, Document document, int offset, String content, String text)
            throws BadLocationException {
        if (content.contains(text)) {
            int todoOffset = content.indexOf(text);
            int linebreakOffset = content.indexOf("\n", todoOffset);
            if (linebreakOffset < 0) {
                linebreakOffset = content.length() - 1;
            }
            String lineString = content.substring(todoOffset, linebreakOffset);
            HashMap<String, Comparable<?>> attributes = new HashMap<String, Comparable<?>>();
            attributes.put(IMarker.LINE_NUMBER, document.getLineOfOffset(offset + todoOffset));
            attributes.put(IMarker.CHAR_START, offset + todoOffset);
            attributes.put(IMarker.CHAR_END, offset + linebreakOffset);
            attributes.put(IMarker.MESSAGE, lineString);
            if (text.equals("TODO")) {
                attributes.put(IMarker.PRIORITY, new Integer(IMarker.PRIORITY_NORMAL));
            } else {
                attributes.put(IMarker.PRIORITY, new Integer(IMarker.PRIORITY_HIGH));
            }
            try {
                MarkerUtilities.createMarker(file, attributes, IMarker.TASK);
            } catch (CoreException e) {
                Debug.report(e);
            }
        }
    }

    /**
     * @return
     * 
     */
    private boolean shouldAbortSaving() {
        if (isExternalInput()) {
            boolean showWarning = Boolean.parseBoolean(
                    PDTPlugin.getDefault().getPreferenceValue(PDT.PREF_EXTERNAL_FILE_SAVE_WARNING, "true"));
            if (showWarning) {
                MessageDialog m = new MessageDialog(getEditorSite().getShell(), "External file", null,
                        "The current file in the editor is not contained in the workspace. Are you sure you want to save this file?",
                        MessageDialog.QUESTION, new String[] { "Yes", "Yes, always", "No" }, 0);
                int answer = m.open();
                switch (answer) {
                case 1:
                    PDTPlugin.getDefault().setPreferenceValue(PDT.PREF_EXTERNAL_FILE_SAVE_WARNING, "false");
                case 0:
                    break;
                case 2:
                case SWT.DEFAULT:
                default:
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public void setFocus() {
        super.setFocus();
        informAboutChangedEditorInput();
    }

    public void informAboutChangedEditorInput() {
        ISchedulingRule rule;
        if (!isExternalInput()) {
            rule = ((IFileEditorInput) getEditorInput()).getFile();
        } else {
            rule = null;
            // TODO: TRHO: This is probably too much. The current file is an
            // external file:
            // rule = ResourcesPlugin.getWorkspace().getRoot();
        }

        Job j = new Job("notify PDT views about changed editor input") {
            @Override
            protected IStatus run(IProgressMonitor monitor) {
                PDTPlugin.getDefault().setSelection(new PDTChangedFileInformation(getEditorInput()));
                return Status.OK_STATUS;
            }
        };
        j.setRule(rule);
        j.schedule();
    }

    public PLEditor() {
        super();
        try {
            colorManager = PDTPlugin.getDefault().getColorManager();

            configuration = new PLConfiguration(colorManager, this);
            setSourceViewerConfiguration(configuration);
        } catch (Throwable t) {
            Debug.report(t);
            throw new RuntimeException(t);
        }
    }

    private static final String SEP_PDT_INFO = "pdt_info_actions";

    private IPath filepath;

    private InformationPresenter fOutlinePresenter;

    private TextEditorAction reloadAction;

    private static final String MATCHING_BRACKETS = "matching.brackets";

    private static final String MATCHING_BRACKETS_COLOR = "matching.brackets.color";

    public static long OCCURRENCE_UPDATE_DELAY = 300;

    @Override
    protected void configureSourceViewerDecorationSupport(SourceViewerDecorationSupport support) {
        getPreferenceStore().setDefault(MATCHING_BRACKETS, true);
        getPreferenceStore().setDefault(MATCHING_BRACKETS_COLOR, "30,30,200");
        support.setCharacterPairMatcher(new PLCharacterPairMatcher());
        support.setMatchingCharacterPainterPreferenceKeys(MATCHING_BRACKETS, MATCHING_BRACKETS_COLOR);

        super.configureSourceViewerDecorationSupport(support);
    }

    @Override
    public void createPartControl(final Composite parent) {
        try {
            createPartControl_impl(parent);
        } catch (Throwable t) {
            Debug.report(t);
            throw new RuntimeException(t.getMessage(), t);
        }
    }

    private void createPartControl_impl(final Composite parent) {
        super.createPartControl(parent);

        createInspectionMenu();

        // TODO: create own bundle
        ResourceBundle bundle = ResourceBundle.getBundle(PDT.RES_BUNDLE_UI);

        createMenuEntryForOutlinePresenter(bundle);

        createMenuEntryForReconsult(bundle);
        createMenuEntryForSaveWithoutReconsult(bundle);

        createMenuEntryForToggleComments(bundle);

        getSourceViewer().getTextWidget().addCaretListener(new CaretListener() {

            @Override
            public void caretMoved(CaretEvent event) {
                updateOccurrenceAnnotations(event.caretOffset);

            }
        });
        checkBackgroundAndTitleImage(getEditorInput());

        getVerticalRuler().getControl().addMouseListener(new MouseListener() {

            @Override
            public void mouseUp(MouseEvent e) {
            }

            @Override
            public void mouseDown(MouseEvent e) {
            }

            @Override
            public void mouseDoubleClick(MouseEvent e) {
                int currentLine = getVerticalRuler().getLineOfLastMouseButtonActivity() + 1;
                Document doc = (Document) getDocumentProvider().getDocument(getEditorInput());
                int currentOffset = UIUtils.physicalToLogicalOffset(doc,
                        getCurrentLineOffsetSkippingWhiteSpaces(currentLine));
                PDTBreakpointHandler.getInstance().toogleBreakpoint(getCurrentIFile(), currentLine, currentOffset);
            }
        });

        PDTConnectorPlugin.getDefault().getPrologProcessService().registerActivePrologProcessListener(this);
        PDTConnectorPlugin.getDefault().getPrologProcessService().registerConsultListener(this);
        PDTCommonPlugin.getDefault().registerProcessStartListener(this);
    }

    /**
     * @param menuMgr
     */
    private void createInspectionMenu() {

        addAction(new FindPredicateActionDelegate(this), FindPredicateActionDelegate.NAME,
                COMMAND_OPEN_PRIMARY_DEFINITION);
        //            "org.eclipse.pdt.ui.open.primary.definition");
        //            IJavaEditorActionDefinitionIds.OPEN_EDITOR);

        addAction(new FindDefinitionsActionDelegate(this), "Find all Definitions and Declarations",
                COMMAND_FIND_ALL_DEFINITIONS);
        //            "org.cs3.pdt.editor.find.definitions");
        //            IJavaEditorActionDefinitionIds.SEARCH_DECLARATIONS_IN_WORKSPACE);

        addAction(new FindReferencesActionDelegate(this), "Find References", COMMAND_FIND_REFERENCES);
        //            "org.cs3.pdt.editor.find.references");
        //            IJavaEditorActionDefinitionIds.SEARCH_REFERENCES_IN_WORKSPACE);

        addAction(new OpenCallHierarchyActionDelegte(this), "Open Call Hierarchy", COMMAND_OPEN_CALL_HIERARCHY);
        // addAction(menuMgr, new SpyPointActionDelegate(this),
        // "Toggle Spy Point", SEP_PDT_INSPECT,
        // "org.eclipse.debug.ui.commands.ToggleBreakpoint");
    }

    private void createMenuEntryForOutlinePresenter(ResourceBundle bundle) {
        Action action;

        fOutlinePresenter = configuration.getOutlinePresenter(this.getSourceViewer());
        fOutlinePresenter.install(this.getSourceViewer());

        action = new TextEditorAction(bundle, PLEditor.class.getName() + ".ToolTipAction", this) {
            @Override
            public void run() {
                TextSelection selection = (TextSelection) getEditorSite().getSelectionProvider().getSelection();
                fOutlinePresenter.setOffset(selection.getOffset());

                fOutlinePresenter.showInformation();
            }
        };
        addAction(action, "Show Outline", COMMAND_SHOW_QUICK_OUTLINE);
    }

    private void createMenuEntryForToggleComments(ResourceBundle bundle) {
        ToggleCommentAction tca = new ToggleCommentAction(bundle,
                PLEditor.class.getName() + ".ToggleCommentsAction", this);
        tca.configure(getSourceViewer(), configuration);
        tca.setEnabled(true);
        addAction(tca, "Toggle Comments", COMMAND_TOGGLE_COMMENTS);
    }

    private void createMenuEntryForReconsult(ResourceBundle bundle) {
        reloadAction = new TextEditorAction(bundle, PLEditor.class.getName() + ".ConsultAction", this) {
            @Override
            public void run() {
                IFile currentIFile = getCurrentIFile();
                if (currentIFile != null) {
                    PDTConnectorPlugin.getDefault().getPrologProcessService().consultFile(currentIFile);
                } else {
                    PDTConnectorPlugin.getDefault().getPrologProcessService().consultFile(getPrologFileName());
                }
                //            new ConsultAction().consultFromActiveEditor();
                ////            addProblemMarkers();
                informViewsAboutChangedEditor();
                ////            executeConsult();
            }

            public void informViewsAboutChangedEditor() {
                PDTPlugin.getDefault().setSelection(new PDTChangedFileInformation(getEditorInput()));
            }
        };
        addAction(reloadAction, "(Re)consult", COMMAND_CONSULT);
    }

    private void createMenuEntryForSaveWithoutReconsult(ResourceBundle bundle) {
        Action action;
        action = new TextEditorAction(bundle, PLEditor.class.getName() + ".SaveNoConsultAction", this) {
            @Override
            public void run() {
                // must be super, otherwise doSave will
                // consult the file and update the problem markers, too.
                if (!shouldAbortSaving()) {
                    PLEditor.super.doSave(new NullProgressMonitor());
                    updateTitleImage(getEditorInput());
                    PDTCommonPlugin.getDefault().notifyDecorators();
                }
            }
        };
        addAction(action, "Save without consult", COMMAND_SAVE_NO_CONSULT);
    }

    /**
     * @param menuMgr
     */
    private void addAction(Action action, String name, String id) {

        action.setActionDefinitionId(id);
        action.setText(name);
        //      menuMgr.appendToGroup(separator, action);
        setAction(id,
                //            IJavaEditorActionDefinitionIds.SEARCH_REFERENCES_IN_WORKSPACE,
                action);
    }

    @Override
    protected void editorContextMenuAboutToShow(IMenuManager menu) {
        super.editorContextMenuAboutToShow(menu);

        menu.prependToGroup(ITextEditorActionConstants.GROUP_OPEN, getAction(COMMAND_OPEN_PRIMARY_DEFINITION));
        menu.insertAfter(COMMAND_OPEN_PRIMARY_DEFINITION, getAction(COMMAND_FIND_ALL_DEFINITIONS));
        menu.insertAfter(COMMAND_FIND_ALL_DEFINITIONS, getAction(COMMAND_FIND_REFERENCES));
        menu.insertAfter(COMMAND_FIND_REFERENCES, getAction(COMMAND_SHOW_QUICK_OUTLINE));
        menu.insertAfter(COMMAND_FIND_REFERENCES, getAction(COMMAND_OPEN_CALL_HIERARCHY));

        addAction(menu, ITextEditorActionConstants.GROUP_EDIT, COMMAND_TOGGLE_COMMENTS);

        menu.appendToGroup(ITextEditorActionConstants.GROUP_OPEN, new Separator(SEP_PDT_INFO));

        addAction(menu, SEP_PDT_INFO, COMMAND_CONSULT);
        addAction(menu, SEP_PDT_INFO, COMMAND_SAVE_NO_CONSULT);
    }

    /**
     * @param parent
     */

    @SuppressWarnings("rawtypes")
    @Override
    public Object getAdapter(Class required) {
        try {
            if (IContentOutlinePage.class.equals(required)) {
                if (fOutlinePage == null) {
                    // fOutlinePage = new PrologOutline(this);
                    fOutlinePage = new NonNaturePrologOutline(this);
                    fOutlinePage.setInput(getEditorInput());
                }
                return fOutlinePage;
            }
            return super.getAdapter(required);
        } catch (Throwable t) {
            Debug.report(t);
            throw new RuntimeException(t);
        }
    }

    /**
     * Informs the editor that its outliner has been closed.
     */
    public void outlinePageClosed() {
        if (fOutlinePage != null) {

            fOutlinePage = null;
            resetHighlightRange();
        }
    }

    public ContentOutlinePage getOutlinePage() {
        return fOutlinePage;
    }

    protected int getCurrentLineOffset(int line) {
        Document document = (Document) getDocumentProvider().getDocument(getEditorInput());
        int offset = 0;
        try {
            offset = document.getLineInformation(line - 1).getOffset();
        } catch (BadLocationException e) {
            e.printStackTrace();
        }
        return offset;
    }

    protected int getCurrentLineOffsetSkippingWhiteSpaces(int line) {
        int offset = 0;
        Document document = (Document) getDocumentProvider().getDocument(getEditorInput());
        try {
            IRegion lineInformation = document.getLineInformation(line - 1);
            String lineContent = document.get(lineInformation.getOffset(), lineInformation.getLength());
            int additionalOffset = 0;
            while (additionalOffset < lineContent.length()) {
                char character = lineContent.charAt(additionalOffset);
                if (character == '\t' || character == ' ') {
                    additionalOffset++;
                } else {
                    break;
                }
            }
            return lineInformation.getOffset() + additionalOffset;
        } catch (BadLocationException e) {
            Debug.report(e);
        }
        return offset;
    }

    /**
     * @param i
     */
    public void gotoLine(int line) {
        Document document;
        document = (Document) getDocumentProvider().getDocument(getEditorInput());
        int offset;
        try {
            offset = document.getLineInformation(line - 1).getOffset();
            TextSelection newSelection = new TextSelection(document, offset, 0);
            getEditorSite().getSelectionProvider().setSelection(newSelection);
        } catch (BadLocationException e) {
            Debug.report(e);
        }
    }

    /**
     * @param i
     * @param i
     */
    public void gotoOffset(int offset, int length) {
        Document document = (Document) getDocumentProvider().getDocument(getEditorInput());
        TextSelection newSelection;
        // try {
        // if(isLineOffset) {
        // offset = document.getLineOffset(offset);
        // }
        newSelection = new TextSelection(document, offset, length);
        getEditorSite().getSelectionProvider().setSelection(newSelection);
        // } catch (BadLocationException e) {
        // e.printStackTrace();
        // }
    }

    /**
     * @return
     */
    public String getSelectedLine() {

        Document document = (Document) getDocumentProvider().getDocument(getEditorInput());

        String line = null;
        try {
            TextSelection selection = (TextSelection) getEditorSite().getSelectionProvider().getSelection();
            IRegion info = document.getLineInformationOfOffset(selection.getOffset());
            int start = PredicateReadingUtilities.findEndOfWhiteSpace(document, info.getOffset(),
                    info.getOffset() + info.getLength());

            line = document.get(start, info.getLength() + info.getOffset() - start);
        } catch (BadLocationException e) {
            Debug.report(e);

        }
        return line;
    }

    /**
     * @return
     */
    public Goal getSelectedPrologElement() throws BadLocationException {
        Document document = (Document) getDocumentProvider().getDocument(getEditorInput());

        TextSelection selection = (TextSelection) getEditorSite().getSelectionProvider().getSelection();
        int length = selection.getLength();
        int offset = selection.getOffset();

        return GoalProvider.getPrologDataFromOffset(getPrologFileName(), document, offset, length);
    }

    @Override
    protected void rulerContextMenuAboutToShow(IMenuManager menu) {
        super.rulerContextMenuAboutToShow(menu);
        Action toggleBreakpointAction = new Action("Toggle breakpoint") {
            @Override
            public void run() {
                int currentLine = getVerticalRuler().getLineOfLastMouseButtonActivity() + 1;
                Document doc = (Document) getDocumentProvider().getDocument(getEditorInput());
                int currentOffset = UIUtils.physicalToLogicalOffset(doc, getCurrentLineOffset(currentLine));

                PDTBreakpointHandler.getInstance().toogleBreakpoint(getCurrentIFile(), currentLine, currentOffset);
            }
        };
        Action removeBreakpointsAction = new Action("Remove all breakpoints") {
            @Override
            public void run() {
                PDTBreakpointHandler.getInstance().removeBreakpointFactsForFile(getPrologFileName());
            }
        };

        menu.add(toggleBreakpointAction);
        menu.add(removeBreakpointsAction);

        if (getCurrentIFile() == null) {
            toggleBreakpointAction.setEnabled(false);
            removeBreakpointsAction.setEnabled(false);
        }
    }

    private IFile getCurrentIFile() {
        if (getEditorInput() instanceof IFileEditorInput) {
            IFileEditorInput input = (IFileEditorInput) getEditorInput();
            return input.getFile();
        }
        return null;
    }

    public String getPrologFileName() {
        return QueryUtils.prologFileName(filepath.toFile());
    }

    public TextSelection getSelection() {
        return (TextSelection) getEditorSite().getSelectionProvider().getSelection();
    }

    /**
     * @param document
     * @param l
     * @return
     */
    public static boolean predicateDelimiter(IDocument document, int l) throws BadLocationException {
        if (isDelimitingDot(document, l)) {
            if (l > 0 && isDelimitingDot(document, l - 1))
                return false;
            if (l < document.getLength() - 1 && isDelimitingDot(document, l + 1))
                return false;
            return true;
        }
        return false;
    }

    /**
     * Checks if the character at position l is a delimiting dot, meaning it is
     * not enclosed by
     * <ul>
     * <li>parentheses</li>
     * <li>numbers</li>
     * </ul>
     * 
     * @param document
     * @param l
     * @return
     * @throws BadLocationException
     */
    private static boolean isDelimitingDot(IDocument document, int l) throws BadLocationException {
        char c = document.getChar(l);
        if (c != '.') {
            return false;
        }
        if (l == 0 || l == document.getLength() - 1) {
            return false;
        }
        if (isNumber(document.getChar(l - 1)) && isNumber(document.getChar(l + 1))) {
            return false;
        }
        if (document.getChar(l - 1) == '(' && document.getChar(l + 1) == ')') {
            return false;
        }
        return true;
    }

    private static boolean isNumber(char c) {
        return c >= '0' && c <= '9';
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.eclipse.ui.editors.text.TextEditor#doSetInput(org.eclipse.ui.IEditorInput
     * )
     */
    @Override
    protected void doSetInput(IEditorInput input) throws CoreException {

        setDocumentProvider(createDocumentProvider(input));

        if (fOutlinePage != null) {
            fOutlinePage.setInput(input);
        }
        super.doSetInput(input);

        filepath = new Path(UIUtils.getFileNameForEditorInput(input));
        checkBackgroundAndTitleImage(input);
    }

    private void checkBackgroundAndTitleImage(IEditorInput input) {
        ISourceViewer sourceViewer = getSourceViewer();
        if (sourceViewer == null)
            return;
        StyledText textWidget = sourceViewer.getTextWidget();
        if (textWidget == null)
            return;
        if (!isExternalInput(input)) {
            textWidget.setBackground(new Color(textWidget.getDisplay(), colorManager.getBackgroundColor()));
        } else {
            textWidget.setBackground(new Color(textWidget.getDisplay(), colorManager.getExternBackgroundColor()));
        }
        updateTitleImage(input);
    }

    private void updateTitleImage(IEditorInput input) {
        if (input instanceof IFileEditorInput) {
            Map<String, Object> result = null;
            try {
                result = PDTCommonUtil.getActivePrologProcess().queryOnce(bT(PDTCommonPredicates.PDT_SOURCE_FILE,
                        QueryUtils.quoteAtom(PDTCommonUtil.prologFileName(input)), "State"));
            } catch (PrologProcessException e) {
                Debug.report(e);
            }
            if (ExternalPrologFilesProjectUtils.isExternalFile(((IFileEditorInput) input).getFile())) {
                if (result == null) {
                    setTitleImage(ImageRepository.getImage(ImageRepository.PROLOG_FILE_EXTERNAL));
                } else {
                    String state = result.get("State").toString();
                    if ("current".equals(state)) {
                        setTitleImage(ImageRepository.getImage(ImageRepository.PROLOG_FILE_EXTERNAL_CONSULTED));
                    } else {
                        setTitleImage(ImageRepository.getImage(ImageRepository.PROLOG_FILE_EXTERNAL_CONSULTED_OLD));
                    }
                }
            } else {
                if (result == null) {
                    setTitleImage(ImageRepository.getImage(ImageRepository.PROLOG_FILE_UNCONSULTED));
                } else {
                    String state = result.get("State").toString();
                    if ("current".equals(state)) {
                        setTitleImage(ImageRepository.getImage(ImageRepository.PROLOG_FILE_CONSULTED));
                    } else {
                        setTitleImage(ImageRepository.getImage(ImageRepository.PROLOG_FILE_CONSULTED_OLD));
                    }
                }
            }
        } else {
            setTitleImage(ImageRepository.getImage(ImageRepository.PROLOG_FILE_EXTERNAL_NOT_LINKED));
        }
    }

    private IDocumentProvider createDocumentProvider(IEditorInput input) {
        //       if(input instanceof FileStoreEditorInput){
        return new ExternalDocumentProvider();
        //       } else{
        //          return new PLDocumentProvider();
        //       }
    }

    private boolean isExternalInput() {
        return isExternalInput(getEditorInput());
    }

    private boolean isExternalInput(IEditorInput input) {
        if (!(input instanceof IFileEditorInput)) {
            return true;
        }
        IFileEditorInput fileEditorInput = (IFileEditorInput) input;
        return ExternalPrologFilesProjectUtils.isExternalFile(fileEditorInput.getFile());
    }

    private Object annotationModelMonitor = new Object();

    public Annotation[] fOccurrenceAnnotations;

    private OccurrencesFinderJob fOccurrencesFinderJob;

    private boolean fMarkOccurrenceAnnotations = true;

    private TextSelection oldSelection;

    private boolean hightlightOccurrences = true;
    private boolean hightlightSingletonsErrors = true;

    class OccurrencesFinderJob extends Job {

        private final IDocument fDocument;
        // private final ISelectionValidator fPostSelectionValidator;
        private boolean fCanceled = false;
        private Object cancelMonitor = new Object();
        private int fCaretOffset;

        public OccurrencesFinderJob(IDocument document, int caretOffset) {
            super("update occurrences");
            fDocument = document;
            fCaretOffset = caretOffset;

            // if (getSelectionProvider() instanceof ISelectionValidator)
            // fPostSelectionValidator=
            // (ISelectionValidator)getSelectionProvider();
            // else
            // fPostSelectionValidator= null;
        }

        // cannot use cancel() because it is declared final
        void doCancel() {
            fCanceled = true;
            cancel();
            synchronized (cancelMonitor) {
                cancelMonitor.notify();
            }
        }

        private boolean isCanceled(IProgressMonitor progressMonitor) {
            return fCanceled || progressMonitor.isCanceled()
            // || fPostSelectionValidator != null &&
            // !(fPostSelectionValidator.isValid(fSelection)
            // TRHO || fForcedMarkOccurrencesSelection == fSelection

                    || LinkedModeModel.hasInstalledModel(fDocument);
        }

        /*
         * @see Job#run(org.eclipse.core.runtime.IProgressMonitor)
         */
        @Override
        public IStatus run(IProgressMonitor progressMonitor) {
            // System.out.println(Thread.currentThread().getName()+ " wait");
            try {
                synchronized (cancelMonitor) {
                    cancelMonitor.wait(OCCURRENCE_UPDATE_DELAY);
                }
            } catch (InterruptedException e) {
                Debug.report(e);
            }
            if (isCanceled(progressMonitor)) {
                // System.out.println(Thread.currentThread().getName()+
                // " cancelled");
                return Status.CANCEL_STATUS;
            }
            // System.out.println(Thread.currentThread().getName()+
            // " not cancelled");

            ITextViewer textViewer = getSourceViewer();
            if (textViewer == 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;

            IAnnotationModel annotationModel = documentProvider.getAnnotationModel(getEditorInput());
            if (annotationModel == null)
                return Status.CANCEL_STATUS;

            // Add occurrence annotations
            ArrayList<OccurrenceLocation> locationList = parseOccurrences(fCaretOffset, document);
            if (locationList == null) {
                //            removeOccurrenceAnnotations();
                return Status.CANCEL_STATUS;
            }

            int length = locationList.size();
            Map<Annotation, Position> annotationMap = new HashMap<Annotation, Position>(length);
            for (int i = 0; i < length; i++) {

                if (isCanceled(progressMonitor))
                    return Status.CANCEL_STATUS;

                OccurrenceLocation location = locationList.get(i);
                Position position = new Position(location.getOffset(), location.getLength());

                String description = location.getDescription();
                String annotationType;
                switch (location.getFlags()) {
                case 0:
                    annotationType = "org.cs3.pdt.editor.occurrences";
                    break;
                case 1:
                    annotationType = "org.cs3.pdt.editor.occurrences.singleton";
                    break;
                case 2:
                    annotationType = "org.cs3.pdt.editor.occurrences.non.singleton";
                    break;
                case 3:
                    annotationType = "org.cs3.pdt.editor.occurrences.singleton.wrong.prefix";
                    break;
                default:
                    annotationType = "org.cs3.pdt.editor.occurrences";
                }

                annotationMap.put(new Annotation(annotationType, false, description), position);
            }

            if (isCanceled(progressMonitor))
                return Status.CANCEL_STATUS;
            synchronized (annotationModelMonitor) {

                // removeOccurrenceAnnotations();

                if (annotationModel instanceof IAnnotationModelExtension) {
                    // ((IAnnotationModelExtension)annotationModel).removeAllAnnotations();
                    ((IAnnotationModelExtension) annotationModel).replaceAnnotations(fOccurrenceAnnotations,
                            annotationMap);
                } else {
                    removeOccurrenceAnnotations();
                    Iterator<Map.Entry<Annotation, Position>> iter = annotationMap.entrySet().iterator();
                    while (iter.hasNext()) {
                        Map.Entry<Annotation, Position> mapEntry = iter.next();
                        annotationModel.addAnnotation((Annotation) mapEntry.getKey(),
                                (Position) mapEntry.getValue());
                    }
                }
                fOccurrenceAnnotations = annotationMap.keySet()
                        .toArray(new Annotation[annotationMap.keySet().size()]);
            }

            return Status.OK_STATUS;
        }
    }

    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 (annotationModelMonitor) {
            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 updateOccurrenceAnnotations(int caretOffset) {

        if (!hightlightOccurrences) {
            return;
        }

        if (fOccurrencesFinderJob != null)
            fOccurrencesFinderJob.doCancel();

        if (!fMarkOccurrenceAnnotations)
            return;

        IDocument document = getSourceViewer().getDocument();
        if (document == null)
            return;

        // if (document instanceof IDocumentExtension4) {
        // int offset= selection.getOffset();
        // long currentModificationStamp=
        // ((IDocumentExtension4)document).getModificationStamp();
        // IRegion markOccurrenceTargetRegion= fMarkOccurrenceTargetRegion;
        // hasChanged= currentModificationStamp !=
        // fMarkOccurrenceModificationStamp;
        // if (markOccurrenceTargetRegion != null && !hasChanged) {
        // if (markOccurrenceTargetRegion.getOffset() <= offset && offset <=
        // markOccurrenceTargetRegion.getOffset() +
        // markOccurrenceTargetRegion.getLength())
        // return;
        // }
        // fMarkOccurrenceTargetRegion= JavaWordFinder.findWord(document,
        // offset);
        // fMarkOccurrenceModificationStamp= currentModificationStamp;
        // }

        // if (locations == null) {
        // // if (!fStickyOccurrenceAnnotations)
        // // removeOccurrenceAnnotations();
        // // else
        // if (hasChanged) // check consistency of current annotations
        // removeOccurrenceAnnotations();
        // return;
        // }

        synchronized (annotationModelMonitor) {
            fOccurrencesFinderJob = new OccurrencesFinderJob(document, caretOffset);
            fOccurrencesFinderJob.setPriority(Job.DECORATE);
            fOccurrencesFinderJob.setSystem(true);
            fOccurrencesFinderJob.schedule();
        }
        // fOccurrencesFinderJob.run(new NullProgressMonitor());
    }

    /**
     * Looks up all occurrences of (singleton) variables at the current
     * location.
     * 
     * @param caretOffset
     * @param document
     * @return
     */
    private ArrayList<OccurrenceLocation> parseOccurrences(int caretOffset, IDocument document) {
        ArrayList<OccurrenceLocation> locationList = new ArrayList<OccurrenceLocation>();
        Map<String, List<OccurrenceLocation>> singletonOccurs = new HashMap<String, List<OccurrenceLocation>>();
        Map<String, List<OccurrenceLocation>> nonSingletonOccurs = new HashMap<String, List<OccurrenceLocation>>();

        try {
            ITypedRegion partition = document.getPartition(caretOffset);
            if (partition == null || isComment(partition)) {
                oldSelection = null;
                return locationList;
            }
            TextSelection var = getVariableAtOffset(document, caretOffset);
            String varName = var.getText();
            if (oldSelection != null && oldSelection.equals(var)) {
                return null;
            } else {
                oldSelection = var;
            }
            int begin = var.getOffset();
            int l = begin == 0 ? begin : begin - 1;
            String proposal = null;
            while (l > 0) {
                ITypedRegion region = document.getPartition(l);
                if (isComment(region))
                    l = region.getOffset();
                else {
                    if (PLEditor.predicateDelimiter(document, l)) {
                        proposal = processProposal(document, singletonOccurs, nonSingletonOccurs, locationList, var,
                                l, true, proposal);
                        break;
                    }
                    proposal = processProposal(document, singletonOccurs, nonSingletonOccurs, locationList, var, l,
                            true, proposal);
                }
                l--;
            }

            // searching downwards
            l = begin = var.getOffset() + var.getLength();
            proposal = null;
            // FIXME: ab, dec 14: this does not collect the occurrence at the end of the document
            while (l < document.getLength()) {
                ITypedRegion region = document.getPartition(l);
                if (isComment(region)) {
                    l = region.getOffset() + region.getLength();
                } else {
                    if (PLEditor.predicateDelimiter(document, l)) {
                        proposal = processProposal(document, singletonOccurs, nonSingletonOccurs, locationList, var,
                                l, false, proposal);
                        break;
                    }
                    proposal = processProposal(document, singletonOccurs, nonSingletonOccurs, locationList, var, l,
                            false, proposal);
                }
                l++;
            }
            if (hightlightSingletonsErrors) {
                for (String varToCheck : singletonOccurs.keySet()) {
                    List<OccurrenceLocation> varLocations = singletonOccurs.get(varToCheck);
                    if (varLocations.size() > 1) {
                        for (OccurrenceLocation varLocation : varLocations) {
                            locationList.add(varLocation);
                        }
                    }
                }
                for (String varToCheck : nonSingletonOccurs.keySet()) {
                    List<OccurrenceLocation> varLocations = nonSingletonOccurs.get(varToCheck);
                    if (varLocations.size() == 1) {
                        for (OccurrenceLocation varLocation : varLocations) {
                            locationList.add(varLocation);
                        }
                    }
                }

            }

            if (ParserUtils.isVarPrefix(varName)) {
                if (locationList.size() > 0) {
                    locationList.add(new OccurrenceLocation(var.getOffset(), var.getLength(), 0, "desc"));
                } else {
                    locationList.add(new OccurrenceLocation(var.getOffset(), var.getLength(), 1, "desc"));
                }
            } else {
                ITypedRegion region = document.getPartition(var.getOffset());
                if (!isComment(region)) {
                    locationList.add(new OccurrenceLocation(var.getOffset(), var.getLength(), 0, "desc"));
                }
            }
        } catch (BadLocationException e) {
        }
        return locationList;
    }

    private String processProposal(IDocument document, Map<String, List<OccurrenceLocation>> singletonOccurs,
            Map<String, List<OccurrenceLocation>> nonSingletonOccurs, ArrayList<OccurrenceLocation> locationList,
            TextSelection var, int l, boolean up, String proposal) throws BadLocationException {
        char c = document.getChar(l);

        if (ParserUtils.isVarChar(c)) {
            if (proposal == null)
                proposal = "";
            if (up) {
                proposal = c + proposal;
            } else {
                proposal = proposal + c;
            }
        } else if (proposal != null) {
            int length = proposal.length();
            if (var.getText().equals(proposal)) {
                locationList.add(new OccurrenceLocation(l + (up ? 1 : -length), length, 0, "desc"));
            } else if (ParserUtils.isVarPrefix(proposal) && !proposal.equals("_")) {
                List<OccurrenceLocation> probOccs;
                int kind = 2;
                if (isSingletonName(proposal) == VAR_KIND_SINGLETON) {
                    probOccs = singletonOccurs.get(proposal);
                    if (probOccs == null) {
                        probOccs = new ArrayList<OccurrenceLocation>();
                        singletonOccurs.put(proposal, probOccs);
                    }
                    kind = 3;
                } else {
                    probOccs = nonSingletonOccurs.get(proposal);
                    if (probOccs == null) {
                        probOccs = new ArrayList<OccurrenceLocation>();
                        nonSingletonOccurs.put(proposal, probOccs);
                    }
                }
                probOccs.add(new OccurrenceLocation(l + (up ? 1 : -length), length, kind, "desc"));
            }
            proposal = null;
        }
        return proposal;
    }

    public static final int VAR_KIND_ANONYMOUS = 0;
    public static final int VAR_KIND_SINGLETON = 1;
    public static final int VAR_KIND_NORMAL = 2;

    /**
     * @param a
     *            valid Prolog variable
     */
    private static int isSingletonName(String proposal) {
        if (proposal.equals("_")) {
            return VAR_KIND_ANONYMOUS;
        }
        if (proposal.length() == 1) {
            return VAR_KIND_NORMAL;
        }
        if (proposal.charAt(0) == '_' && ParserUtils.isSingleSecondChar(proposal.charAt(1))) {
            return VAR_KIND_SINGLETON;
        }
        return VAR_KIND_NORMAL;
    }

    protected boolean isComment(ITypedRegion region) {
        return region.getType().equals(PLPartitionScanner.PL_COMMENT)
                || region.getType().equals(PLPartitionScanner.PL_MULTI_COMMENT)
                || region.getType().equals(PLPartitionScanner.PL_SINGLE_QUOTED_STRING)
                || region.getType().equals(PLPartitionScanner.PL_DOUBLE_QUOTED_STRING);
    }

    /**
     * Element representing a occurrence
     */
    public static class OccurrenceLocation {
        private final int fOffset;
        private final int fLength;
        private final int fFlags;
        private final String fDescription;

        public OccurrenceLocation(int offset, int length, int flags, String description) {
            fOffset = offset;
            fLength = length;
            fFlags = flags;
            fDescription = description;
        }

        public int getOffset() {
            return fOffset;
        }

        public int getLength() {
            return fLength;
        }

        public int getFlags() {
            return fFlags;
        }

        public String getDescription() {
            return fDescription;
        }

        @Override
        public String toString() {
            return "[" + fOffset + " / " + fLength + "] " + fDescription; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
        }

    }

    // private class VarPos {
    // int begin;
    // int length;
    // String prefix;
    //
    // VarPos(IDocument document, int begin, String prefix) {
    // this.begin=begin;
    // this.prefix=prefix;
    // this.length=prefix.length();
    // }
    // }

    private TextSelection getVariableAtOffset(IDocument document, int offset) throws BadLocationException {
        int begin = offset;
        if (offset == document.getLength() || !ParserUtils.isVarChar(document.getChar(begin)) && begin > 0) {
            begin--;
        }
        while (ParserUtils.isVarChar(document.getChar(begin)) && begin > 0)
            begin--;
        if (begin < offset)
            begin++;
        int end = offset;
        while (end < document.getLength() && ParserUtils.isVarChar(document.getChar(end)) && begin > 0)
            end++;
        int length = end - begin;
        // String pos = document.get(begin, length);

        return new TextSelection(document, begin, length);
    }

    @Override
    public void beforeConsult(PrologProcess process, List<IFile> files, IProgressMonitor monitor)
            throws PrologProcessException {
        monitor.beginTask("", 1);
        monitor.done();
    }

    @Override
    public void afterConsult(PrologProcess process, List<IFile> files, List<String> allConsultedFiles,
            IProgressMonitor monitor) throws PrologProcessException {
        monitor.beginTask("", 1);
        if (process.equals(PDTCommonUtil.getActivePrologProcess())) {
            String editorFile = getPrologFileName();
            if (allConsultedFiles.contains(editorFile)) {
                updateState();
            }
        }
        monitor.done();
    }

    @Override
    public void activePrologProcessChanged(PrologProcess process) {
        updateState();
    }

    @Override
    public void prologProcessStarted(PrologProcess process) {
        if (process.equals(PDTCommonUtil.getActivePrologProcess())) {
            updateState();
        }
    }

    private void updateState() {
        getSite().getShell().getDisplay().asyncExec(new Runnable() {
            @Override
            public void run() {
                PLEditor.this.updateTitleImage(getEditorInput());
                try {
                    PLEditor.this.configuration.getPLScanner().initHighlighting();
                    PLEditor.this.getSourceViewer().invalidateTextPresentation();
                } catch (PrologProcessException e) {
                    Debug.report(e);
                } catch (CoreException e) {
                    Debug.report(e);
                }
                ;
            }
        });
    }

    @Override
    public void dispose() {
        super.dispose();
        PDTConnectorPlugin.getDefault().getPrologProcessService().unRegisterActivePrologProcessListener(this);
        PDTConnectorPlugin.getDefault().getPrologProcessService().unRegisterConsultListener(this);
        PDTCommonPlugin.getDefault().unregisterProcessStartListener(this);
    }

}