com.mulgasoft.emacsplus.commands.YankPopHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.mulgasoft.emacsplus.commands.YankPopHandler.java

Source

/**
 * Copyright (c) 2009, 2010 Mark Feber, MulgaSoft
 *
 * All rights reserved. This program and the accompanying materials
 * are 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 com.mulgasoft.emacsplus.commands;

import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.ui.texteditor.ITextEditor;

import com.mulgasoft.emacsplus.EmacsPlusActivator;
import com.mulgasoft.emacsplus.EmacsPlusUtils;
import com.mulgasoft.emacsplus.IEmacsPlusCommandDefinitionIds;
import com.mulgasoft.emacsplus.KillRing;
import com.mulgasoft.emacsplus.preferences.EmacsPlusPreferenceConstants;

/**
 * Implements: yank-pop
 * 
 * Valid only if called immediately after a `yank' or a `yank-pop'
 * yank-pop deletes previous popped text and replaces it with the 'next' stretch of killed text.
 * 
 * With no argument, then previous kill is inserted
 * With ARG, insert the ARGth 'previous' kill (ARG == 1 is the same as no argument)
 * With negative ARG, insert the ARGth 'next' kill
 * 
 * @author Mark Feber - initial API and implementation
 */
public class YankPopHandler extends BaseYankHandler {

    // if true, then auto browse kill ring on invocation with no previous yank
    private static boolean autoBrowse = (Boolean) getPreference(EmacsPlusPreferenceConstants.P_AUTO_BROWSE_KR);
    private static final String YP_DISABLED = "YankPopHandler_0"; //$NON-NLS-1$ 

    /**
     * Replace the yanked text with the previous yank and return the new offset 
     * 
     * @see com.mulgasoft.emacsplus.commands.EmacsPlusCmdHandler#transform(ITextEditor, IDocument, ITextSelection, ExecutionEvent)
     */
    @Override
    protected int transform(ITextEditor editor, IDocument document, ITextSelection currentSelection,
            ExecutionEvent event) throws BadLocationException {

        if (KillRing.getInstance().isYanked()) {
            return (currentSelection.getOffset() + yankIt(document, currentSelection));
        } else if (autoBrowse) {
            // Browse kill ring if true
            try {
                EmacsPlusUtils.executeCommand(IEmacsPlusCommandDefinitionIds.BROWSE_KILL_RING, null, editor);
            } catch (Exception e) {
                EmacsPlusUtils.showMessage(editor, EmacsPlusActivator.getString(YP_DISABLED), false);
            }
        } else {
            EmacsPlusUtils.showMessage(editor, EmacsPlusActivator.getString(YP_DISABLED), false);
        }
        return currentSelection.getOffset();
    }

    protected int yankIt(IDocument document, ITextSelection selection) throws BadLocationException {
        int len = 0;
        KillRing kb = KillRing.getInstance();
        String prevText = convertDelimiters(kb.lastYank());
        String yankText = convertDelimiters(kb.yankPop());
        if (yankText != null) {
            int origin = selection.getOffset() - prevText.length();
            // in case selection has been mouse moved
            // Since our mouse listener would have to be on the StyledText widget
            if (prevText == null || !prevText.equals(document.get(origin, prevText.length()))) {
                kb.setYanked(false);
                return 0;
            }
            updateText(document, origin, prevText.length(), yankText);
            kb.setYanked(true);
            return yankText.length() - prevText.length();
        }
        return len;
    }

    /**
     *  Simulate yank pop
     *  
     * @see com.mulgasoft.emacsplus.commands.BaseYankHandler#paste(org.eclipse.core.commands.ExecutionEvent, org.eclipse.swt.custom.StyledText)
     */
    protected void paste(ExecutionEvent event, StyledText widget, boolean isProcess) {
        KillRing kb = KillRing.getInstance();
        if (kb.isYanked()) {
            String cacheText = KillRing.getInstance().getClipboardText();
            String prevText = convertDelimiters(kb.lastYank(), isProcess);
            String yankText = convertDelimiters(kb.yankPop(), isProcess);
            try {
                int offset = widget.getCaretOffset();
                if (prevText == null || !prevText.equals(widget.getText(offset - prevText.length(), offset - 1))) {
                    kb.setYanked(false);
                    EmacsPlusUtils.showMessage(HandlerUtil.getActivePart(event),
                            EmacsPlusActivator.getString(YP_DISABLED), false);
                    return;
                }
                widget.setRedraw(false);
                widget.setSelection(offset - prevText.length(), offset);
                kb.setClipboardText(yankText);
                super.paste(event, widget);
            } finally {
                if (cacheText != null) {
                    kb.setClipboardText(cacheText);
                }
                widget.setRedraw(true);
            }
        } else {
            EmacsPlusUtils.showMessage(HandlerUtil.getActivePart(event), EmacsPlusActivator.getString(YP_DISABLED),
                    false);
        }
    }

    /**
     * Enable or disable auto browse of kill ring
     * 
     * @param auto
     */
    public static void setAutoBrowse(boolean auto) {
        YankPopHandler.autoBrowse = auto;
    }

    private static boolean getPreference(String key) {
        boolean result = false;
        IPreferenceStore store = EmacsPlusActivator.getDefault().getPreferenceStore();
        if (store != null) {
            result = store.getBoolean(key);
        }
        return result;
    }
}