/** * 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 static com.mulgasoft.emacsplus.EmacsPlusUtils.getPreferenceBoolean; import static com.mulgasoft.emacsplus.EmacsPlusUtils.getPreferenceStore; import static com.mulgasoft.emacsplus.preferences.PrefVars.KILL_WHOLE_LINE; import static org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds.CUT_LINE; import static org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds.CUT_LINE_TO_END; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.swt.custom.StyledText; import org.eclipse.ui.console.IConsoleView; import org.eclipse.ui.console.TextConsoleViewer; import org.eclipse.ui.texteditor.ITextEditor; import com.mulgasoft.emacsplus.IEmacsPlusCommandDefinitionIds; import com.mulgasoft.emacsplus.KillRing; /** * Version of CUT_LINE_TO_END for use with universal-argument to replicate Emacs semantics of * kill-line * * @author Mark Feber - initial API and implementation */ public class KillLineHandler extends ConsoleCmdHandler { private static boolean WHOLE_LINE = getPreferenceBoolean(KILL_WHOLE_LINE.getPref()); static { // listen for changes in the property store getPreferenceStore().addPropertyChangeListener( new IPropertyChangeListener() { public void propertyChange(PropertyChangeEvent event) { if (KILL_WHOLE_LINE.getPref().equals(event.getProperty())) { setKillWholeLine((Boolean)event.getNewValue()); } } } ); } public static void setKillWholeLine(boolean val) { WHOLE_LINE = val; } public static boolean isKillWholeLine() { return WHOLE_LINE; } /** * @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 { int uArg = getUniversalCount(); int offset = getCursorOffset(editor, currentSelection); int offsetLine = document.getLineOfOffset(offset); if (uArg == 1) { try { // gnu emacs: If the variable `kill-whole-line' is non-`nil', `C-k' at the very // beginning of a line kills the entire line including the following newline. boolean killWhole = isKillWholeLine() && (offset == document.getLineOffset(offsetLine)); executeCommand(killWhole ? CUT_LINE : CUT_LINE_TO_END, null, editor); } catch (Exception e) {} } else { try { // flag us as a kill command KillRing.getInstance().setKill(IEmacsPlusCommandDefinitionIds.KILL_LINE, false); int lastOffset = offset; // note that line numbers start from 0 int maxLine = document.getNumberOfLines() - 1; int endLine = uArg + document.getLineOfOffset(offset); // if range includes eof if (endLine >= maxLine) { // delete through to last character lastOffset = document.getLineOffset(maxLine) + document.getLineLength(maxLine); } else { // delete by whole lines lastOffset = document.getLineOffset(Math.min(Math.max(endLine, 0), maxLine)); } updateText(document, ((lastOffset >= offset ? offset : lastOffset)), Math.abs(lastOffset - offset), EMPTY_STR); } finally { // clear kill command flag KillRing.getInstance().setKill(null, false); } } return NO_OFFSET; } /** * When called from a console context, will use ST.CUT * * @see com.mulgasoft.emacsplus.commands.ConsoleCmdHandler#consoleDispatch(TextConsoleViewer, * IConsoleView, ExecutionEvent) */ public Object consoleDispatch(TextConsoleViewer viewer, IConsoleView activePart, ExecutionEvent event) { if (viewer.isEditable()) { IDocument doc = viewer.getDocument(); StyledText st = viewer.getTextWidget(); int offset = st.getCaretOffset(); try { IRegion info = doc.getLineInformationOfOffset(offset); int noffset = info.getOffset() + info.getLength(); if (offset == noffset) { int line = doc.getLineOfOffset(offset); if (++line < doc.getNumberOfLines()) { noffset = doc.getLineOffset(line); if (noffset == doc.getLength()) { noffset = offset; } } } if (offset != noffset) { st.redraw(); st.setSelection(offset, noffset); KillRing.getInstance().setKill(CUT_LINE_TO_END, false); return super.consoleDispatch(viewer, activePart, event); } viewer.refresh(); } catch (BadLocationException e) { } } return null; } /** * @see com.mulgasoft.emacsplus.commands.EmacsPlusCmdHandler#isLooping() */ protected boolean isLooping() { return false; } /** * CID for CUT to simulate CUT_TO_LINE_END in console * * @see com.mulgasoft.emacsplus.commands.ConsoleCmdHandler#getId(org.eclipse.core.commands.ExecutionEvent, * org.eclipse.ui.console.TextConsoleViewer) */ protected String getId(ExecutionEvent event, TextConsoleViewer viewer) { return IEmacsPlusCommandDefinitionIds.EMP_CUT; } }