Начиная работать в IntelliJ IDEA, обнаружил отсутствие удобной комбинации клавиш, которой пользуюсь в Eclipse — Ctrl+Alt+Up. По этой комбинации выделенный блок текста или строка, копируется вверх с перемещением курсора в начало скопированного блока.
В Idea есть действие по умолчанию на Ctrl+D, которое копирует блок вниз (Ctrl+Alt+Down в Eclipse), но невозможно добавить аналогичное действие вверх. После гугления, был задан вопрос в Q&A, оставшийся без ответа. Заведён issue на jetbrains. Все эти действия не дали ответа, поэтому решено было написать небольшой плагин для Idea.
Начало
Для начала стоит скачать исходники community версии IDE, т.к. времени это займёт достаточно много, общий размер около 1,6 Гб.
Репозиторий git:
git://git.jetbrains.org/idea/community.git
Действие это необязательное, но очень желательное, т.к. здесь мы найдём java доки интересующих нас классов и методов, а также исходники готовых плагинов (практически весь код ниже я подглядел в них).
Создание проекта
В целом, для разработки плагина не требуется ничего, кроме IntelliJ IDEA. Я использовал коммерческую версию, поэтому все действия далее проводятся на ней. Значительных отличий от community редакции быть не должно.
Создаём проект плагина: File -> New Project…
Выбираем пункт IntelliJ Platform Plugin
Если отсутствует Project SDK, нажимаем New… и указываем папку, куда установлена Idea.
Жмём Finish.
Добавление java доков
Необязательный шаг.
После закачки исходников IDE, жмём File -> Project Structure… и на закладке Sourcepath указываем путь к исходникам:
Теперь разработка и дебаг плагина станет проще.
Например, было:
стало:
Структура плагина
Про структуру плагина в Idea можно почитать здесь.
Любой плагин для Idea, это .jar файл, содержащий конфигурационный файл plugin.xml в папке META-INF и код, отвечающий за работу плагина.
Необходимо заполнить некоторые данные в plugin.xml. На этом этапе, ничего сложного в заполнении нет.
<idea-plugin version="2">
<id>org.idea.plugin.duplicatelines</id>
<name>Duplicate lines</name>
<version>1.0</version>
<vendor email="test@yourcompany.com">mobileDeveloper</vendor>
<description><![CDATA[
Plugin for intellij idea to allow copy lines<br>
and block of code like Eclipse IDE (Ctrl+Alt+Up and Ctrl+Alt+Down).
]]></description>
<idea-version since-build="107.105"/>
<actions></actions>
<extensions defaultExtensionNs="com.intellij">
<!-- Add your extensions here -->
</extensions>
</idea-plugin>
Actions
В Idea работает так называемая Action System. Она позволяет плагинам добавлять свои действия в меню, на тулбар и т.д. Actions организованы в группы, которые в свою очередь могут содержать другие группы. Каждый Action имеет уникальный идентификатор. Большинство стандартных идентификаторов определено в файле IdeActions.java
Action является обычным java классом, который наследуется от абстактного класса AnAction
. Мы будем наследоваться от более конкретного EditorAction
.
Action можно создать через граф. интерфейс: пр. кн. мыши на package -> New -> Action:
Выбрав необходимую группу, по необходимости можно задать комбинацию клавиш на новый Action, будет создан класс наследник AnAction
, а в plugin.xml, в секцию <actions/> будет добавлено описание Action класса.
Дадим имя нашему Action классу — CopyLineUpAction.
Теперь внутри тега <actions></actions>
файла plugin.xml будет следующий код:
<actions>
<action id="CopyLineUpAction" class="org.idea.plugin.duplicatelines.CopyLineUpAction"
text="Copy line(s) up."
description="Copy line(s) up.">
<add-to-group group-id="EditorActions" anchor="last"/>
<keyboard-shortcut first-keystroke="control alt UP" keymap="$default"/>
</action>
</actions>
Обратите внимание, мы определили комбинацию клавиш Ctrl+Alt+Up по умолчанию. Я использовал стандартную комбинацию Eclipse, т.к. привык к ней. В настройках Idea эту комбинацию можно будет переопределить.
Код
Если вы использовали gui для создания Action, то в указанном пакете уже присутствует класс CopyLineUpAction
, в противном случае нужно создать его вручную.
Логика работы нашего Action очень простая: по нажатию комбинации клавиш, определить копируемый кусок текста, вставить этот текст выше текущей строки и переместить курсор в начало скопированного блока.
Собственно сам код CopyLineUpAction, его немного и, по-моему, он достаточно ясен. Добавлю лишь, что Action класс должен содержать конструктор без параметров (конструктор по умолчанию):
package org.idea.plugin.duplicatelines;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.actionSystem.EditorAction;
import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
import com.intellij.openapi.editor.actionSystem.EditorWriteActionHandler;
public class CopyLineUpAction extends EditorAction {
public CopyLineUpAction(EditorActionHandler defaultHandler) {
super(defaultHandler);
}
public CopyLineUpAction() {
this(new UpHandler());
}
private static class UpHandler extends EditorWriteActionHandler {
private UpHandler() {
}
@Override
public void executeWriteAction(Editor editor, DataContext dataContext) {
Document document = editor.getDocument();
if (editor == null || document == null || !document.isWritable()) {
return;
}
// CaretModel used to find caret position
CaretModel caretModel = editor.getCaretModel();
// SelectionModel used to find selection ranges
SelectionModel selectionModel = editor.getSelectionModel();
// get the range of the selected characters
Range charsRange = new Range(selectionModel.getSelectionStart(), selectionModel.getSelectionEnd());
// get the range of the selected lines (block of code)
Range linesRange = new Range(document.getLineNumber(charsRange.getStart()), document.getLineNumber(charsRange.getEnd()));
// range of the duplicated string
Range linesBlock = new Range(document.getLineStartOffset(linesRange.getStart()), document.getLineEndOffset(linesRange.getEnd()));
// get the string to duplicate
String duplicatedString = document.getText().substring(linesBlock.getStart(), linesBlock.getEnd());
duplicatedString += "n";
// insert new duplicated string into the document
document.insertString(linesBlock.getStart(), duplicatedString);
// select duplicated block
editor.getSelectionModel().setSelection(linesBlock.getStart(), linesBlock.getEnd());
// move cursor to the start of copied block
caretModel.moveToOffset(linesBlock.getStart());
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
}
}
}
Для работы Action, нам потребуется вспомогательный класс Range. Он позволит хранить интервал (отрезок) копируемых линий кода.
package org.idea.plugin.duplicatelines;
final class Range {
private final int start;
private final int end;
Range(final int begin, final int end) {
this.start = begin;
this.end = end;
}
public int getStart() {
return start;
}
public int getEnd() {
return end;
}
}
Отладка
Дебажить вновь создаваемый плагин можно точно также, как и любое java приложение в Idea, с единственным отличием, в окне Run/Debug Configurations -> Add New Configuration, нужно будет указать Plugin. После выбора Run/Debug будет запущена новая копия Idea с уже установленным плагином.
Сборка и установка плагина
Чтобы собрать плагин, выбираем в меню Build -> Prepare Plugin Module 'plugin name' For Deployment. Будет создан .jar файл в директории проекта.
Установка прагина производится через File ->Settings… -> IDE Settings -> Plugins -> Install plugin from disk…
В настройках Keymap мы увидим такую строчку:
Проверяем, радуемся новому функционалу.
Полезные ссылки
Ссылка на исходникиPlugin Development Documentation
Урок по созданию плагина для Idea
Open API and Plugin Development — здесь можно найти ответ на многие вопросы по плагинам для Idea.
Автор: mobileDeveloper