1. 序章

過去数年間で、JetBrainsのIntelliJはすぐにJava開発者のトップIDEになりました。 最新のJavaの状態レポートでは、IntelliJが61 % o fの回答者に選ばれたIDEであり、前年の55% tから増加しました。

IntelliJをJava開発者にとって非常に魅力的なものにする1つの機能はプラグインを使用して新しい機能を拡張および作成する機能。

このチュートリアルでは、Gradleで新しい推奨方法を使用してIntelliJプラグインを作成し、IDEを拡張するいくつかの方法を示します。 この記事は、プラグイン開発キットを使用した同じプラグインの作成について説明している以前ののリミックスです。

2. プラグインの主な種類

最も一般的なタイプのプラグインには、次の機能が含まれます。

  • カスタム言語のサポート:さまざまな言語で記述されたコードを記述、解釈、およびコンパイルする機能
  • フレームワークの統合:Springなどのサードパーティフレームワークのサポート
  • ツールの統合:Gradleなどの外部ツールとの統合
  • ユーザーインターフェイスアドオン:新しいメニュー項目、ツールウィンドウ、プログレスバーなど

プラグインは多くの場合、複数のカテゴリに分類されます。 たとえば、IntelliJに同梱されている Gitプラグインは、システムにインストールされているgit実行可能ファイルと相互作用します。 プラグインは、ツールウィンドウとポップアップメニュー項目を提供すると同時に、プロジェクト作成ワークフロー、設定ウィンドウなどにも統合されます。

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

プラグインを作成するには、2つのサポートされている方法があります。 Plugin Devkit を使用する代わりに、Gradleを使用する新しいプロジェクトに推奨される方法を使用します。

Gradleベースのプラグインの作成は、新規>プロジェクトメニューを使用して行います。

必要なプラグインクラスがクラスパスで利用できるようにするには、JavaとIntelliJプラットフォームプラグインを含める必要があることに注意してください。

この記事の執筆時点では、IntelliJプラグインの作成に使用できるのはJDK8のみです

4. プラグインの例

IDEの複数の領域から人気のあるStackOverflowWebサイトにすばやくアクセスできるプラグインを作成します。 含まれるもの:

  • [質問する]ページにアクセスするための[ツール]メニュー項目
  • 強調表示されたテキストのスタックオーバーフローを検索するためのテキストエディタとコンソール出力の両方のポップアップメニュー項目

4.1. アクションの作成

アクションは、プラグインにアクセスするための最も一般的な方法です。 アクションは、メニュー項目やツールバーボタンのクリックなど、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ページを開く際の微妙な違いをすべて処理します。

StackOverflowで検索を実行するには、言語タグと検索するテキストの2つのパラメーターが必要です。

言語タグを取得するには、 Program Structure Interface (PSI)を使用します。 このAPIは、プロジェクト内のすべてのファイルを解析し、それらを検査するプログラム的な方法を提供します。

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

Optional<PsiFile> psiFile = Optional.ofNullable(e.getData(LangDataKeys.PSI_FILE));
String languageTag = psiFile.map(PsiFile::getLanguage)
  .map(Language::getDisplayName)
  .map(String::toLowerCase)
  .map(lang -> "[" + lang + "]")
  .orElse("");

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

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

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

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

@Override
public void actionPerformed(@NotNull AnActionEvent e) {
    Optional<PsiFile> psiFile = Optional.ofNullable(e.getData(LangDataKeys.PSI_FILE));
    String languageTag = psiFile.map(PsiFile::getLanguage)
      .map(Language::getDisplayName)
      .map(String::toLowerCase)
      .map(lang -> "[" + lang + "]")
      .orElse("");

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

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

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

Editor editor = e.getRequiredData(CommonDataKeys.EDITOR);
CaretModel caretModel = editor.getCaretModel();
e.getPresentation().setEnabledAndVisible(caretModel.getCurrentCaret().hasSelection());

4.2. アクションの登録

アクションを記述したら、それらをIDEに登録する必要があります。 これを行うには2つの方法があります。

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

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

<actions>
    <action
      id="StackOverflow.AskQuestion.ToolsMenu"
      class="com.baeldung.intellij.stackoverflowplugin.AskQuestionAction"
      text="Ask Question on Stack Overflow"
      description="Ask a Question on Stack Overflow">
        <add-to-group group-id="ToolsMenu" anchor="last"/>
    </action>
    <action
      id="StackOverflow.Search.Editor"
      class="com.baeldung.intellij.stackoverflowplugin.SearchAction"
      text="Search on Stack Overflow"
      description="Search on Stack Overflow">
        <add-to-group group-id="EditorPopupMenu" anchor="last"/>
    </action>
    <action
      id="StackOverflow.Search.Console"
      class="com.baeldung.intellij.stackoverflowplugin.SearchAction"
      text="Search on Stack Overflow"
      description="Search on Stack Overflow">
        <add-to-group group-id="ConsoleEditorPopupMenu" anchor="last"/>
    </action>
</actions>

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

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

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

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

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

5. プラグインのテスト

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

Gradleツールウィンドウを開いてrunIdeタスクを実行することで、プラグインを手動でテスト(およびデバッグ)できます。

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

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

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

Gradleプラグインは、プラグインをパッケージ化する簡単な方法を提供するため、プラグインをインストールして配布できます。 Gradleツールウィンドウを開き、buildPluginタスクを実行するだけです。 これにより、 build /distributionsディレクトリ内にZIPファイルが生成されます。

生成されたZIPファイルには、IntelliJにロードするために必要なコードと構成ファイルが含まれています。 ローカルにインストールすることも、プラグインリポジトリに公開して他の人が使用できるようにすることもできます。

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

7. 結論

この記事では、IntelliJIDEを拡張する方法を強調する簡単なプラグインを開発しました。

私たちは主にアクションを扱いますが、IntelliJプラグインSDKは、IDEに新しい機能を追加するいくつかの方法を提供します。 詳細については、公式のスタートガイドをご覧ください。

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