Порядок перестановки для редактора Java для Eclipse
Асимметричный способ, которым (, запятая) используется для разделения элементов в списках параметров и аргументов, всегда вызывает проблемы, когда кто-то хочет переупорядочить этот список в редакторе Java. Поэтому Java позволяет использовать запятые в инициализаторе массива? ? может быть. Плагин Reorder поддерживает замену выражений инициализатора параметра, аргумента или массива одним или несколькими щелчками мыши с помощью предыдущего или следующего элемента списка. Каждый элемент последовательности может быть литералом, идентификатором или более сложным выражением. Разделитель запятых правильно обрабатывается.
Этот плагин добавляет две кнопки панели инструментов в редактор Eclipse Java:
- Своп назад
- Своп вперед
использование
С каретой на | в:
void process(int age, String |name, boolean member) {...}
нажатие кнопки «
Переместить вперед» дает:
void process(int age, boolean member, String |name) {...}
или нажав
Поменяйте местами кнопку « Назад»
с исходным источником:
void process(String |name, int age, boolean member) {...}
Реализация действий
Точки расширения
Следующие точки расширения объявляют действия для замены элементов в списке. Обратите внимание, что эти действия появляются на панели инструментов редактора, когда редактор Java активен.
<extension
point="org.eclipse.ui.editorActions">
<editorContribution
id="Reorder.editorContribution"
targetID="org.eclipse.jdt.ui.CompilationUnitEditor">
<action
class="reorder.SwapForwardAction"
definitionId="Reorder.swapForwardCommand" <!-- commands -->
icon="icons/swapforward.png"
id="Reorder.swapForwardAction"
label="Swap Forward"
style="push"
toolbarPath="Normal/additions">
</action>
<action
class="reorder.SwapBackwardAction"
definitionId="Reorder.swapBackwardCommand" <!-- commands -->
icon="icons/swapbackward.png"
id="Reorder.swapBackwardAction"
label="Swap Backward"
style="push"
toolbarPath="Normal/additions">
</action>
</editorContribution>
</extension>
Следующая точка расширения объявляет команды.
<extension
id="Reorder.swapCommands"
name="Swap Commands"
point="org.eclipse.ui.commands">
<command
categoryId="org.eclipse.jdt.ui.category.source"
id="Reorder.swapForwardCommand"
name="Swap Forward">
</command>
<command
categoryId="org.eclipse.jdt.ui.category.source"
id="Reorder.swapBackwardCommand"
name="Swap Backward">
</command>
</extension>
Следующая точка расширения объявляет привязки клавиш для команд.
<extension
point="org.eclipse.ui.bindings">
<!-- win32: M1=CTRL, M2=SHIFT, M3=ALT, M4=-
carbon: M1=COMMAND, M2=SHIFT, M3=ALT, M4=CTRL -->
<key
sequence="M1+," <!-- keybinding -->
contextId="org.eclipse.jdt.ui.javaEditorScope"
commandId="Reorder.swapBackwardCommand"
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"/>
<key
sequence="M1+." <!-- keybinding -->
contextId="org.eclipse.jdt.ui.javaEditorScope"
commandId="Reorder.swapForwardCommand"
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"/>
</extension>
AbstractSwapAction
Это просто абстрактный базовый класс, который вызывает действия подкачки на основе смещения, возвращаемого подклассами.
package reorder;
import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ui.IEditorActionDelegate;
import org.eclipse.ui.IEditorPart;
import reorder.SwapOperations.Bias;
@SuppressWarnings("restriction")
public abstract class AbstractSwapAction implements IEditorActionDelegate {
protected JavaEditor targetEditor;
public void setActiveEditor(IAction action, IEditorPart targetEditor) {
this.targetEditor = null;
if (targetEditor instanceof JavaEditor) {
this.targetEditor = (JavaEditor) targetEditor;
}
}
public void run(IAction action) {
if (targetEditor != null) {
SwapOperations.swap(targetEditor, getBias());
}
}
// Sub classes specify the bias
protected abstract Bias getBias();
public void selectionChanged(IAction action, ISelection selection) {}
}
SwapBackwardAction
Это действие реализует обмен с предыдущим элементом.
package reorder;
import reorder.SwapOperations.Bias;
public class SwapBackwardAction extends AbstractSwapAction {
@Override
protected Bias getBias() {
// Swap with preceding item
return Bias.BACKWARD;
}
}
SwapForwardAction
Это действие реализует обмен со следующим элементом.
package reorder;
import reorder.SwapOperations.Bias;
public class SwapForwardAction extends AbstractSwapAction {
@Override
protected Bias getBias() {
// Swap with following item
return Bias.FORWARD;
}
}
SwapOperations
Этот класс реализует основную логику плагина Reorder. По сути, он использует API-интерфейсы AST для получения проанализированной структуры исходного кода Java, окружающего каретку в редакторе Java.
- Он получает ASTNode в позиции каретки с помощью API-интерфейса NodeFinder и начинает обход родительских ASTNodes до тех пор, пока не найдет создание экземпляра класса, вызов метода, объявление метода или узел инициализатора массива.
- Найдя его, он получает список аргументов, параметров или элементов инициализации массива ASTNode (в зависимости от ситуации) и сохраняет текст каждого узла в упорядоченном списке элементов. При этом он также записывает промежуточные пробелы как элементы.
- Он также записывает, какой экстент элемента окружает позицию каретки. Он записывает это как текущий элемент.
- Затем он заменяет текущий элемент следующим или предшествующим непробельным элементом в списке на основе вызванного действия — прямая или обратная замена.
- Наконец, он строит строку из списка элементов и заменяет исходный текст новой строкой.
package reorder;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ArrayCreation;
import org.eclipse.jdt.core.dom.ArrayInitializer;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.internal.corext.dom.NodeFinder;
import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jdt.ui.SharedASTProvider;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Display;
@SuppressWarnings("restriction")
public class SwapOperations {
enum Bias {
BACKWARD, FORWARD
};
@SuppressWarnings("unchecked")
static void swap(JavaEditor editor, Bias bias) {
// Editor not editable...bail out
if (!editor.isEditable()) {
Display.getCurrent().beep();
return;
}
// Get source viewer
ISourceViewer viewer = editor.getViewer();
if (viewer == null)
return;
// Get the caret position
Point selectedRange = viewer.getSelectedRange();
int caretAt = selectedRange.x;
int length = selectedRange.y;
// Get the Java element
ITypeRoot element = JavaUI.getEditorInputTypeRoot(editor
.getEditorInput());
if (element == null)
return;
// Get the compilation unit AST
CompilationUnit ast = SharedASTProvider.getAST(element,
SharedASTProvider.WAIT_YES, null);
if (ast == null)
return;
// Find the node at caret position
NodeFinder finder = new NodeFinder(caretAt, length);
ast.accept(finder);
ASTNode originalNode = finder.getCoveringNode();
ASTNode node;
List arguments = null;
// traverser the succesively outer node
node = originalNode;
while (node != null) {
node = node.getParent();
// Is it an interesting node? If so remember the interesting list of item
if (node instanceof ClassInstanceCreation) {
arguments = ((ClassInstanceCreation) node).arguments();
} else if (node instanceof MethodInvocation) {
arguments = ((MethodInvocation) node).arguments();
} else if (node instanceof MethodDeclaration) {
arguments = ((MethodDeclaration) node).parameters();
} else if (node instanceof ArrayCreation) {
ArrayCreation arrayCreation = (ArrayCreation) node;
ArrayInitializer initializer = arrayCreation.getInitializer();
if (initializer != null) {
arguments = initializer.expressions();
}
}
// Something to reorder
if (arguments != null && arguments.size() >= 2) {
final int firstStart = ((ASTNode) arguments.get(0))
.getStartPosition();
final int lastEnd = ((ASTNode) arguments.get(arguments.size() - 1))
.getStartPosition()
+ ((ASTNode) arguments.get(arguments.size() - 1))
.getLength();
// Is the caret in the range
if (firstStart <= caretAt && caretAt <= lastEnd) {
int caretOffset = -1;
List<String> tokens = new LinkedList<String>();
int currentTokenIndex = -1;
String currentToken = null;
int previousEnd = -1;
// Add items and intervening white spaces to a list
// Also remember the item that surrounds the caret
for (Object argument : arguments) {
ASTNode expression = (ASTNode) argument;
int startPosition = expression.getStartPosition();
int endPosition = startPosition + expression.getLength();
if (previousEnd != -1) {
try {
// capture separator and intervening whitespaces
tokens.add(viewer.getDocument().get(previousEnd, (startPosition-previousEnd)));
} catch (BadLocationException e) {
Activator.getDefault().getLog().log(new Status(IStatus.ERROR
,Activator.PLUGIN_ID
,"Could not get whitespace token."));
return;
}
}
// capture the token
final String token = argument.toString();
tokens.add(token);
if (startPosition <= caretAt && caretAt <= endPosition) {
// record the token that surrounds the caret and the
// caret offset from the start of that token
currentTokenIndex = tokens.size() - 1;
currentToken = token;
caretOffset = caretAt - (int) startPosition;
}
previousEnd = endPosition;
}
// Now do the reordering
if (tokens.size() > 0 && currentTokenIndex != -1) {
String current = tokens.get(currentTokenIndex);
switch (bias) {
case BACKWARD:
if (currentTokenIndex == 0) {
Display.getCurrent().beep();
return;
}
// Swap with previous non-whitespace token
String previous = tokens.get(currentTokenIndex - 2);
tokens.set(currentTokenIndex - 2, current);
tokens.set(currentTokenIndex, previous);
break;
case FORWARD:
if (currentTokenIndex == (tokens.size() - 1)) {
Display.getCurrent().beep();
return;
}
// Swap with following non-whitespace token
String next = tokens.get(currentTokenIndex + 2);
tokens.set(currentTokenIndex + 2, current);
tokens.set(currentTokenIndex, next);
break;
}
// Build the insertion string
final StringBuilder stringBuilder = new StringBuilder();
int offset = 0;
final int[] moveCaretOffset = new int[1];
for (String token : tokens) {
final String text = token;
if (token == currentToken) {
moveCaretOffset[0] = offset + caretOffset;
}
offset += text.length();
stringBuilder.append(text);
}
// Now replace the old text with new text
try {
viewer.getDocument().replace(firstStart,
(lastEnd - firstStart), stringBuilder.toString());
} catch (BadLocationException e) {
Activator.getDefault().getLog().log(new Status(IStatus.ERROR
,Activator.PLUGIN_ID
,"Could not swap items."));
return;
}
viewer.setSelectedRange((int) firstStart
+ moveCaretOffset[0], 0);
}
}
break;
}
}
}
}
MANIFEST.MF
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Reorder Plug-in
Bundle-SymbolicName: Reorder;singleton:=true
Bundle-Version: 1.0.4
Bundle-Activator: reorder.Activator
Bundle-Vendor: Sandip V. Chitale
Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
org.eclipse.jdt.core;bundle-version="3.4.0",
org.eclipse.jdt.ui;bundle-version="3.4.0",
org.eclipse.ui.editors;bundle-version="3.4.0",
org.eclipse.jface.text;bundle-version="3.4.0"
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Bundle-ActivationPolicy: lazy
Установка
В разделе ресурсов есть ссылка на jar плагина, который можно поместить в каталог плагинов вашей инсталляции Eclipse. После установки вы сможете использовать действия Swap forward и Swap back, когда активен JavaEditor.
Исходный код
Исходный код находится в jar-файле плагина. Фактически вы можете импортировать исходный проект плагина в PDE и взломать его дальше. Исходный код также доступен
здесь .
Вывод
В этом уроке мы создали простой, но полезный плагин Eclipse —
Reorder for Java Editor . Он использует JDOM и AST API. Также демонстрируется, как зарегистрировать действия для редактора Java, как объявить команды и связать их с действиями и объявить привязки клавиш для команд.
Java и все товарные знаки и логотипы на основе Java являются товарными знаками или зарегистрированными товарными знаками Sun Microsystems, Inc. в США или других странах.
Примечания к
ресурсам
по архитектуре
подключаемых модулей Eclipse PDE выполняет подключаемые модули
Вкладывая действия в Eclipse Workbench Переупорядочение
загрузки
для
подключаемого модуля редактора Java для источников Eclipse