org.vimplugin.editors.VimEditor.java Source code

Java tutorial

Introduction

Here is the source code for org.vimplugin.editors.VimEditor.java

Source

/*
 * Vimplugin
 *
 * Copyright (c) 2007 - 2012 by The Vimplugin Project.
 *
 * Released under the GNU General Public License
 * with ABSOLUTELY NO WARRANTY.
 *
 * See the file COPYING for more information.
 */
package org.vimplugin.editors;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;

import java.lang.reflect.Field;

import java.net.URI;

import org.eclim.logging.Logger;

import org.eclim.util.CommandExecutor;

import org.eclim.util.file.FileUtils;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;

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.Status;

import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;

import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceDialog;

import org.eclipse.jface.text.IDocument;

import org.eclipse.swt.SWT;

import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;

import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
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.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IURIEditorInput;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;

import org.eclipse.ui.dialogs.PreferencesUtil;

import org.eclipse.ui.editors.text.TextEditor;

import org.eclipse.ui.internal.part.StatusPart;

import org.eclipse.ui.texteditor.AbstractTextEditor;
import org.eclipse.ui.texteditor.IDocumentProvider;

import org.vimplugin.DisplayUtils;
import org.vimplugin.VimConnection;
import org.vimplugin.VimPlugin;
import org.vimplugin.VimServer;

import org.vimplugin.preferences.PreferenceConstants;

/**
 * Provides an Editor to Eclipse which is backed by a Vim instance.
 */
public class VimEditor extends TextEditor {
    private static final Logger logger = Logger.getLogger(VimEditor.class);

    private static final String ECLIMD_VIEW_ID = "org.eclim.eclipse.ui.EclimdView";

    /** ID of the VimServer. */
    private int serverID;

    /** Buffer ID in Vim instance. */
    private int bufferID;

    private Canvas editorGUI;
    private IFile selectedFile;
    private IDocument document;
    private VimViewer viewer;
    private VimDocumentProvider documentProvider;

    private boolean dirty;
    private boolean alreadyClosed = false;
    private long lastFocus = 0;

    private Composite parent;

    /**
     * The field to grab for Windows/Win32.
     */
    public static final String win32WID = "handle";

    /**
     * The field to grab for GTK2.
     */
    public static final String gtkWID = "embeddedHandle";

    /**
     * a shell to open {@link MessageDialog MessageDialogs}.
     */
    private Shell shell;

    private boolean embedded;
    private boolean tabbed;
    private boolean documentListen;

    /**
     * The constructor.
     */
    public VimEditor() {
        super();
        bufferID = -1; // not really necessary but set it to an invalid buffer
        setDocumentProvider(documentProvider = new VimDocumentProvider());
    }

    /*
     * (non-Javadoc)
     *
     * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#createPartControl(org.eclipse.swt.widgets.Composite)
     */
    @Override
    public void createPartControl(Composite parent) {
        this.parent = parent;
        this.shell = parent.getShell();

        VimPlugin plugin = VimPlugin.getDefault();

        if (!plugin.gvimAvailable()) {
            MessageDialog dialog = new MessageDialog(shell, "Vimplugin", null,
                    plugin.getMessage("gvim.not.found.dialog"), MessageDialog.ERROR,
                    new String[] { IDialogConstants.OK_LABEL, IDialogConstants.CANCEL_LABEL }, 0) {
                protected void buttonPressed(int buttonId) {
                    super.buttonPressed(buttonId);
                    if (buttonId == IDialogConstants.OK_ID) {
                        PreferenceDialog prefs = PreferencesUtil.createPreferenceDialogOn(shell,
                                "org.vimplugin.preferences.VimPreferences", null, null);
                        if (prefs != null) {
                            prefs.open();
                        }
                    }
                }
            };
            dialog.open();

            if (!plugin.gvimAvailable()) {
                throw new RuntimeException(plugin.getMessage("gvim.not.found"));
            }
        }

        IPreferenceStore prefs = plugin.getPreferenceStore();
        tabbed = prefs.getBoolean(PreferenceConstants.P_TABBED);
        embedded = prefs.getBoolean(PreferenceConstants.P_EMBED);
        // disabling documentListen until there is a really good reason to have,
        // cause it is by far the buggest part of vim's netbeans interface.
        documentListen = false; //plugin.gvimNbDocumentListenSupported();
        if (embedded) {
            if (!plugin.gvimEmbedSupported()) {
                String message = plugin.getMessage("gvim.not.supported",
                        plugin.getMessage("gvim.embed.not.supported"));
                throw new RuntimeException(message);
            }
        }
        if (!plugin.gvimNbSupported()) {
            String message = plugin.getMessage("gvim.not.supported", plugin.getMessage("gvim.nb.not.enabled"));
            throw new RuntimeException(message);
        }

        //set some flags
        alreadyClosed = false;
        dirty = false;

        String projectPath = null;
        String filePath = null;
        IEditorInput input = getEditorInput();
        if (input instanceof IFileEditorInput) {
            selectedFile = ((IFileEditorInput) input).getFile();

            IProject project = selectedFile.getProject();
            IPath path = project.getRawLocation();
            if (path == null) {
                String name = project.getName();
                path = ResourcesPlugin.getWorkspace().getRoot().getRawLocation();
                path = path.append(name);
            }
            projectPath = path.toPortableString();

            filePath = selectedFile.getRawLocation().toPortableString();
            if (filePath.toLowerCase().indexOf(projectPath.toLowerCase()) != -1) {
                filePath = filePath.substring(projectPath.length() + 1);
            }
        } else {
            URI uri = ((IURIEditorInput) input).getURI();
            filePath = uri.toString().substring("file:".length());
            filePath = filePath.replaceFirst("^/([A-Za-z]:)", "$1");
        }

        if (filePath != null) {
            editorGUI = new Canvas(parent, SWT.EMBEDDED);

            //create a vim instance
            VimConnection vc = createVim(projectPath, filePath, parent);

            viewer = new VimViewer(bufferID, vc, editorGUI != null ? editorGUI : parent, SWT.EMBEDDED);
            viewer.getTextWidget().setVisible(false);
            viewer.setDocument(document);
            viewer.setEditable(isEditable());
            try {
                Field fSourceViewer = AbstractTextEditor.class.getDeclaredField("fSourceViewer");
                fSourceViewer.setAccessible(true);
                fSourceViewer.set(this, viewer);
            } catch (Exception e) {
                logger.error("Unable to access source viewer field.", e);
            }

            // open eclimd view if necessary
            boolean startEclimd = plugin.getPreferenceStore().getBoolean(PreferenceConstants.P_START_ECLIMD);
            if (startEclimd) {
                IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
                try {
                    if (page != null && page.findView(ECLIMD_VIEW_ID) == null) {
                        page.showView(ECLIMD_VIEW_ID);
                    }
                } catch (PartInitException pie) {
                    logger.error("Unable to open eclimd view.", pie);
                }
            }

            // on initial open, our part listener isn't firing for some reason.
            if (embedded) {
                plugin.getPartListener().partOpened(this);
                plugin.getPartListener().partBroughtToTop(this);
                plugin.getPartListener().partActivated(this);
            }
        }
    }

    /**
     * Create a vim instance figuring out if it should be external or embedded.
     *
     * @param workingDir
     * @param filePath
     * @param parent
     */
    private VimConnection createVim(String workingDir, String filePath, Composite parent) {
        VimPlugin plugin = VimPlugin.getDefault();

        //get bufferId
        bufferID = plugin.getNumberOfBuffers();
        plugin.setNumberOfBuffers(bufferID + 1);

        IStatus status = null;
        VimConnection vc = null;
        if (embedded) {
            try {
                vc = createEmbeddedVim(workingDir, filePath, editorGUI);
            } catch (Exception e) {
                embedded = false;
                vc = createExternalVim(workingDir, filePath, parent);

                String message = plugin
                        .getMessage(e instanceof NoSuchFieldException ? "embed.unsupported" : "embed.fallback");
                status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, message, e);
            }
        } else {
            vc = createExternalVim(workingDir, filePath, parent);
            String message = plugin.getMessage("gvim.external.success");
            status = new Status(IStatus.OK, PlatformUI.PLUGIN_ID, message);
        }

        if (status != null) {
            editorGUI.dispose();
            editorGUI = null;
            new StatusPart(parent, status);
            // remove the "Show the Error Log View" button if the status is OK
            if (status.getSeverity() == IStatus.OK) {
                for (Control c : parent.getChildren()) {
                    if (c instanceof Composite) {
                        for (Control ch : ((Composite) c).getChildren()) {
                            if (ch instanceof Button) {
                                ch.setVisible(false);
                            }
                        }
                    }
                }
            }
        }

        plugin.getVimserver(serverID).getEditors().add(this);

        return vc;
    }

    /**
     * Create an external Vim instance.
     *
     * @param workingDir
     * @param filePath
     * @param parent
     */
    private VimConnection createExternalVim(String workingDir, String filePath, Composite parent) {
        VimPlugin plugin = VimPlugin.getDefault();
        boolean first = plugin.getVimserver(VimPlugin.DEFAULT_VIMSERVER_ID) == null;
        serverID = tabbed ? plugin.getDefaultVimServer() : plugin.createVimServer();
        plugin.getVimserver(serverID).start(workingDir, filePath, tabbed, first);

        VimConnection vc = plugin.getVimserver(serverID).getVc();
        vc.command(bufferID, "editFile", "\"" + filePath + "\"");

        if (documentListen) {
            vc.command(bufferID, "startDocumentListen", "");
        } else {
            vc.command(bufferID, "stopDocumentListen", "");
        }
        return vc;
    }

    /**
     * Creates an embedded Vim instance (platform-dependent!). Gets the Window
     * ID/Handle of the SWT Widget given, uses reflection since the code is
     * platform specific and this allows us to distribute just one plugin for
     * all platforms.
     *
     * @param workingDir
     * @param filePath
     * @param parent
     * @throws Exception
     */
    private VimConnection createEmbeddedVim(String workingDir, String filePath, Composite parent) throws Exception {
        long wid = 0;

        Field f = null;
        try {
            f = Composite.class.getField(VimEditor.gtkWID);
        } catch (NoSuchFieldException nsfe) {
            f = Control.class.getField(VimEditor.win32WID);
        }

        wid = f.getLong(parent);

        VimPlugin plugin = VimPlugin.getDefault();
        serverID = plugin.createVimServer();
        plugin.getVimserver(serverID).start(workingDir, wid);

        //int h = parent.getClientArea().height;
        //int w = parent.getClientArea().width;

        VimConnection vc = plugin.getVimserver(serverID).getVc();
        //vc.command(bufferID, "setLocAndSize", h + " " + w);
        vc.command(bufferID, "editFile", "\"" + filePath + "\"");
        if (documentListen) {
            vc.command(bufferID, "startDocumentListen", "");
        } else {
            vc.command(bufferID, "stopDocumentListen", "");
        }
        return vc;
    }

    /**
     * This function will be called by vimserver when it gets an event
     * disconnect or killed It doesn't ask to save modifications since vim takes
     * care of that.
     */
    public void forceDispose() {
        final VimEditor editor = this;
        Display display = getSite().getShell().getDisplay();
        display.asyncExec(new Runnable() {
            public void run() {
                if (editor != null && !editor.alreadyClosed) {
                    editor.setDirty(false);
                    editor.showBusy(true);
                    editor.close(false);
                    getSite().getPage().closeEditor(editor, false);
                    // editor.alreadyClosed = true;
                }
            }
        });
    }

    /*
     * (non-Javadoc)
     *
     * @see org.eclipse.ui.editors.text.TextEditor#dispose()
     */
    @Override
    public void dispose() {
        // closing the eclipse tab directly calls dispose, but not close.
        close(true);

        if (viewer != null) {
            viewer.getTextWidget().dispose();
            viewer = null;
        }

        if (editorGUI != null) {
            editorGUI.dispose();
            editorGUI = null;
        }

        document = null;

        super.dispose();
    }

    /**
     * This function will be called when we close the window If the
     * <code>save</code> is true then we call command save If the current
     * buffer is the last one the vim will be closed, else only the buffer will
     * be closed.
     */
    @Override
    public void close(boolean save) {
        if (this.alreadyClosed) {
            super.close(false);
            return;
        }

        VimPlugin plugin = VimPlugin.getDefault();

        alreadyClosed = true;
        VimServer server = plugin.getVimserver(serverID);
        if (server != null) {
            server.getEditors().remove(this);

            if (save && dirty) {
                server.getVc().command(bufferID, "save", "");
                dirty = false;
                firePropertyChange(PROP_DIRTY);
            }

            if (server.getEditors().size() > 0) {
                server.getVc().command(bufferID, "close", "");
                String gvim = VimPlugin.getDefault().getPreferenceStore().getString(PreferenceConstants.P_GVIM);
                String[] args = new String[5];
                args[0] = gvim;
                args[1] = "--servername";
                args[2] = String.valueOf(server.getID());
                args[3] = "--remote-send";
                args[4] = "<esc>:redraw!<cr>";
                try {
                    CommandExecutor.execute(args, 1000);
                } catch (Exception e) {
                    logger.error("Error redrawing vim after file close.", e);
                }
            } else {
                try {
                    VimConnection vc = server.getVc();
                    if (vc != null) {
                        server.getVc().function(bufferID, "saveAndExit", "");
                    }
                    plugin.stopVimServer(serverID);
                } catch (IOException e) {
                    message(plugin.getMessage("server.stop.failed"), e);
                }
            }
        }

        super.close(false);
    }

    /*
     * public void setHighlightRange(int offset,int length,boolean moveCursor){
     * System.out.println("--Highlighted-"+offset+length+"-- OK!");
     * if(moveCursor){ VimPlugin.getDefault().getVimserver().getVc().command(
     * bufferID, "setDot", "2/1"); } }
     */

    /**
     * We can't modify the file in the eclipse source viewer.. We use that only
     * for showing error messages...
     */
    @Override
    public boolean isEditable() {
        return false;
    }

    /*
     * (non-Javadoc)
     *
     * @see org.eclipse.ui.texteditor.AbstractTextEditor#doSave(org.eclipse.core.runtime.IProgressMonitor)
     */
    @Override
    public void doSave(IProgressMonitor monitor) {
        VimPlugin.getDefault().getVimserver(serverID).getVc().command(bufferID, "save", "");
        dirty = false;
        firePropertyChange(PROP_DIRTY);
    }

    /**
     * Since we have a copy of edited text in document, we can perform saveAs
     * operation
     */
    @Override
    public void doSaveAs() {
        performSaveAs(null);
    }

    /**
     * Initialisation goes here..
     */
    @Override
    public void init(IEditorSite site, IEditorInput input) throws PartInitException {
        setSite(site);
        setInput(input);
        try {
            document = documentProvider.createDocument(input);
        } catch (Exception e) {
            VimPlugin plugin = VimPlugin.getDefault();
            message(plugin.getMessage("document.create.failed"), e);
        }
    }

    /**
     * Returns <code>true</code> if the file was modified, else return
     * <code>false</code>
     */
    @Override
    public boolean isDirty() {
        return dirty;
    }

    /**
     * Returns <code>true</code> if save as is allowed, else return
     * <code>false</code>
     */
    @Override
    public boolean isSaveAsAllowed() {
        return true;
    }

    private String getFilePath(IEditorInput input) {
        String filePath = null;
        if (input instanceof IFileEditorInput) {
            selectedFile = ((IFileEditorInput) input).getFile();
            filePath = selectedFile.getRawLocation().toPortableString();
        } else {
            URI uri = ((IURIEditorInput) input).getURI();
            filePath = uri.toString().substring("file:".length());
            filePath = filePath.replaceFirst("^/([A-Za-z]:)", "$1");
        }
        return filePath;
    }

    /**
     * Makes the present editor dirty. Thus the IDE knows that file was
     * modified. Asynchronous call of firePropertyChangeAsync.
     *
     * @param result
     */
    public void setDirty(boolean result) {
        dirty = result;

        final VimEditor vime = this;
        Display display = getSite().getShell().getDisplay();
        display.asyncExec(new Runnable() {
            public void run() {
                vime.firePropertyChangeAsync(PROP_DIRTY);
            }
        });
    }

    /**
     * Needed to allow calls from asyncronous threads. Simply delegates to
     * super.firePropertyChange
     *
     * @param prop the property to change
     */
    public void firePropertyChangeAsync(int prop) {
        super.firePropertyChange(prop);
    }

    /**
     * Sets focus (brings to top in Vim) to the buffer.. this function will be
     * called when user activates this editor window
     */
    @Override
    public void setFocus() {
        if (alreadyClosed) {
            getSite().getPage().closeEditor(this, false);
            return;
        }

        // let the parent composite handle setting the focus on the tab first.
        if (embedded) {
            parent.setFocus();
        }

        VimPlugin plugin = VimPlugin.getDefault();
        VimConnection conn = plugin.getVimserver(serverID).getVc();

        // get the current offset which "setDot" requires.
        //String offset = "0";
        try {
            String cursor = conn.function(bufferID, "getCursor", "");
            if (cursor == null) {
                // the only case that i know of where this happens is if the file is
                // open somewhere else and gvim is prompting the user as to how to
                // proceed.  Exit now or the gvim prompt will be sent to the background.
                return;
            }
        } catch (IOException ioe) {
            logger.error("Unable to get cursor position.", ioe);
        }
        // Brings the corresponding buffer to top
        //conn.command(bufferID, "setDot", offset);
        // Brings the vim editor window to top
        conn.command(bufferID, "raise", "");

        // to fully focus gvim, we need to simulate a mouse click.
        // Should this be optional, via a preference? There is the potential for
        // weirdness here.
        if (embedded && parent.getDisplay().getActiveShell() != null) {
            boolean autoClickFocus = plugin.getPreferenceStore().getBoolean(PreferenceConstants.P_FOCUS_AUTO_CLICK);
            if (autoClickFocus) {
                // hack: setFocus may be called more than once, so attempt to only
                // simulate a click only on the first one.
                long now = System.currentTimeMillis();
                long delta = (now - lastFocus);
                lastFocus = now;

                if (delta > 300) {
                    Rectangle bounds = parent.getBounds();
                    final Point point = parent.toDisplay(bounds.x + 5, bounds.y + bounds.height - 25);
                    new Thread() {
                        public void run() {
                            DisplayUtils.doClick(parent.getDisplay(), point.x, point.y, true);
                        }
                    }.start();
                }
            }
        }
    }

    /**
     * Sets the editor window title to path.. need to change path to file name..
     *
     * @param path
     */
    public void setTitleTo(final String path) {
        Display.getDefault().asyncExec(new Runnable() {
            public void run() {
                String filename = path.substring(path.lastIndexOf(File.separator) + 1);
                setPartName(filename);
            }
        });
    }

    // /////// Handling Document content.. ///////////

    /**
     * Returns the document provider
     */
    @Override
    public IDocumentProvider getDocumentProvider() {
        return documentProvider;
    }

    /**
     * Sets the document content to given text
     *
     * @param text The text for the editor.
     */
    public void setDocumentText(String text) {
        document.set(text);
        setDirty(true);
    }

    /**
     * Remove the backslashes from the given string.
     *
     * @param text String to remove from
     * @return The processed string
     */
    private String removeBackSlashes(String text) {
        if (text.length() <= 2)
            return text;
        int offset = 0, length = text.length(), offset1 = 0;
        String newText = "";
        while (offset < length) {
            offset1 = text.indexOf('\\', offset);
            if (offset1 < 0) {
                newText = newText + text.substring(offset);
                break;
            }
            newText = newText + text.substring(offset, offset1)
                    + (text.length() > offset1 + 1 ? text.substring(offset1 + 1, offset1 + 2) : "");
            offset = offset1 + 2;
        }
        return newText;
    }

    /**
     * Inserts text into document.
     *
     * @param text The text to insert.
     * @param offset The offset to insert it at.
     */
    public void insertDocumentText(String text, int offset) {
        text = removeBackSlashes(text);

        try {
            String contents = document.get();
            // FIXME: determine file encoding.
            offset = FileUtils.byteOffsetToCharOffset(new ByteArrayInputStream(contents.getBytes()), offset, null);
            String first = contents.substring(0, offset);
            String last = contents.substring(offset);
            if (text.equals(new String("\\n"))) {
                first = first + System.getProperty("line.separator") + last;
            } else {
                first = first + text + last;
            }
            document.set(first);
            setDirty(true);
        } catch (Exception e) {
            VimPlugin plugin = VimPlugin.getDefault();
            logger.error(plugin.getMessage("document.insert.failed"), e);
        }
    }

    /**
     * Removes text in the document
     *
     * @param offset The offset of the cursor in the text.
     * @param length The amount of text to remove.
     */
    public void removeDocumentText(int offset, int length) {
        try {
            String contents = document.get();
            // FIXME: determine file encoding.
            int loffset = FileUtils.byteOffsetToCharOffset(new ByteArrayInputStream(contents.getBytes()),
                    offset + length, null);
            offset = FileUtils.byteOffsetToCharOffset(new ByteArrayInputStream(contents.getBytes()), offset, null);
            length = loffset - offset;
            String first = contents.substring(0, offset);
            String last = contents.substring(offset + length);
            first = first + last;
            document.set(first);
            setDirty(true);
        } catch (Exception e) {
            VimPlugin plugin = VimPlugin.getDefault();
            logger.error(plugin.getMessage("document.remove.failed"), e);
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see org.eclipse.ui.editors.text.TextEditor#createActions()
     */
    @Override
    protected void createActions() {
        super.createActions();
    }

    /**
     * {@inheritDoc}
     * @see TextEditor#doSetInput(IEditorInput)
     */
    @Override
    protected void doSetInput(IEditorInput input) throws CoreException {
        if (getEditorInput() != null) {
            String oldFilePath = getFilePath(getEditorInput());
            String newFilePath = getFilePath(input);
            if (!oldFilePath.equals(newFilePath)) {
                VimConnection vc = VimPlugin.getDefault().getVimserver(serverID).getVc();

                if (input instanceof IFileEditorInput) {
                    IProject project = selectedFile.getProject();
                    IPath path = project.getRawLocation();
                    if (path == null) {
                        String name = project.getName();
                        path = ResourcesPlugin.getWorkspace().getRoot().getRawLocation();
                        path = path.append(name);
                    }
                    String projectPath = path.toPortableString();

                    if (newFilePath.toLowerCase().indexOf(projectPath.toLowerCase()) != -1) {
                        newFilePath = newFilePath.substring(projectPath.length() + 1);
                    }
                }

                if (isDirty()) {
                    vc.remotesend("<esc>:saveas! " + newFilePath.replace(" ", "\\ ") + "<cr>");
                } else {
                    vc.command(bufferID, "editFile", "\"" + newFilePath + "\"");
                }
            }
        }

        super.doSetInput(input);
    }

    /**
     * {@inheritDoc}
     * @see org.eclipse.ui.IPersistable#saveState(IMemento)
     */
    @Override
    public void saveState(IMemento arg0) {
        // no-op for now.  prevents error on closing of eclipse while a VimEditor
        // instance is open.
    }

    /**
     * @return the file.
     */
    public IFile getSelectedFile() {
        return selectedFile;
    }

    /**
     * @return the gvim server id.
     */
    public int getServerID() {
        return serverID;
    }

    /**
     * @return the bufferID
     */
    public int getBufferID() {
        return bufferID;
    }

    /**
     * Determines if this editor is running an embedded gvim instance or not.
     *
     * @return True if the gvim instance is embedded, false otherwise.
     */
    public boolean isEmbedded() {
        return embedded;
    }

    /**
     * simple one-liner to display error-messages using {@link MessageDialog}.
     * @param message the string to display
     */
    private void message(String message, Throwable e) {

        //convert stacktrace to string
        String stacktrace;
        StringWriter sw = null;
        PrintWriter pw = null;
        try {
            sw = new StringWriter();
            pw = new PrintWriter(sw);
            e.printStackTrace(pw);
            stacktrace = sw.toString();
        } finally {
            try {
                if (pw != null)
                    pw.close();
                if (sw != null)
                    sw.close();
            } catch (IOException ignore) {
            }
        }

        MessageDialog.openError(shell, "Vimplugin", message + stacktrace);
    }
}