IntelliJ IDEAプラグインを書く

IntelliJ IDEAプラグインの作成

1.  前書き

過去数年間で、JetBrainsのIntelliJはすぐにJava開発者にとってトップのIDEになりました。 最新のState of Java reportでは、IntelliJが55%の回答者に選ばれたIDEであり、前年の48%から増加しました。

IntelliJがJava開発者にとって非常に魅力的な機能の1つは、プラグインを使用して新しい機能を拡張および作成する機能です。 このチュートリアルでは、IDEを拡張するいくつかの方法を示すためにIntelliJプラグインを作成する方法を見ていきます。

また、この記事ではIntelliJプラグインに焦点を当てていますが、JetBrains IDEはすべて共通のコードを共有しています。 したがって、PyCharm、RubyMineなどのmany of the techniques used here can be applied to other JetBrain’s IDEs

2. プラグインの機能

IntelliJのプラグイン機能は通常、次の4つのカテゴリのいずれかに分類されます。

  • Custom languages:さまざまな言語で記述されたコードを記述、解釈、およびコンパイルする機能

  • Frameworks:Springなどのサードパーティフレームワークのサポート

  • Tools:Gradleなどの外部ツールとの統合

  • User interface add-ons:新しいメニュー項目、ツールウィンドウとボタンなど

Plugins will often fall into multiple categories。 たとえば、IntelliJに同梱されているGit pluginは、システムにインストールされているgit実行可能ファイルと相互作用します。 プラグインは、ツールウィンドウとポップアップメニュー項目を提供すると同時に、プロジェクト作成ワークフロー、設定ウィンドウなどに統合します。

3. プラグインを作成する

IntelliJプラグインを使い始める最も簡単な方法は、Plugin DevKitを使用することです。 これは、New>Projectメニューからアクセスできます。

image

Note we must use a JetBrains JDKを使用して、必要なプラグインクラスがクラスパスで使用可能であることを確認します。 IntelliJにはデフォルトで適切なJDKが付属しているはずですが、そうでない場合はhereからダウンロードできます。

この記事の執筆時点では、we can only use Java 8 for writing IntelliJ pluginsです。 これは、JetBrainsが現在Java 9以降の公式JDKを提供していないためです。

4. プラグインの例

IntelliJプラグインの作成を示すために、IDEの複数の領域から人気のあるStack OverflowWebサイトにすばやくアクセスできるプラグインを作成します。 追加します:

  • [質問]ページにアクセスする[ツール]メニュー項目

  • テキストエディタとコンソール出力の両方のポップアップメニュー項目で、強調表示されたテキストのスタックオーバーフローを検索します。

4.1. アクションの作成

Actions are the core component used for writing IntelliJ plugins。 アクションは、メニュー項目やツールバーボタンをクリックするなど、IDEのイベントによってトリガーされます。

アクションを作成する最初のステップは、AnActionを拡張するJavaクラスを作成することです。 Stack Overflowプラグインでは、2つのアクションを作成します。

最初のアクションは、新しいブラウザーウィンドウで質問ページを開きます。

public class AskQuestionAction extends AnAction {
   @Override
   public void actionPerformed(AnActionEvent e) {
       BrowserUtil.browse("https://stackoverflow.com/questions/ask");
   }
}

組み込みのBrowserUtilクラスを使用するのは、さまざまなオペレーティングシステムやブラウザーでWebページを開く際の微妙な違いをすべて処理するためです。

2番目のアクションは、Stack Overflow検索ページを開き、検索テキストをクエリ文字列として渡します。 今回は2つのメソッドを実装します。

実装する最初のメソッドは、最初のアクションと同じで、Webブラウザーを開くことを処理します。

ただし、最初に、StackOverflowの2つの値を収集する必要があります。 1つは言語タグで、もう1つは検索するテキストです。

言語タグを取得するには、Program Structure Interfaceを使用します。 This API parses all the files in a project and provides a programmatic way to inspect them.

この場合、PSIを使用してファイルのプログラミング言語を決定します。

PsiFile file = e.getData(CommonDataKeys.PSI_FILE);
Language lang = e.getData(CommonDataKeys.PSI_FILE).getLanguage();
String languageTag = "+[" + lang.getDisplayName().toLowerCase() + "]";

PSIは、ファイルに関する言語固有の詳細も提供することに注意してください。 たとえば、we could use the PSI to find all public methods in a Java class.

検索するテキストを取得するには、Editor APIを使用して、画面上で強調表示されているテキストを取得します。

final Editor editor = e.getRequiredData(CommonDataKeys.EDITOR);
CaretModel caretModel = editor.getCaretModel();
String selectedText = caretModel.getCurrentCaret().getSelectedText();

このアクションはエディターウィンドウとコンソールウィンドウの両方で同じですが、選択したテキストへのアクセスは同じように機能します。

これで、これをすべてactionPerformed宣言にまとめることができます。

@Override
public void actionPerformed(AnActionEvent e) {

    PsiFile file = e.getData(CommonDataKeys.PSI_FILE);
    Language lang = e.getData(CommonDataKeys.PSI_FILE).getLanguage();
    String languageTag = "+[" + lang.getDisplayName().toLowerCase() + "]";

    Editor editor = e.getRequiredData(CommonDataKeys.EDITOR);
    CaretModel caretModel = editor.getCaretModel();
    String selectedText = caretModel.getCurrentCaret().getSelectedText()

    String query = selectedText.replace(' ', '+') + languageTag;
    BrowserUtil.browse("https://stackoverflow.com/search?q=" + query);
}

このアクションは、updateという名前の2番目のメソッドもオーバーライドします。 これにより、さまざまな条件下でアクションを有効または無効にできます。

この場合、選択されたテキストがない場合、検索アクションを無効にします。

@Override
public void update(AnActionEvent e) {
     Editor editor = e.getRequiredData(CommonDataKeys.EDITOR);
     CaretModel caretModel = editor.getCaretModel();
     e.getPresentation().setEnabledAndVisible(caretModel.getCurrentCaret().hasSelection());
}

4.2. アクションの登録

アクションを記述したら、we need to register them with the IDE。 これを行うには2つの方法があります。

最初の方法は、新しいプロジェクトを開始するときに作成されるplugin.xmlファイルを使用することです。

デフォルトでは、ファイルには空の<actions>要素があり、ここにアクションを追加します。


    
        
    
    
        
    
    
        
    

XMLファイルを使用してアクションを登録すると、IDEの起動時に確実に登録されます。これは通常望ましい方法です。

アクションを登録する2番目の方法は、プログラムでActionManagerクラスを使用することです。

ActionManager.getInstance().registerAction("StackOverflow.SearchAction", new SearchAction());

これには、アクションを動的に登録できるという利点があります。 たとえば、リモートAPIと統合するプラグインを作成する場合、呼び出すAPIのバージョンに基づいて異なるアクションセットを登録することができます。

このアプローチの欠点は、起動時にアクションが登録されないことです。 アクションを管理するには、ApplicationComponentのインスタンスを作成する必要があります。これには、より多くのコーディングとXML構成が必要です。

5. プラグインのテスト

他のプログラムと同様に、IntelliJプラグインを作成するにはテストが必要です。 私たちが書いたような小さなプラグインの場合、プラグインがコンパイルされ、作成したアクションをクリックしたときに期待どおりに機能することを確認するだけで十分です。

プラグインの実行構成を使用して、プラグインを手動でテスト(およびデバッグ)できます。

image

これにより、プラグインがアクティブ化されたIntelliJの新しいインスタンスが起動します。 これにより、作成したさまざまなメニュー項目をクリックして、適切なStack Overflowページを開くことができます。

従来の単体テストを実行したい場合、IntelliJは単体テストを実行するためのheadless environmentを提供します。 必要なテストフレームワークを使用してテストを記述でき、テストはIDEの実際の非モックコンポーネントを使用して実行されます。

6. プラグインのデプロイ

プラグインDevKitは、プラグインをインストールして配布できるように、プラグインをパッケージ化する簡単な方法を提供します。 プラグインプロジェクトを右クリックし、「展開用のプラグインモジュールの準備」を選択するだけです。 これにより、プロジェクトディレクトリ内にJARファイルが生成されます。

生成されたJARファイルには、IntelliJへのロードに必要なコードと構成ファイルが含まれています。 ローカルにインストールすることも、他のユーザーが使用できるようにplugin repositoryに公開することもできます。

以下のスクリーンショットは、動作中の新しいStack Overflowメニュー項目の1つを示しています。

image

7. 結論

この記事では、IntelliJ IDEを強化する方法のほんの一部を強調するシンプルなプラグインを開発しました。

主にアクションを使用しましたが、IntelliJプラグインSDKはIDEに新しい機能を追加するいくつかの方法を提供します。 詳細については、official getting started guideを確認してください。

いつものように、サンプルプラグインの完全なコードはGitHub repositoryにあります。