- PVSM.RU - https://www.pvsm.ru -

Пишем плагин для IntelliJ IDEA, добавляем функциональности редактору кода

Начиная работать в IntelliJ IDEA, обнаружил отсутствие удобной комбинации клавиш, которой пользуюсь в Eclipse — Ctrl+Alt+Up. По этой комбинации выделенный блок текста или строка, копируется вверх с перемещением курсора в начало скопированного блока.
В Idea есть действие по умолчанию на Ctrl+D, которое копирует блок вниз (Ctrl+Alt+Down в Eclipse), но невозможно добавить аналогичное действие вверх. После гугления, был задан вопрос [1] в 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
Пишем плагин для IntelliJ IDEA, добавляем функциональности редактору кода
Если отсутствует Project SDK, нажимаем New… и указываем папку, куда установлена Idea.
Жмём Finish.

Добавление java доков

Необязательный шаг.
После закачки исходников IDE, жмём File -> Project Structure… и на закладке Sourcepath указываем путь к исходникам:
Пишем плагин для IntelliJ IDEA, добавляем функциональности редактору кода
Теперь разработка и дебаг плагина станет проще.
Например, было:
Пишем плагин для IntelliJ IDEA, добавляем функциональности редактору кода
стало:
Пишем плагин для IntelliJ IDEA, добавляем функциональности редактору кода

Структура плагина

Про структуру плагина в Idea можно почитать здесь [2].
Любой плагин для Idea, это .jar файл, содержащий конфигурационный файл plugin.xml в папке META-INF и код, отвечающий за работу плагина.
Пишем плагин для IntelliJ IDEA, добавляем функциональности редактору кода
Необходимо заполнить некоторые данные в plugin.xml. На этом этапе, ничего сложного в заполнении нет.

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 [3]

Action является обычным java классом, который наследуется от абстактного класса AnAction. Мы будем наследоваться от более конкретного EditorAction.
Action можно создать через граф. интерфейс: пр. кн. мыши на package -> New -> Action:
Пишем плагин для IntelliJ IDEA, добавляем функциональности редактору кода
Выбрав необходимую группу, по необходимости можно задать комбинацию клавиш на новый Action, будет создан класс наследник AnAction, а в plugin.xml, в секцию <actions/> будет добавлено описание Action класса.
Дадим имя нашему Action классу — CopyLineUpAction.
Теперь внутри тега <actions></actions> файла plugin.xml будет следующий код:

Описание Action


    <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 класс должен содержать конструктор без параметров (конструктор по умолчанию):

CodeLineUpAction.java

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. Он позволит хранить интервал (отрезок) копируемых линий кода.

Класс 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 с уже установленным плагином.

Скриншот

Пишем плагин для IntelliJ IDEA, добавляем функциональности редактору кода

Сборка и установка плагина

Чтобы собрать плагин, выбираем в меню Build -> Prepare Plugin Module 'plugin name' For Deployment. Будет создан .jar файл в директории проекта.
Установка прагина производится через File ->Settings… -> IDE Settings -> Plugins -> Install plugin from disk…
В настройках Keymap мы увидим такую строчку:
Пишем плагин для IntelliJ IDEA, добавляем функциональности редактору кода
Проверяем, радуемся новому функционалу.

Полезные ссылки

Ссылка на исходники [4]Plugin Development Documentation [5]
Урок по созданию плагина для Idea [6]
Open API and Plugin Development [7] — здесь можно найти ответ на многие вопросы по плагинам для Idea.

Автор: mobileDeveloper

Источник [8]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/java/33345

Ссылки в тексте:

[1] вопрос: http://habrahabr.ru/qa/38735/

[2] здесь: http://confluence.jetbrains.com/display/IDEADEV/IntelliJ+IDEA+Plugin+Structure

[3] IdeActions.java: http://git.jetbrains.org/?p=idea/community.git;a=blob;f=platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java;hb=HEAD

[4] Ссылка на исходники: https://github.com/mobile-developer/idea-duplicate-lines

[5] Plugin Development Documentation: http://confluence.jetbrains.com/display/IDEADEV/PluginDevelopment

[6] Урок по созданию плагина для Idea: http://confluence.jetbrains.com/display/IntelliJIDEA/Custom+Language+Support

[7] Open API and Plugin Development: http://devnet.jetbrains.com/community/idea/open_api_and_plugin_development

[8] Источник: http://habrahabr.ru/post/178217/