LoginSignup
18
16

More than 5 years have passed since last update.

PhpStorm Plugin(オートコンプリート)の作成方法について

Last updated at Posted at 2015-04-09

今回はオートコンプリートプラグイン作成方法について簡単に説明します

基本的な部分はRubyMineやAndroid Studioでも変わらないと思います(試してないです)

plugin1.gif

今回作成するプラグイン

今回はSample::get()の引数として渡されるクラス名を補完するプラグインを作成します

/**
 * 何か処理する
 *
 * @param string $className クラス名
 */
public static function get($className)
{
    // 何か処理
}

試したバージョン

  • IntelliJ IDEA - 13.1.2
  • PhpStorm - 8.0.3
  • IntelliJ Platform Plugin SDK - IDEA IU-135.690

作成方法

プロジェクトの作成

プラグインプロジェクト(IntelliJ Platform Plugin)を新規作成します

今回はSampleStormという名前にしてます

プロジェクトの設定

以下に従いライブラリ(php-openapi.jar、php.jar)とplugin.xmlを編集(ライブラリの依存関係を記入)をしてください

Project Language Level

デフォルトでPhpStormは6.0で起動する為、7.0以降でビルドされたプラグインをインストールするとエラー(Unsupported major.minor version 51.0みたいなやつ)になります。

自分しか使わない、環境が固定されている等であれば特に6.0にする必要はないと思いますが、不特定多数に使うような場合は6.0にしておく方がよいかもしれません。

META-INF/plugin.xml

プラグインの情報としてid, name, version, vendorを編集します。

ここの情報を編集しないとプラグインは動作しないので注意してください。

<idea-plugin version="2">
  <id>com.samplestorm</id>
  <name>SampleStorm</name>
  <version>1.0</version>
  <vendor email="aaa@example.com" url="http://www.example.com">Example</vendor>

SampleCompletionContributorクラス

ドキュメントによるとオートコンプリートを提供するのに一番簡単な方法はCompletion Contributorを利用する事だそうなのでそれを利用します。

CompletionContributorクラスを継承したSampleCompletionContributorクラスを作成します。

package samplestorm.completion.contributor;

import com.intellij.codeInsight.completion.CompletionContributor;

public class SampleCompletionContributor extends CompletionContributor {

    public SampleCompletionContributor() {
        extend(CompletionType.BASIC, PlatformPatterns.psiElement(PsiElement.class), new CompletionProvider<CompletionParameters>() {
            @Override
            protected void addCompletions(@NotNull CompletionParameters completionParameters,
                                          ProcessingContext processingContext,
                                          @NotNull CompletionResultSet completionResultSet) {
                completionResultSet.addElement(LookupElementBuilder.create("Hello"));
            }
        });
    }

}

コンストラクタ内でextendメソッドを利用してSampleCompletionContributorクラスが提供するオートコンプリートを設定します

META-INF/plugin.xml

作成したSimpleCompletionContributorクラスを追加します

言語がPHPの場合に実施するようになります

<extensions defaultExtensionNs="com.intellij">
    <!-- Add your extensions here -->
    <completion.contributor language="PHP" implementationClass="samplestorm.completion.contributor.SampleCompletionContributor"/>
</extensions>

これで一旦デバッグを起動するとHelloという文字列に補完が入るようになります

ss 2015-04-09 13.43.39.png

CompletionContributor.extendメソッド

以下の引数を指定する事でオートコンプリートを設定できます

  1. CompletionType - オートコンプリートのタイプを指定します
  2. ElementPattern - オートコンプリートする対象を指定します
  3. CompletionProvider - オートコンプリートを提供するクラスを指定します

今回作成するプラグインでは2のElementPatternでSample::get()を対象として、3のCompletionProviderでPHPクラス名を提供するように実装します。

オートコンプリートする対象を指定する

上記サンプルでは最低限の指定しかしていないので別にSample::get()以外(aaa:bbb())でも補完がかかります。

ss 2015-04-09 13.58.05.png

これを修正してSample::get()にだけ補完が入るように修正します。

指定するにはPsi Elementの基本知識を必要になります。

PsiElement

PhpStorm(IntelliJ)ではプロジェクト配下のファイルはPSI(Program Structure Interface) Elementによりツリー上で表現されています

例えば、Sample::get("className")のget("className")だけをすごく簡単に書くと以下のような感じなります(感じなので正確じゃないです)

// ツリーはもっとあると
+ Method reference (get)
    + Class reference (Sample)
    + Parameter list
        + String ("className")
            + PsiElement (")
            + PsiElement (className)
            + PsiElement (")

このようなツリー上の場合にのみ補完が入ると指定する事でSample::get()の時だけ補完が入るようになります。

指定ルールはリーフから書くので今回でいうとPsiElement (className)から指定します ※もっと綺麗な指定方法があると思います、力業ですみません!

  1. 自分の親(withParent)はString
  2. 1の親はParamter List
  3. 2の親はMethod Reference
  4. 3はクラスメソッド
  5. メソッド名はget
  6. 3の親の名前はSample

指定ルール返すsamplePatternというメソッドを作成します

    public static PsiElementPattern.Capture samplePattern() {
        return PlatformPatterns.psiElement(PsiElement.class)
                .withParent(
                        PlatformPatterns.psiElement(StringLiteralExpression.class)
                                .withParent(
                                        PlatformPatterns.psiElement(PhpElementTypes.PARAMETER_LIST)
                                                .withParent(
                                                        PlatformPatterns.psiElement(PhpElementTypes.METHOD_REFERENCE)
                                                                .referencing(
                                                                        PhpPatterns.psiElement().withElementType(
                                                                                PhpElementTypes.CLASS_METHOD
                                                                        ).withName(StandardPatterns.string().oneOf("get"))
                                                                                .withParent(
                                                                                        PhpPatterns.psiElement().withName("Sample")
                                                                                )
                                                                )
                                                )
                                )
                );
    }

extend()を修正してsamplePatternを呼び出すようにします

extend(CompletionType.BASIC, samplePattern(), new CompletionProvider<CompletionParameters>() {
    @Override
    protected void addCompletions(@NotNull CompletionParameters completionParameters,
                                  ProcessingContext processingContext,
                                  @NotNull CompletionResultSet completionResultSet) {
        completionResultSet.addElement(LookupElementBuilder.create("Hello"));
    }
});

デバッグを起動します

これでSample::get()では補完が入り、aaa::bbb()では補完が入らないようになります

ss 2015-04-09 14.29.02.png

補完時にPHPクラスを提供する

CompletionProviderを継承したSampleProviderを作成します

public class SampleProvider<CompletionParameters>  extends CompletionProvider {

    @Override
    protected void addCompletions(@NotNull com.intellij.codeInsight.completion.CompletionParameters completionParameters,
                                  ProcessingContext processingContext,
                                  @NotNull CompletionResultSet completionResultSet) {

        completionResultSet.addElement(LookupElementBuilder.create("Hello"));
}

extend()を修正してSampleProviderを指定します

extend(CompletionType.BASIC, samplePattern(), new SampleProvider<CompletionParameters>());

デバッグを起動して補完がうまく動くのを確認します

addCompletions()メソッドの引数で渡されるCompletionResultSetにLookupElmentに補完候補を追加するだけで後はいい感じで動作してくれます

Helloを追加している行をコピーすると他の文字列も補完が入るようになるのが確認できると思います

LookupElement

補完が入った時の1行が1LookupElementのイメージです、CompletionResultSetが全体

ss_2015-04-09_11_05_52 2.png

今回は既に用意されているものを利用しますが、これも継承する事で独自のものを作れます

アイコンやテキスト、装飾(文字色、Boldとか)を設定できるようになります(時間があったらどこかで書きます)

今回はプロジェクト内のPHPクラスが補完されればいいのでプロジェクト内のPHPファイルを取得して追加していくようにします

プロジェクト内のPHPをインデックス化して検索機能を提供しているクラスPhpIndexが提供されているのでこれを利用します、またLookupElementも既に用意されているPhpLookupElementを利用します

@Override
protected void addCompletions(@NotNull com.intellij.codeInsight.completion.CompletionParameters completionParameters,
                              ProcessingContext processingContext,
                              @NotNull CompletionResultSet completionResultSet) {

    Project project = completionParameters.getPosition().getContainingFile().getProject();
    PhpIndex phpIndex = PhpIndex.getInstance(project);
    for (String className : phpIndex.getAllClassNames(completionResultSet.getPrefixMatcher())) {
        PhpClass phpClass = phpIndex.getClassByName(className);
        if (phpClass != null) {
            completionResultSet.addElement(new PhpLookupElement(phpClass));
        }
    }
}

デバッグでPHPクラスが補完されるか確認してみてください

パッケージ化する

プロジェクトを選択して右メニューから以下を選択するとパッケージ(SampleStorm.jar)が作成できます

ss 2015-04-09 15.21.50.png

これをPhpStormのPluginをディスクからインストールしてみると動くはずです

ss 2015-04-09 15.19.17.png

おまけ

PsiViewer

Psi Elementのツリー上を確認すた為に便利なプラグインがPsiViewerがあります

これを利用してSample::get()のツリーがどのようになっているを確認します

ss 2015-04-09 14.07.35.png

Links

参考にしたサイトです

以上

18
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
16