--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>\r
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>\r
+ <classpathentry kind="src" path="src"/>\r
+ <classpathentry kind="output" path="bin"/>\r
+</classpath>\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+ <name>jp.sourceforge.moreemacs.test</name>\r
+ <comment></comment>\r
+ <projects>\r
+ </projects>\r
+ <buildSpec>\r
+ <buildCommand>\r
+ <name>org.eclipse.jdt.core.javabuilder</name>\r
+ <arguments>\r
+ </arguments>\r
+ </buildCommand>\r
+ <buildCommand>\r
+ <name>org.eclipse.pde.ManifestBuilder</name>\r
+ <arguments>\r
+ </arguments>\r
+ </buildCommand>\r
+ <buildCommand>\r
+ <name>org.eclipse.pde.SchemaBuilder</name>\r
+ <arguments>\r
+ </arguments>\r
+ </buildCommand>\r
+ </buildSpec>\r
+ <natures>\r
+ <nature>org.eclipse.pde.PluginNature</nature>\r
+ <nature>org.eclipse.jdt.core.javanature</nature>\r
+ </natures>\r
+</projectDescription>\r
--- /dev/null
+#Thu Jun 04 00:56:56 JST 2009\r
+eclipse.preferences.version=1\r
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6\r
+org.eclipse.jdt.core.compiler.compliance=1.6\r
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error\r
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error\r
+org.eclipse.jdt.core.compiler.source=1.6\r
--- /dev/null
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Test fragment
+Bundle-SymbolicName: jp.sourceforge.moreemacs.test
+Bundle-Version: 1.0.0
+Bundle-Vendor: quiver2k
+Fragment-Host: jp.sourceforge.moreemacs
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Require-Bundle: org.junit4;bundle-version="4.3.1"
--- /dev/null
+source.. = src/\r
+output.. = bin/\r
+bin.includes = META-INF/,\\r
+ .\r
--- /dev/null
+package jp.sourceforge.moreemacs.utils;\r
+\r
+import java.util.Locale;\r
+import static org.junit.Assert.*;\r
+import org.junit.Test;\r
+\r
+public class CharacterUtilsTest {\r
+ @Test\r
+ public void testGetWidth() {\r
+ String str = "α■";\r
+ for(int codePoint : CodePointIterator.each(str)) {\r
+ assertEquals(2, CharacterUtils.getWidth(codePoint, Locale.JAPANESE));\r
+ }\r
+ }\r
+}\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>\r
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>\r
+ <classpathentry kind="src" path="src"/>\r
+ <classpathentry kind="output" path="bin"/>\r
+</classpath>\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+ <name>jp.sourceforge.moreemacs</name>\r
+ <comment></comment>\r
+ <projects>\r
+ </projects>\r
+ <buildSpec>\r
+ <buildCommand>\r
+ <name>org.eclipse.jdt.core.javabuilder</name>\r
+ <arguments>\r
+ </arguments>\r
+ </buildCommand>\r
+ <buildCommand>\r
+ <name>org.eclipse.pde.ManifestBuilder</name>\r
+ <arguments>\r
+ </arguments>\r
+ </buildCommand>\r
+ <buildCommand>\r
+ <name>org.eclipse.pde.SchemaBuilder</name>\r
+ <arguments>\r
+ </arguments>\r
+ </buildCommand>\r
+ </buildSpec>\r
+ <natures>\r
+ <nature>org.eclipse.pde.PluginNature</nature>\r
+ <nature>org.eclipse.jdt.core.javanature</nature>\r
+ </natures>\r
+</projectDescription>\r
--- /dev/null
+#Thu Jun 04 00:52:23 JST 2009\r
+eclipse.preferences.version=1\r
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6\r
+org.eclipse.jdt.core.compiler.compliance=1.6\r
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error\r
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error\r
+org.eclipse.jdt.core.compiler.source=1.6\r
--- /dev/null
+Copyright (c) 2009, quiver2k\r
+All rights reserved.\r
+\r
+Redistribution and use in source and binary forms, with or without\r
+modification, are permitted provided that the following conditions are met:\r
+\r
+ * Redistributions of source code must retain the above copyright notice,\r
+ this list of conditions and the following disclaimer.\r
+ * Redistributions in binary form must reproduce the above copyright notice,\r
+ this list of conditions and the following disclaimer in the documentation\r
+ and/or other materials provided with the distribution.\r
+ * Neither the name of the authors nor the names of its contributors may be\r
+ used to endorse or promote products derived from this software without\r
+ specific prior written permission.\r
+\r
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\r
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+POSSIBILITY OF SUCH DAMAGE.\r
--- /dev/null
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: MoreEmacs plugin
+Bundle-SymbolicName: jp.sourceforge.moreemacs;singleton:=true
+Bundle-Version: 1.0.0
+Bundle-Activator: jp.sourceforge.moreemacs.MoreEmacs
+Bundle-Vendor: quiver2k
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.eclipse.ui.editors;bundle-version="3.4.0",
+ com.ibm.icu;bundle-version="3.8.1",
+ org.eclipse.jface.text;bundle-version="3.4.2"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Bundle-ActivationPolicy: lazy
--- /dev/null
+source.. = src/\r
+output.. = bin/\r
+bin.includes = META-INF/,\\r
+ .,\\r
+ plugin.xml\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<?eclipse version="3.4"?>\r
+<plugin>\r
+ <extension\r
+ point="org.eclipse.ui.commands">\r
+ <category\r
+ id="jp.sourceforge.moreemacs.category"\r
+ name="More Emacs">\r
+ </category>\r
+ <command\r
+ categoryId="jp.sourceforge.moreemacs.category"\r
+ id="jp.sourceforge.moreemacs.MoveBeginningOfLine"\r
+ name="move-beginning-of-line">\r
+ </command>\r
+ <command\r
+ categoryId="jp.sourceforge.moreemacs.category"\r
+ id="jp.sourceforge.moreemacs.MoveEndOfLine"\r
+ name="move-end-of-line">\r
+ </command>\r
+ <command\r
+ categoryId="jp.sourceforge.moreemacs.category"\r
+ id="jp.sourceforge.moreemacs.ForwardWord"\r
+ name="forword-word">\r
+ </command>\r
+ <command\r
+ categoryId="jp.sourceforge.moreemacs.category"\r
+ id="jp.sourceforge.moreemacs.BackwardWord"\r
+ name="backword-word">\r
+ </command>\r
+ <command\r
+ categoryId="jp.sourceforge.moreemacs.category"\r
+ id="jp.sourceforge.moreemacs.KillWord"\r
+ name="kill-word">\r
+ </command>\r
+ <command\r
+ categoryId="jp.sourceforge.moreemacs.category"\r
+ id="jp.sourceforge.moreemacs.BackwardKillWord"\r
+ name="backward-kill-word">\r
+ </command>\r
+ <command\r
+ categoryId="jp.sourceforge.moreemacs.category"\r
+ id="jp.sourceforge.moreemacs.DeleteHorizontalSpace"\r
+ name="delete-horizontal-space">\r
+ </command>\r
+ <command\r
+ categoryId="jp.sourceforge.moreemacs.category"\r
+ id="jp.sourceforge.moreemacs.KillLine"\r
+ name="kill-line">\r
+ </command>\r
+ <command\r
+ categoryId="jp.sourceforge.moreemacs.category"\r
+ id="jp.sourceforge.moreemacs.TransposeChars"\r
+ name="transpose-chars">\r
+ </command>\r
+ <command\r
+ categoryId="jp.sourceforge.moreemacs.category"\r
+ id="jp.sourceforge.moreemacs.TransposeWords"\r
+ name="transpose-words">\r
+ </command>\r
+ <command\r
+ categoryId="jp.sourceforge.moreemacs.category"\r
+ id="jp.sourceforge.moreemacs.KillRectangle"\r
+ name="kill-rectangle">\r
+ </command>\r
+ <command\r
+ categoryId="jp.sourceforge.moreemacs.category"\r
+ id="jp.sourceforge.moreemacs.YankRectangle"\r
+ name="yank-rectangle">\r
+ </command>\r
+ <command\r
+ categoryId="jp.sourceforge.moreemacs.category"\r
+ id="jp.sourceforge.moreemacs.OpenLine"\r
+ name="open-line">\r
+ </command>\r
+ </extension>\r
+\r
+ <extension\r
+ point="org.eclipse.ui.handlers">\r
+ <handler\r
+ commandId="jp.sourceforge.moreemacs.MoveBeginningOfLine">\r
+ <class\r
+ class="jp.sourceforge.moreemacs.handlers.CommandHandler">\r
+ </class>\r
+ </handler>\r
+ <handler\r
+ commandId="jp.sourceforge.moreemacs.MoveEndOfLine">\r
+ <class\r
+ class="jp.sourceforge.moreemacs.handlers.CommandHandler">\r
+ </class>\r
+ </handler>\r
+ <handler\r
+ commandId="jp.sourceforge.moreemacs.ForwardWord">\r
+ <class\r
+ class="jp.sourceforge.moreemacs.handlers.CommandHandler">\r
+ </class>\r
+ </handler>\r
+ <handler\r
+ commandId="jp.sourceforge.moreemacs.BackwardWord">\r
+ <class\r
+ class="jp.sourceforge.moreemacs.handlers.CommandHandler">\r
+ </class>\r
+ </handler>\r
+ <handler\r
+ commandId="jp.sourceforge.moreemacs.KillWord">\r
+ <class\r
+ class="jp.sourceforge.moreemacs.handlers.CommandHandler">\r
+ </class>\r
+ </handler>\r
+ <handler\r
+ commandId="jp.sourceforge.moreemacs.BackwardKillWord">\r
+ <class\r
+ class="jp.sourceforge.moreemacs.handlers.CommandHandler">\r
+ </class>\r
+ </handler>\r
+ <handler\r
+ commandId="jp.sourceforge.moreemacs.DeleteHorizontalSpace">\r
+ <class\r
+ class="jp.sourceforge.moreemacs.handlers.CommandHandler">\r
+ </class>\r
+ </handler>\r
+ <handler\r
+ commandId="jp.sourceforge.moreemacs.KillLine">\r
+ <class\r
+ class="jp.sourceforge.moreemacs.handlers.CommandHandler">\r
+ </class>\r
+ </handler>\r
+ <handler\r
+ commandId="jp.sourceforge.moreemacs.TransposeChars">\r
+ <class\r
+ class="jp.sourceforge.moreemacs.handlers.CommandHandler">\r
+ </class>\r
+ </handler>\r
+ <handler\r
+ commandId="jp.sourceforge.moreemacs.TransposeWords">\r
+ <class\r
+ class="jp.sourceforge.moreemacs.handlers.CommandHandler">\r
+ </class>\r
+ </handler>\r
+ <handler\r
+ commandId="jp.sourceforge.moreemacs.KillRectangle">\r
+ <class\r
+ class="jp.sourceforge.moreemacs.handlers.CommandHandler">\r
+ </class>\r
+ </handler>\r
+ <handler\r
+ commandId="jp.sourceforge.moreemacs.YankRectangle">\r
+ <class\r
+ class="jp.sourceforge.moreemacs.handlers.CommandHandler">\r
+ </class>\r
+ </handler>\r
+ <handler\r
+ commandId="jp.sourceforge.moreemacs.OpenLine">\r
+ <class\r
+ class="jp.sourceforge.moreemacs.handlers.CommandHandler">\r
+ </class>\r
+ </handler>\r
+\r
+ </extension>\r
+\r
+ <extension\r
+ point="org.eclipse.ui.bindings">\r
+ <scheme\r
+ description="provides more emacs like key binding."\r
+ id="jp.sourceforge.moreemacs.moreEmacsAcceleratorConfiguration"\r
+ name="More Emacs"\r
+ parentId="org.eclipse.ui.emacsAcceleratorConfiguration">\r
+ </scheme>\r
+ <key\r
+ commandId="org.eclipse.ui.edit.undo"\r
+ contextId="org.eclipse.ui.contexts.window"\r
+ schemeId="jp.sourceforge.moreemacs.moreEmacsAcceleratorConfiguration"\r
+ sequence="CTRL+/">\r
+ </key>\r
+ <key\r
+ commandId="org.eclipse.ui.edit.text.deletePrevious"\r
+ contextId="org.eclipse.ui.contexts.window"\r
+ schemeId="jp.sourceforge.moreemacs.moreEmacsAcceleratorConfiguration"\r
+ sequence="CTRL+H">\r
+ </key>\r
+ <key\r
+ commandId="org.eclipse.ui.window.nextEditor"\r
+ contextId="org.eclipse.ui.contexts.window"\r
+ schemeId="jp.sourceforge.moreemacs.moreEmacsAcceleratorConfiguration"\r
+ sequence="CTRL+TAB">\r
+ </key>\r
+ <key\r
+ commandId="org.eclipse.ui.window.nextEditor"\r
+ contextId="org.eclipse.ui.contexts.window"\r
+ schemeId="jp.sourceforge.moreemacs.moreEmacsAcceleratorConfiguration"\r
+ sequence="CTRL+X O">\r
+ </key>\r
+ <key\r
+ commandId="org.eclipse.ui.window.previousEditor"\r
+ contextId="org.eclipse.ui.contexts.window"\r
+ schemeId="jp.sourceforge.moreemacs.moreEmacsAcceleratorConfiguration"\r
+ sequence="CTRL+SHIFT+TAB">\r
+ </key>\r
+ <key\r
+ commandId="org.eclipse.ui.file.close"\r
+ contextId="org.eclipse.ui.contexts.window"\r
+ schemeId="jp.sourceforge.moreemacs.moreEmacsAcceleratorConfiguration"\r
+ sequence="CTRL+X 0">\r
+ </key>\r
+ <key\r
+ commandId="org.eclipse.ui.window.maximizePart"\r
+ contextId="org.eclipse.ui.contexts.window"\r
+ schemeId="jp.sourceforge.moreemacs.moreEmacsAcceleratorConfiguration"\r
+ sequence="CTRL+X 1">\r
+ </key>\r
+ <key\r
+ commandId="org.eclipse.ui.window.newEditor"\r
+ contextId="org.eclipse.ui.contexts.window"\r
+ schemeId="jp.sourceforge.moreemacs.moreEmacsAcceleratorConfiguration"\r
+ sequence="CTRL+X 2">\r
+ </key>\r
+ <key\r
+ commandId="org.eclipse.ui.edit.findReplace"\r
+ contextId="org.eclipse.ui.contexts.window"\r
+ schemeId="jp.sourceforge.moreemacs.moreEmacsAcceleratorConfiguration"\r
+ sequence="ALT+SHIFT+5">\r
+ </key>\r
+ <key\r
+ contextId="org.eclipse.ui.contexts.window"\r
+ schemeId="jp.sourceforge.moreemacs.moreEmacsAcceleratorConfiguration"\r
+ sequence="Ctrl+M">\r
+ </key>\r
+ <key\r
+ commandId="jp.sourceforge.moreemacs.MoveBeginningOfLine"\r
+ contextId="org.eclipse.ui.textEditorScope"\r
+ schemeId="jp.sourceforge.moreemacs.moreEmacsAcceleratorConfiguration"\r
+ sequence="Ctrl+A">\r
+ </key>\r
+ <key\r
+ commandId="jp.sourceforge.moreemacs.MoveEndOfLine"\r
+ contextId="org.eclipse.ui.textEditorScope"\r
+ schemeId="jp.sourceforge.moreemacs.moreEmacsAcceleratorConfiguration"\r
+ sequence="Ctrl+E">\r
+ </key>\r
+ <key\r
+ commandId="jp.sourceforge.moreemacs.ForwardWord"\r
+ contextId="org.eclipse.ui.textEditorScope"\r
+ schemeId="jp.sourceforge.moreemacs.moreEmacsAcceleratorConfiguration"\r
+ sequence="Alt+F">\r
+ </key>\r
+ <key\r
+ commandId="jp.sourceforge.moreemacs.BackwardWord"\r
+ contextId="org.eclipse.ui.textEditorScope"\r
+ schemeId="jp.sourceforge.moreemacs.moreEmacsAcceleratorConfiguration"\r
+ sequence="Alt+B">\r
+ </key>\r
+ <key\r
+ commandId="jp.sourceforge.moreemacs.KillWord"\r
+ contextId="org.eclipse.ui.textEditorScope"\r
+ schemeId="jp.sourceforge.moreemacs.moreEmacsAcceleratorConfiguration"\r
+ sequence="Alt+D">\r
+ </key>\r
+ <key\r
+ commandId="jp.sourceforge.moreemacs.BackwardKillWord"\r
+ contextId="org.eclipse.ui.textEditorScope"\r
+ schemeId="jp.sourceforge.moreemacs.moreEmacsAcceleratorConfiguration"\r
+ sequence="Alt+Backspace">\r
+ </key>\r
+ <key\r
+ commandId="jp.sourceforge.moreemacs.DeleteHorizontalSpace"\r
+ contextId="org.eclipse.ui.textEditorScope"\r
+ schemeId="jp.sourceforge.moreemacs.moreEmacsAcceleratorConfiguration"\r
+ sequence="Alt+\">\r
+ </key>\r
+ <key\r
+ commandId="jp.sourceforge.moreemacs.KillLine"\r
+ contextId="org.eclipse.ui.textEditorScope"\r
+ schemeId="jp.sourceforge.moreemacs.moreEmacsAcceleratorConfiguration"\r
+ sequence="CTRL+K">\r
+ </key>\r
+ <key\r
+ commandId="jp.sourceforge.moreemacs.OpenLine"\r
+ contextId="org.eclipse.ui.textEditorScope"\r
+ schemeId="jp.sourceforge.moreemacs.moreEmacsAcceleratorConfiguration"\r
+ sequence="CTRL+O">\r
+ </key>\r
+ <key\r
+ commandId="jp.sourceforge.moreemacs.TransposeChars"\r
+ contextId="org.eclipse.ui.textEditorScope"\r
+ schemeId="jp.sourceforge.moreemacs.moreEmacsAcceleratorConfiguration"\r
+ sequence="CTRL+T">\r
+ </key>\r
+ <key\r
+ commandId="jp.sourceforge.moreemacs.TransposeWords"\r
+ contextId="org.eclipse.ui.textEditorScope"\r
+ schemeId="jp.sourceforge.moreemacs.moreEmacsAcceleratorConfiguration"\r
+ sequence="ALT+T">\r
+ </key>\r
+ <key\r
+ commandId="jp.sourceforge.moreemacs.KillRectangle"\r
+ contextId="org.eclipse.ui.textEditorScope"\r
+ schemeId="jp.sourceforge.moreemacs.moreEmacsAcceleratorConfiguration"\r
+ sequence="CTRL+X R K">\r
+ </key>\r
+ <key\r
+ commandId="jp.sourceforge.moreemacs.YankRectangle"\r
+ contextId="org.eclipse.ui.textEditorScope"\r
+ schemeId="jp.sourceforge.moreemacs.moreEmacsAcceleratorConfiguration"\r
+ sequence="CTRL+X R Y">\r
+ </key>\r
+ </extension>\r
+\r
+</plugin>\r
--- /dev/null
+package jp.sourceforge.moreemacs;\r
+\r
+import org.eclipse.ui.plugin.AbstractUIPlugin;\r
+import org.osgi.framework.BundleContext;\r
+\r
+/**\r
+ * The activator class controls the plug-in life cycle\r
+ */\r
+public class MoreEmacs extends AbstractUIPlugin {\r
+\r
+ // The plug-in ID\r
+ public static final String PLUGIN_ID = "jp.sourceforge.moreemacs";\r
+\r
+ // The shared instance\r
+ private static MoreEmacs plugin;\r
+ \r
+ /**\r
+ * The constructor\r
+ */\r
+ public MoreEmacs() {\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)\r
+ */\r
+ public void start(BundleContext context) throws Exception {\r
+ super.start(context);\r
+ plugin = this;\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)\r
+ */\r
+ public void stop(BundleContext context) throws Exception {\r
+ plugin = null;\r
+ super.stop(context);\r
+ }\r
+\r
+ /**\r
+ * Returns the shared instance\r
+ *\r
+ * @return the shared instance\r
+ */\r
+ public static MoreEmacs getDefault() {\r
+ return plugin;\r
+ }\r
+\r
+}\r
--- /dev/null
+package jp.sourceforge.moreemacs.handlers;\r
+\r
+import org.eclipse.jface.text.BadLocationException;\r
+import org.eclipse.swt.dnd.Clipboard;\r
+import org.eclipse.swt.dnd.TextTransfer;\r
+import org.eclipse.swt.dnd.Transfer;\r
+\r
+public final class BackwardKillWordExecution extends TextEditorExecution {\r
+\r
+ @Override\r
+ public void execute()throws BadLocationException {\r
+ if(!textEditor.isEditable()) {\r
+ return;\r
+ }\r
+\r
+ int current = cursor.offset();\r
+ int previous = BackwardWordExecution.getPreviousWordPosition(doc, current);\r
+ String word = doc.get(previous, current - previous);\r
+ Clipboard c = new Clipboard(window.getShell().getDisplay());\r
+ c.setContents(new String[] { word },\r
+ new Transfer[] { TextTransfer.getInstance() });\r
+ doc.replace(previous, current - previous, "");\r
+\r
+ }\r
+}\r
--- /dev/null
+package jp.sourceforge.moreemacs.handlers;\r
+\r
+import jp.sourceforge.moreemacs.utils.CodePointIterator;\r
+import jp.sourceforge.moreemacs.utils.DocumentCharSequence;\r
+\r
+import org.eclipse.jface.text.BadLocationException;\r
+import org.eclipse.jface.text.IDocument;\r
+\r
+public final class BackwardWordExecution extends TextEditorExecution {\r
+\r
+ @Override\r
+ public void execute() throws BadLocationException {\r
+ int current = cursor.offset();\r
+ cursor.move(getPreviousWordPosition(doc, current));\r
+ }\r
+ \r
+ public static int getPreviousWordPosition(IDocument doc, int offset) throws BadLocationException {\r
+ CharSequence seq = new DocumentCharSequence(doc, 0, offset);\r
+ CodePointIterator itr = new CodePointIterator(seq, seq.length());\r
+\r
+ for(; itr.hasPrevious(); ) {\r
+ if (Character.isLetterOrDigit(itr.previous())) {\r
+ itr.next();\r
+ break;\r
+ }\r
+ }\r
+ for(; itr.hasPrevious(); ) {\r
+ if (!Character.isLetterOrDigit(itr.previous())) {\r
+ itr.next();\r
+ break;\r
+ }\r
+ }\r
+ \r
+ return itr.index();\r
+ }\r
+\r
+}\r
--- /dev/null
+package jp.sourceforge.moreemacs.handlers;\r
+\r
+import java.util.regex.Pattern;\r
+\r
+import org.eclipse.core.commands.AbstractHandler;\r
+import org.eclipse.core.commands.Command;\r
+import org.eclipse.core.commands.ExecutionEvent;\r
+import org.eclipse.core.commands.ExecutionException;\r
+import org.eclipse.ui.IWorkbenchWindow;\r
+import org.eclipse.ui.handlers.HandlerUtil;\r
+\r
+public final class CommandHandler extends AbstractHandler {\r
+\r
+ @Override\r
+ public Object execute(ExecutionEvent event) throws ExecutionException {\r
+ IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event);\r
+\r
+ Execution exe = newExecution(event);\r
+ if(!exe.init(window)) {\r
+ return null;\r
+ }\r
+ try {\r
+ exe.execute();\r
+ } catch (Exception e) {\r
+ throw new ExecutionException(e.getMessage(), e);\r
+ }\r
+\r
+ return null;\r
+ }\r
+ \r
+ private Execution newExecution(ExecutionEvent event) throws ExecutionException {\r
+ try {\r
+ String className = getExecutionClassName(event);\r
+ Class<?> clazz = Class.forName(className);\r
+ Object obj = clazz.newInstance();\r
+ if(!(obj instanceof Execution)) {\r
+ throw new ExecutionException("the class "+clazz.getName()+\r
+ " does not implements Execution.");\r
+ }\r
+ return (Execution)obj;\r
+ } catch (ClassNotFoundException e) {\r
+ throw new ExecutionException(e.getMessage(), e);\r
+ } catch (InstantiationException e) {\r
+ throw new ExecutionException(e.getMessage(), e);\r
+ } catch (IllegalAccessException e) {\r
+ throw new ExecutionException(e.getMessage(), e);\r
+ }\r
+ \r
+ }\r
+ \r
+ // naming strategy will be separated to another class.\r
+ private static final String COMMAND_PREFIX_QUOTED = Pattern.quote("jp.sourceforge.moreemacs.");\r
+ private static final String HANDLER_PREFIX = "jp.sourceforge.moreemacs.handlers."; \r
+ private static final String HANDLER_SUFFIX = "Execution";\r
+ private static String getExecutionClassName(ExecutionEvent event) {\r
+ Command command = event.getCommand();\r
+ String className = command.getId()\r
+ .replaceFirst(COMMAND_PREFIX_QUOTED, HANDLER_PREFIX)\r
+ +HANDLER_SUFFIX;\r
+ return className;\r
+ }\r
+\r
+}\r
--- /dev/null
+package jp.sourceforge.moreemacs.handlers;\r
+\r
+import org.eclipse.jface.text.ITextSelection;\r
+import org.eclipse.jface.text.ITextViewer;\r
+import org.eclipse.jface.text.ITextViewerExtension5;\r
+import org.eclipse.swt.custom.StyledText;\r
+import org.eclipse.ui.texteditor.ITextEditor;\r
+\r
+final class Cursor {\r
+ private final ITextEditor textEditor;\r
+ private final ITextViewerExtension5 textViewerEx5;\r
+ private final StyledText styledText;\r
+ \r
+ Cursor(ITextEditor textEditor, ITextViewer textViewer) {\r
+ this.textEditor = textEditor;\r
+ this.styledText = textViewer.getTextWidget();\r
+ this.textViewerEx5 = (textViewer instanceof ITextViewerExtension5)\r
+ ? (ITextViewerExtension5) textViewer: null;\r
+ }\r
+ \r
+ int offset() {\r
+ if(textViewerEx5 != null) {\r
+ return textViewerEx5.widgetOffset2ModelOffset(\r
+ styledText.getCaretOffset());\r
+ }\r
+\r
+ ITextSelection selectoin =\r
+ (ITextSelection) textEditor.getSelectionProvider().getSelection();\r
+ int selectionBegin = selectoin.getOffset();\r
+ return selectionBegin;\r
+ }\r
+ \r
+ void move(int offset) {\r
+// if(textViewerEx5 != null) {\r
+// styledText.setCaretOffset(textViewerEx5.modelOffset2WidgetOffset(offset));\r
+// return;\r
+// }\r
+\r
+ textEditor.resetHighlightRange();\r
+ textEditor.setHighlightRange(offset, 0, true);\r
+ }\r
+}\r
--- /dev/null
+package jp.sourceforge.moreemacs.handlers;\r
+\r
+import jp.sourceforge.moreemacs.utils.CodePointIterator;\r
+import jp.sourceforge.moreemacs.utils.DocumentCharSequence;\r
+\r
+import org.eclipse.jface.text.BadLocationException;\r
+import org.eclipse.jface.text.IDocument;\r
+import org.eclipse.jface.text.IRegion;\r
+\r
+public final class DeleteHorizontalSpaceExecution extends TextEditorExecution {\r
+\r
+ @Override\r
+ public void execute() throws BadLocationException {\r
+ if(!textEditor.isEditable()) {\r
+ return;\r
+ }\r
+\r
+ int current = cursor.offset();\r
+ int start = skipBackwardSpaces(doc, current);\r
+ int end = skipForwardSpaces(doc, current);\r
+ doc.replace(start, end - start, "");\r
+ }\r
+ \r
+ int skipBackwardSpaces(IDocument doc, int offset) throws BadLocationException {\r
+ IRegion line = doc.getLineInformationOfOffset(offset);\r
+\r
+ CharSequence seq = new DocumentCharSequence(doc, \r
+ line.getOffset(), offset-line.getOffset());\r
+\r
+ int result = offset;\r
+ for(CodePointIterator itr = new CodePointIterator(seq, seq.length()); itr.hasPrevious(); ) {\r
+ int codePoint = itr.previous();\r
+ if (!Character.isWhitespace(codePoint)) {\r
+ break;\r
+ }\r
+ result = line.getOffset() + itr.index();\r
+ }\r
+ return result;\r
+ }\r
+ \r
+ int skipForwardSpaces(IDocument doc, int offset) throws BadLocationException {\r
+ IRegion line = doc.getLineInformationOfOffset(offset);\r
+ CharSequence seq = new DocumentCharSequence(doc, \r
+ offset,line.getOffset()+line.getLength()-offset);\r
+ int result = offset;\r
+ for(CodePointIterator itr = new CodePointIterator(seq); itr.hasNext(); ) {\r
+ int codePoint = itr.next();\r
+ if (!Character.isWhitespace(codePoint)) {\r
+ break;\r
+ }\r
+ result = offset + itr.index();\r
+ }\r
+ return result;\r
+ }\r
+}\r
--- /dev/null
+package jp.sourceforge.moreemacs.handlers;\r
+\r
+import org.eclipse.ui.IWorkbenchWindow;\r
+\r
+public interface Execution {\r
+ boolean init(IWorkbenchWindow window);\r
+ void execute() throws Exception;\r
+}\r
--- /dev/null
+package jp.sourceforge.moreemacs.handlers;\r
+\r
+import jp.sourceforge.moreemacs.utils.CodePointIterator;\r
+import jp.sourceforge.moreemacs.utils.DocumentCharSequence;\r
+\r
+import org.eclipse.jface.text.BadLocationException;\r
+import org.eclipse.jface.text.IDocument;\r
+\r
+public final class ForwardWordExecution extends TextEditorExecution {\r
+\r
+ @Override\r
+ public void execute() throws BadLocationException {\r
+ int current = cursor.offset();\r
+ cursor.move(getNextWordPosition(doc, current));\r
+ }\r
+\r
+ public static int getNextWordPosition(IDocument doc, int offset) throws BadLocationException {\r
+ CharSequence seq = new DocumentCharSequence(doc, offset, doc.getLength()-offset);\r
+ CodePointIterator itr = new CodePointIterator(seq);\r
+\r
+\r
+ for(; itr.hasNext(); ) {\r
+ int codePoint = itr.next();\r
+ if (Character.isLetterOrDigit(codePoint)) {\r
+ itr.previous();\r
+ break;\r
+ }\r
+ }\r
+ for(; itr.hasNext(); ) {\r
+ if (!Character.isLetterOrDigit(itr.next())) {\r
+ itr.previous();\r
+ break;\r
+ }\r
+ }\r
+ \r
+ return offset + itr.index();\r
+ }\r
+ \r
+}\r
--- /dev/null
+package jp.sourceforge.moreemacs.handlers;\r
+\r
+import jp.sourceforge.moreemacs.utils.CodePointIterator;\r
+import jp.sourceforge.moreemacs.utils.DocumentCharSequence;\r
+\r
+import org.eclipse.jface.text.BadLocationException;\r
+import org.eclipse.jface.text.IDocument;\r
+import org.eclipse.jface.text.IRegion;\r
+import org.eclipse.swt.dnd.Clipboard;\r
+import org.eclipse.swt.dnd.TextTransfer;\r
+import org.eclipse.swt.dnd.Transfer;\r
+\r
+public final class KillLineExecution extends TextEditorExecution {\r
+\r
+ @Override\r
+ public void execute() throws BadLocationException {\r
+ if(!textEditor.isEditable()) {\r
+ return;\r
+ }\r
+\r
+ int current = cursor.offset();\r
+ int linePos = doc.getLineOfOffset(current);\r
+ IRegion line = doc.getLineInformation(linePos);\r
+ String delim = doc.getLineDelimiter(linePos);\r
+\r
+ int length = line.getOffset() + line.getLength() - current;\r
+ boolean allSpaces = isAllSpaces(doc, current, length);\r
+\r
+ int cutLength = length;\r
+ if (allSpaces && delim != null) {\r
+ cutLength += delim.length();\r
+ }\r
+\r
+ String cut = doc.get(current, cutLength);\r
+ Clipboard c = new Clipboard(window.getShell().getDisplay());\r
+ c.setContents(\r
+ new String[] { cut }, \r
+ new Transfer[] { TextTransfer.getInstance() });\r
+ doc.replace(current, cutLength, "");\r
+ }\r
+ \r
+ private boolean isAllSpaces(IDocument doc, int offset, int length) throws BadLocationException {\r
+ CharSequence seq = new DocumentCharSequence(doc, offset, length);\r
+ for(int codePoint : CodePointIterator.each(seq)) {\r
+ if (!Character.isWhitespace(codePoint)) {\r
+ return false;\r
+ }\r
+ }\r
+ return true;\r
+ }\r
+}\r
--- /dev/null
+package jp.sourceforge.moreemacs.handlers;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import jp.sourceforge.moreemacs.utils.CodePointIterator;\r
+import jp.sourceforge.moreemacs.utils.ColumnUtils;\r
+import jp.sourceforge.moreemacs.utils.DocumentCharSequence;\r
+import jp.sourceforge.moreemacs.utils.DocumentTransaction;\r
+\r
+import org.eclipse.jface.text.BadLocationException;\r
+import org.eclipse.jface.text.DocumentRewriteSessionType;\r
+import org.eclipse.jface.text.IDocument;\r
+import org.eclipse.jface.text.IRegion;\r
+import org.eclipse.jface.text.ITextSelection;\r
+\r
+public final class KillRectangleExecution extends RectangleExecution {\r
+\r
+ @Override\r
+ public void execute() throws BadLocationException {\r
+\r
+ if(!textEditor.isEditable()) {\r
+ return;\r
+ }\r
+ \r
+ ITextSelection selection = getSelection(true);\r
+\r
+ int start = selection.getOffset();\r
+ int startRow = doc.getLineOfOffset(start);\r
+ int startColumn = ColumnUtils.getColumn(doc, start, getTabStop());\r
+\r
+ int end = start + selection.getLength();\r
+ int endRow = doc.getLineOfOffset(end);\r
+ int endColumn = ColumnUtils.getColumn(doc, end, getTabStop());\r
+ \r
+ if(startColumn > endColumn) {\r
+ int work = startColumn;\r
+ startColumn = endColumn;\r
+ endColumn = work;\r
+ }\r
+\r
+ DocumentTransaction transaction = new DocumentTransaction(doc); \r
+ transaction.begin(DocumentRewriteSessionType.UNRESTRICTED_SMALL);\r
+ try {\r
+ List<String> rectangle = killRectangle(doc, startRow, startColumn, endRow, endColumn);\r
+ setRectangle(rectangle);\r
+ } finally {\r
+ transaction.end();\r
+ }\r
+ }\r
+ private List<String> killRectangle(IDocument doc,\r
+ int startRow, int startColumn,\r
+ int endRow, int endColumn)\r
+ throws BadLocationException {\r
+\r
+ List<String> rectangle = new ArrayList<String>();\r
+\r
+ for(int i = startRow; i <= endRow; i++) {\r
+ String str = killString(doc, i, startColumn, endColumn);\r
+ rectangle.add(str);\r
+ }\r
+ return rectangle;\r
+ }\r
+ private String killString(IDocument doc, int row,\r
+ int startColumn, int endColumn) throws BadLocationException {\r
+ IRegion line = doc.getLineInformation(row);\r
+\r
+ StringBuilder builder = new StringBuilder();\r
+ int column = 0;\r
+ int cutOffset = 0;\r
+ int cutLength = 0;\r
+ \r
+ CharSequence seq = new DocumentCharSequence(doc, line.getOffset(), line.getLength());\r
+ \r
+ for(CodePointIterator itr = new CodePointIterator(seq); itr.hasNext(); ) {\r
+ if(column >= endColumn) {\r
+ break;\r
+ }\r
+ int offset = line.getOffset() + itr.index();\r
+ int codePoint = itr.next();\r
+\r
+ int nextColumn = ColumnUtils.getNextColumn(column, codePoint, getTabStop());\r
+ \r
+ if(nextColumn < startColumn+1) {\r
+ column = nextColumn;\r
+ continue;\r
+ }\r
+ if(cutLength == 0) { \r
+ cutOffset = offset;\r
+ }\r
+ builder.appendCodePoint(codePoint);\r
+ cutLength += Character.charCount(codePoint);\r
+ column = nextColumn;\r
+ }\r
+ \r
+ doc.replace(cutOffset, cutLength, "");\r
+ cursor.move(cutOffset);\r
+\r
+ \r
+ for(int i = 0; i < endColumn-column; i++) {\r
+ builder.append(' ');\r
+ }\r
+ \r
+ return builder.toString();\r
+ }\r
+\r
+}\r
--- /dev/null
+package jp.sourceforge.moreemacs.handlers;\r
+\r
+import org.eclipse.jface.text.BadLocationException;\r
+import org.eclipse.swt.dnd.Clipboard;\r
+import org.eclipse.swt.dnd.TextTransfer;\r
+import org.eclipse.swt.dnd.Transfer;\r
+\r
+public final class KillWordExecution extends TextEditorExecution {\r
+\r
+ @Override\r
+ public void execute() throws BadLocationException {\r
+ if(!textEditor.isEditable()) {\r
+ return;\r
+ }\r
+\r
+ int current = cursor.offset();\r
+ int next = ForwardWordExecution.getNextWordPosition(doc, current);\r
+ String word = doc.get(current, next-current);\r
+ Clipboard c = new Clipboard(window.getShell().getDisplay());\r
+ c.setContents(\r
+ new String[] { word }, \r
+ new Transfer[] { TextTransfer.getInstance() });\r
+ doc.replace(current, next-current, "");\r
+ }\r
+}\r
--- /dev/null
+package jp.sourceforge.moreemacs.handlers;\r
+\r
+import org.eclipse.jface.text.BadLocationException;\r
+import org.eclipse.jface.text.IRegion;\r
+\r
+public final class MoveBeginningOfLineExecution extends TextEditorExecution {\r
+ @Override\r
+ public void execute() throws BadLocationException {\r
+ IRegion line = doc.getLineInformationOfOffset(cursor.offset());\r
+ cursor.move(line.getOffset());\r
+ }\r
+}\r
+\r
--- /dev/null
+package jp.sourceforge.moreemacs.handlers;\r
+\r
+import org.eclipse.jface.text.BadLocationException;\r
+import org.eclipse.jface.text.IRegion;\r
+\r
+public final class MoveEndOfLineExecution extends TextEditorExecution {\r
+\r
+ @Override\r
+ public void execute() throws BadLocationException {\r
+ IRegion line = doc.getLineInformationOfOffset(cursor.offset());\r
+ cursor.move(line.getOffset()+line.getLength());\r
+ }\r
+\r
+}\r
--- /dev/null
+package jp.sourceforge.moreemacs.handlers;\r
+\r
+import org.eclipse.jface.text.TextUtilities;\r
+\r
+public final class OpenLineExecution extends TextEditorExecution {\r
+\r
+ @Override\r
+ public void execute() throws Exception {\r
+ if(!textEditor.isEditable()) {\r
+ return;\r
+ }\r
+ String delim = TextUtilities.getDefaultLineDelimiter(doc);\r
+ doc.replace(cursor.offset(), 0, delim);\r
+ }\r
+\r
+}\r
--- /dev/null
+package jp.sourceforge.moreemacs.handlers;\r
+\r
+import java.util.List;\r
+\r
+abstract class RectangleExecution extends TextEditorExecution {\r
+ private static List<String> rectangle ;\r
+ \r
+ protected static void setRectangle(List<String> rect) {\r
+ rectangle = rect;\r
+ }\r
+ \r
+ protected static List<String> getRectangle() {\r
+ return rectangle;\r
+ }\r
+}\r
--- /dev/null
+package jp.sourceforge.moreemacs.handlers;\r
+\r
+import org.eclipse.jface.text.IDocument;\r
+import org.eclipse.jface.text.ITextOperationTarget;\r
+import org.eclipse.jface.text.ITextSelection;\r
+import org.eclipse.jface.text.ITextViewer;\r
+import org.eclipse.jface.text.ITextViewerExtension;\r
+import org.eclipse.ui.IEditorPart;\r
+import org.eclipse.ui.IWorkbenchWindow;\r
+import org.eclipse.ui.texteditor.ITextEditor;\r
+\r
+abstract class TextEditorExecution implements Execution {\r
+ protected IWorkbenchWindow window;\r
+ protected ITextEditor textEditor;\r
+ protected ITextViewer textViewer;\r
+ protected Cursor cursor;\r
+ protected IDocument doc;\r
+ \r
+ @Override\r
+ public boolean init(IWorkbenchWindow window) {\r
+ this.window = window;\r
+\r
+ IEditorPart editor = window.getActivePage().getActiveEditor();\r
+ if (editor instanceof ITextEditor) {\r
+ textEditor = (ITextEditor) editor;\r
+ } else {\r
+ textEditor = (ITextEditor) editor.getAdapter(ITextEditor.class);\r
+ }\r
+ if(textEditor == null) {\r
+ return false;\r
+ }\r
+ \r
+ doc = textEditor.getDocumentProvider().getDocument(\r
+ textEditor.getEditorInput());\r
+\r
+ ITextOperationTarget target =\r
+ (ITextOperationTarget)editor.getAdapter(ITextOperationTarget.class);\r
+ if(!(target instanceof ITextViewer)) {\r
+ return false;\r
+ }\r
+ textViewer = (ITextViewer) target;\r
+ \r
+ cursor = new Cursor(textEditor, textViewer);\r
+ \r
+ return true;\r
+ }\r
+ \r
+ protected ITextSelection getSelection(boolean fallbackToMark) {\r
+ ITextSelection selection =\r
+ (ITextSelection) textEditor.getSelectionProvider().getSelection();\r
+ \r
+ if(!fallbackToMark && selection.getLength() != 0) {\r
+ return selection;\r
+ }\r
+ \r
+ IEditorPart editor = window.getActivePage().getActiveEditor();\r
+ ITextOperationTarget target =\r
+ (ITextOperationTarget)editor.getAdapter(ITextOperationTarget.class);\r
+ \r
+ if(!(target instanceof ITextViewerExtension)) {\r
+ return selection;\r
+ }\r
+ \r
+ ITextViewerExtension viewerEx = (ITextViewerExtension) target;\r
+ \r
+ int mark = viewerEx.getMark();\r
+ \r
+ if(mark == -1) {\r
+ return selection;\r
+ }\r
+ \r
+ int current = selection.getOffset();\r
+ \r
+ int start = (mark < current) ? mark : current;\r
+ textEditor.selectAndReveal(start, Math.abs(mark - current));\r
+ \r
+ return (ITextSelection) textEditor\r
+ .getSelectionProvider().getSelection();\r
+ }\r
+\r
+ protected final int getTabStop() {\r
+ return textViewer.getTextWidget().getTabs();\r
+ }\r
+}\r
--- /dev/null
+package jp.sourceforge.moreemacs.handlers;\r
+\r
+import jp.sourceforge.moreemacs.utils.DocumentCharSequence;\r
+\r
+import org.eclipse.jface.text.BadLocationException;\r
+import org.eclipse.jface.text.IRegion;\r
+\r
+public final class TransposeCharsExecution extends TextEditorExecution {\r
+ @Override\r
+ public void execute() throws BadLocationException {\r
+ if(!textEditor.isEditable()) {\r
+ return;\r
+ }\r
+\r
+ int current = cursor.offset();\r
+ if(current == 0) {\r
+ // beginning of document\r
+ return;\r
+ }\r
+\r
+ int linePos = doc.getLineOfOffset(current);\r
+ IRegion line = doc.getLineInformation(linePos);\r
+ \r
+ DocumentCharSequence seq = new DocumentCharSequence(doc);\r
+\r
+ if(line.getOffset() + line.getLength() == current) {\r
+ // if end of line, adjust current position\r
+ current = (line.getOffset() == current)\r
+ ? current - doc.getLineDelimiter(linePos-1).length() \r
+ : seq.previousCodePointIndex(current);\r
+ linePos = doc.getLineOfOffset(current);\r
+ line = doc.getLineInformation(linePos);\r
+ }\r
+ if(current == 0) {\r
+ // beginning of document again\r
+ return;\r
+ }\r
+\r
+ int nextIndex = seq.nextCodePointIndex(current);\r
+ String forwardChars = (line.getOffset() + line.getLength() == current) \r
+ ? doc.getLineDelimiter(linePos) : doc.get(current, nextIndex - current);\r
+ \r
+ int prevIndex = seq.previousCodePointIndex(current);\r
+ String backwardChars = (line.getOffset() == current) \r
+ ? doc.getLineDelimiter(linePos-1) : doc.get(prevIndex, current-prevIndex);\r
+\r
+ doc.replace(current-backwardChars.length(), \r
+ backwardChars.length() + forwardChars.length(),\r
+ forwardChars+backwardChars);\r
+ }\r
+ \r
+}\r
--- /dev/null
+package jp.sourceforge.moreemacs.handlers;\r
+\r
+import org.eclipse.jface.text.BadLocationException;\r
+\r
+public final class TransposeWordsExecution extends TextEditorExecution {\r
+ @Override\r
+ public void execute() throws BadLocationException {\r
+ if(!textEditor.isEditable()) {\r
+ return;\r
+ }\r
+\r
+ int current = cursor.offset();\r
+ int previousBegin = BackwardWordExecution.getPreviousWordPosition(doc, current);\r
+ int previousEnd = ForwardWordExecution.getNextWordPosition(doc, previousBegin);\r
+ int nextEnd = ForwardWordExecution.getNextWordPosition(doc, current);\r
+ int nextBegin = BackwardWordExecution.getPreviousWordPosition(doc, nextEnd);\r
+ \r
+ if(nextBegin <= previousEnd) {\r
+ return;\r
+ }\r
+ \r
+ String previous = doc.get(previousBegin, previousEnd-previousBegin);\r
+ String simbols = doc.get(previousEnd, nextBegin-previousEnd);\r
+ String next = doc.get(nextBegin, nextEnd-nextBegin);\r
+\r
+ doc.replace(previousBegin,\r
+ nextEnd-previousBegin,\r
+ next+simbols+previous);\r
+ \r
+ }\r
+}\r
--- /dev/null
+package jp.sourceforge.moreemacs.handlers;\r
+\r
+import java.util.List;\r
+\r
+import jp.sourceforge.moreemacs.utils.CodePointIterator;\r
+import jp.sourceforge.moreemacs.utils.ColumnUtils;\r
+import jp.sourceforge.moreemacs.utils.DocumentCharSequence;\r
+import jp.sourceforge.moreemacs.utils.DocumentTransaction;\r
+\r
+import org.eclipse.jface.text.BadLocationException;\r
+import org.eclipse.jface.text.DocumentRewriteSessionType;\r
+import org.eclipse.jface.text.IDocument;\r
+import org.eclipse.jface.text.IRegion;\r
+import org.eclipse.jface.text.TextUtilities;\r
+\r
+public final class YankRectangleExecution extends RectangleExecution {\r
+ @Override\r
+ public void execute() throws BadLocationException {\r
+ if(!textEditor.isEditable()) {\r
+ return;\r
+ }\r
+ \r
+ List<String> rectangle = getRectangle();\r
+ if(rectangle == null) {\r
+ return;\r
+ }\r
+ \r
+ int current = cursor.offset();\r
+ int row = doc.getLineOfOffset(current);\r
+ int column = ColumnUtils.getColumn(doc, current, getTabStop());\r
+ \r
+ ensureLines(doc, row + rectangle.size());\r
+ \r
+ DocumentTransaction transaction = new DocumentTransaction(doc); \r
+ transaction.begin(DocumentRewriteSessionType.UNRESTRICTED_SMALL);\r
+ try {\r
+ yankRectangle(doc, row, column, rectangle);\r
+ } finally {\r
+ transaction.end();\r
+ }\r
+ }\r
+ \r
+ private void ensureLines(IDocument doc, int lines) throws BadLocationException {\r
+ int n = lines - doc.getNumberOfLines();\r
+ if(n <= 0) {\r
+ return;\r
+ }\r
+\r
+ StringBuilder builder = new StringBuilder();\r
+ String delim = TextUtilities.getDefaultLineDelimiter(doc);\r
+ for(int i = 0; i < n; i++) {\r
+ builder.append(delim);\r
+ }\r
+ doc.replace(doc.getLength(), 0, builder.toString());\r
+ \r
+ }\r
+\r
+ private void yankRectangle(IDocument doc,\r
+ int row, int column, List<String> rectangle)\r
+ throws BadLocationException {\r
+ for(int i = 0; i < rectangle.size(); i++) {\r
+ yankString(doc, row+i, column, rectangle.get(i));\r
+ }\r
+ }\r
+\r
+ private void yankString(IDocument doc, int row, int column, String str)\r
+ throws BadLocationException\r
+ {\r
+ IRegion line = doc.getLineInformation(row);\r
+ int col = 0;\r
+\r
+ CharSequence seq = new DocumentCharSequence(doc, line.getOffset(), line.getLength());\r
+ \r
+ for(CodePointIterator itr = new CodePointIterator(seq); itr.hasNext(); ) {\r
+ int offset = line.getOffset() + itr.index();\r
+ int codePoint = itr.next();\r
+ if(col >= column) {\r
+ doc.replace(offset, 0, str);\r
+ cursor.move(offset+str.length());\r
+ return;\r
+ }\r
+ col = ColumnUtils.getNextColumn(col, codePoint, getTabStop());\r
+ }\r
+ \r
+\r
+ StringBuilder builder = new StringBuilder();\r
+ for(int i = 0; i < column-col; i++) {\r
+ builder.append(" ");\r
+ }\r
+ builder.append(str);\r
+ doc.replace(line.getOffset()+line.getLength(), 0, builder.toString());\r
+ cursor.move(line.getOffset()+line.getLength()+builder.length());\r
+ }\r
+\r
+}\r
+\r
+\r
--- /dev/null
+package jp.sourceforge.moreemacs.utils;\r
+\r
+import java.util.Arrays;\r
+import java.util.List;\r
+import java.util.Locale;\r
+\r
+import com.ibm.icu.lang.UCharacter;\r
+import com.ibm.icu.lang.UProperty;\r
+\r
+public final class CharacterUtils {\r
+ private CharacterUtils() {}\r
+\r
+ private static List<String> EAST_ASIAN_LANGS =\r
+ Arrays.asList("ja", "vi", "kr", "zh");\r
+\r
+ public static int getWidth(int codePoint) {\r
+ return getWidth(codePoint, Locale.getDefault());\r
+ }\r
+\r
+ public static int getWidth(int codePoint, Locale locale) {\r
+ if(locale == null) {\r
+ throw new NullPointerException("locale is null");\r
+ }\r
+ int value = UCharacter.getIntPropertyValue(codePoint, \r
+ UProperty.EAST_ASIAN_WIDTH);\r
+ switch(value) {\r
+ case UCharacter.EastAsianWidth.NARROW:\r
+ case UCharacter.EastAsianWidth.NEUTRAL:\r
+ case UCharacter.EastAsianWidth.HALFWIDTH:\r
+ return 1;\r
+ case UCharacter.EastAsianWidth.FULLWIDTH:\r
+ case UCharacter.EastAsianWidth.WIDE:\r
+ return 2;\r
+ case UCharacter.EastAsianWidth.AMBIGUOUS:\r
+ if(EAST_ASIAN_LANGS.contains(locale.getLanguage())) {\r
+ return 2;\r
+ } else {\r
+ return 1;\r
+ }\r
+ default:\r
+ return 1;\r
+ }\r
+ }\r
+}\r
--- /dev/null
+package jp.sourceforge.moreemacs.utils;\r
+\r
+import java.util.Iterator;\r
+\r
+public final class CodePointIterator implements Iterator<Integer> {\r
+ private final CharSequence seq;\r
+ private int index;\r
+\r
+ public CodePointIterator(CharSequence seq) {\r
+ this(seq, 0);\r
+ }\r
+ \r
+ public CodePointIterator(CharSequence seq, int index) {\r
+ if(seq == null) {\r
+ throw new NullPointerException("seq is null");\r
+ }\r
+\r
+ this.seq = seq;\r
+ setIndex(index);\r
+ }\r
+ \r
+ public void setIndex(int index) {\r
+ if(index < 0 || index > seq.length()) {\r
+ throw new IndexOutOfBoundsException();\r
+ }\r
+ this.index = index;\r
+ }\r
+ \r
+ @Override\r
+ public boolean hasNext() { \r
+ return index < seq.length(); \r
+ }\r
+ \r
+ public boolean hasPrevious() { \r
+ return index > 0;\r
+ }\r
+ \r
+ public int index() {\r
+ return index;\r
+ }\r
+ \r
+ @Override\r
+ public Integer next() { \r
+ int codePoint = Character.codePointAt(seq, index); \r
+ index += Character.charCount(codePoint); \r
+ return codePoint; \r
+ }\r
+\r
+ public Integer previous() { \r
+ int codePoint = Character.codePointBefore(seq, index); \r
+ index -= Character.charCount(codePoint); \r
+ return codePoint; \r
+ }\r
+ \r
+ @Override\r
+ public void remove() {\r
+ throw new UnsupportedOperationException("unsupported");\r
+ }\r
+\r
+ public static Iterable<Integer> each(final CharSequence seq) {\r
+ return new Iterable<Integer>() {\r
+ @Override\r
+ public Iterator<Integer> iterator() {\r
+ return new CodePointIterator(seq);\r
+ }\r
+ \r
+ };\r
+ }\r
+}\r
--- /dev/null
+package jp.sourceforge.moreemacs.utils;\r
+\r
+import org.eclipse.jface.text.BadLocationException;\r
+import org.eclipse.jface.text.IDocument;\r
+import org.eclipse.jface.text.IRegion;\r
+\r
+public final class ColumnUtils {\r
+ private ColumnUtils() {}\r
+ \r
+ public static int getColumn(IDocument doc, int offset, int tabStop)\r
+ throws BadLocationException {\r
+ IRegion line = doc.getLineInformationOfOffset(offset);\r
+ int column = 0;\r
+ \r
+ CharSequence seq = new DocumentCharSequence(doc, line.getOffset(), offset - line.getOffset());\r
+ for(CodePointIterator itr = new CodePointIterator(seq); itr.hasNext(); ) {\r
+ int codePoint = itr.next();\r
+ column = getNextColumn(column, codePoint, tabStop);\r
+ }\r
+ \r
+ return column;\r
+ }\r
+ \r
+ public static int getNextColumn(int column, int codePoint, int tabStop) {\r
+ if(codePoint == '\t') {\r
+ return column - (column%tabStop) + tabStop;\r
+ } else {\r
+ return column + CharacterUtils.getWidth(codePoint);\r
+ }\r
+ }\r
+}\r
--- /dev/null
+package jp.sourceforge.moreemacs.utils;\r
+\r
+import org.eclipse.jface.text.BadLocationException;\r
+import org.eclipse.jface.text.IDocument;\r
+\r
+public final class DocumentCharSequence implements CharSequence {\r
+ private final IDocument doc;\r
+ private final int offset;\r
+ private final int length;\r
+\r
+ public DocumentCharSequence(IDocument doc) {\r
+ this(doc, 0, doc.getLength());\r
+ }\r
+ \r
+ public DocumentCharSequence(IDocument doc, int offset, int length) {\r
+ if(doc == null) {\r
+ throw new NullPointerException("doc is null");\r
+ }\r
+\r
+ this.doc = doc;\r
+ this.offset = offset;\r
+ this.length = length;\r
+\r
+ validate(offset, length, doc.getLength());\r
+ }\r
+ \r
+ private static void validate(int offset, int length, int capacity) {\r
+ if(offset < 0 || length < 0 || offset+length > capacity) {\r
+ throw new IndexOutOfBoundsException();\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public char charAt(int index) {\r
+ if(index < 0 || index >= length) {\r
+ throw new IndexOutOfBoundsException();\r
+ }\r
+ try {\r
+ return doc.getChar(offset + index);\r
+ } catch (BadLocationException e) {\r
+ throw new IndexOutOfBoundsException(e.getMessage());\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public int length() {\r
+ return length;\r
+ }\r
+\r
+ @Override\r
+ public CharSequence subSequence(int start, int end) {\r
+ validate(start, end-start, length);\r
+ return new DocumentCharSequence(doc, offset+start, end - start);\r
+ }\r
+\r
+ public int nextCodePointIndex(int index) {\r
+ int codePoint = Character.codePointAt(this, index); \r
+ return index + Character.charCount(codePoint); \r
+ }\r
+ public int previousCodePointIndex(int index) {\r
+ int codePoint = Character.codePointBefore(this, index); \r
+ return index - Character.charCount(codePoint); \r
+ }\r
+}\r
--- /dev/null
+package jp.sourceforge.moreemacs.utils;\r
+\r
+import org.eclipse.jface.text.DocumentRewriteSession;\r
+import org.eclipse.jface.text.DocumentRewriteSessionType;\r
+import org.eclipse.jface.text.IDocument;\r
+import org.eclipse.jface.text.IDocumentExtension4;\r
+\r
+public final class DocumentTransaction {\r
+ private IDocumentExtension4 sessionManager;\r
+ private DocumentRewriteSession session;\r
+ \r
+ public DocumentTransaction(IDocument doc) {\r
+ if(doc instanceof IDocumentExtension4) {\r
+ sessionManager = (IDocumentExtension4)doc;\r
+ }\r
+ }\r
+ \r
+ public boolean isAvailable() {\r
+ return sessionManager != null;\r
+ }\r
+ \r
+ public void begin(DocumentRewriteSessionType type) {\r
+ if(!isAvailable()) {\r
+ return;\r
+ }\r
+ if(session != null) {\r
+ throw new IllegalStateException("session already started");\r
+ }\r
+ session = sessionManager.startRewriteSession(type);\r
+ }\r
+ \r
+ public void end() {\r
+ if(!isAvailable()) {\r
+ return;\r
+ }\r
+ if(session == null) {\r
+ throw new IllegalStateException("session is not started");\r
+ }\r
+ sessionManager.stopRewriteSession(session);\r
+ session = null;\r
+ }\r
+\r
+}\r