このパートでは、強調表示、リンクシステム、オートコンプリート、コードナビゲーション。 前の部分はこちらです。
構文とエラーの強調表示
IDEAが対応するテキスト範囲を強調表示する方法を決定するために使用するクラスは、 TextAttributesKeyと呼ばれます 。 このクラスのインスタンスは、強調表示する必要のあるさまざまなタイプの要素(キーワード、数字、行、コメントなど)ごとに作成され、対応するタイプの要素に適用されるデフォルト属性を定義します(たとえば、キーワードは太字、青の数字、斜体の線、および緑の背景)。 エディターで使用される特定の属性へのTextAttributesKeyのマッピングはEditorColorsSchemeクラスによって定義され、プラグインが適切な構成インターフェースを提供する場合、ユーザーが構成できます。 強調表示では、複数のTextAttributeKeysの重複を使用できます。たとえば、1つのキーでスタイルを決定し、もう1つのキーで要素の色を決定できます。
基本的な構文の強調表示
構文とエラーの強調表示は、さまざまなレベルで実行されます。 最初は、字句解析の結果に基づいた構文の強調表示は、 SyntaxHighlighterインターフェイスを介して実行されます。 このインターフェイスは、トークンの各タイプのTextAttributeKeyインスタンスを返すため、特別な強調表示が必要です。 レクサーエラーを強調表示するために、無効な文字(
HighligherColors.BAD_CHARACTER
)にはTextAttributeKeyクラスの標準オブジェクトが使用されます。
Intelli IDEA 12.1では、カラー管理スキームがわずかに変更され、回路設計者の作業が容易になり、スキームが元々意図されていなかった場合でも、異なるプログラミング言語で同じディスプレイが作成されます。 以前は、言語プラグインは、たとえば暗いテーマと常に互換性があるとは限らない固定の配色を使用していました。 新しい実装により、特定の言語ではなく、スキームに関連付けられた一連の標準テキスト属性への依存関係を決定できます。 特定の言語の属性は、スキーマデザイナによって引き続き設定できますが、現在はオプションです。 互換性の問題を回避するため、新しい配色には拡張子.iclsが付けられています。
現在、 DefaultLanguageHighlighterColorsクラスを使用して、テキスト属性を定義し、標準キーに依存しています。
例:PropertiesプラグインのSyntaxHighlighlighter実装 。
ハイライトの第2レベル-解析中に発生したエラーのハイライト。 特定のトークンチェーンが言語の文法と一致しない場合、PsiBuilder.error()メソッドを使用して無効なトークンを強調表示し、エラーメッセージを表示できます。
注釈
バックライトの第3レベルは、 Annotatorインターフェイスを使用して行われます。 プラグインは、
com.intellij.annotator
拡張
com.intellij.annotator
で1つまたは複数の注釈を登録できます。その後、ユーザーの言語PSIツリーの要素を強調表示しながら、バックグラウンドプロセスで呼び出されます。 注釈は、構文だけでなくセマンティクスも分析できるため、エラーを処理および強調表示するためのより微妙なロジックを提供します。 注釈には、検出された問題を解決する機能(いわゆるクイックフィックス)が含まれる場合があります。
ファイルが変更されると、PSIツリーの変更された要素のみを処理するために、注釈がインクリメンタルに呼び出されます。
特定の範囲のテキストをエラーまたは警告として強調表示するために、注釈はAnnotationHolder型のオブジェクトでcreateErrorAnnotation()またはcreateWarningAnnotation()を呼び出し、オプションでAnnotatorクラスの返されたオブジェクトでregisterFix()を呼び出してエラー修正ロジックを追加します。 追加の強調表示を適用するために、注釈は空のメッセージでAnnotationHolder.createInfoAnnotation()を呼び出し、次にAnnotation.setTextAttributes()を呼び出して、テキスト属性を設定できます。
例: プロパティ言語のアノテーター 。
外部注釈
最後に、ユーザー言語がファイル検証に外部ツールを使用する場合、 ExternalAnnotatorインターフェースを実装し、
com.intellij.externalAnnotator
拡張
com.intellij.externalAnnotator
で登録することにより、結果を提供できます。 ExternalAnnotatorを使用したバックライトの優先順位は最も低く、すべてのバックグラウンドプロセスが完了した後にのみ発生します。 外部注釈は、同じAnnotationHolderインターフェイスを使用して、外部ツールの出力を調整し、強調表示を表示します。
色設定ページ
プラグインは、ユーザーが特定の要素の色をカスタマイズできるようにする構成インターフェイスも提供できます。 これを行うには、 ColorSettingPageクラスのインスタンスを作成し、拡張ポイント
com.intellij.colorSettingsPage
登録する必要が
com.intellij.colorSettingsPage
ます。
例: プロパティのColorSettingsPage
「HTMLにエクスポート」機能は、エディターと同じ強調表示メカニズムを使用するため、SyntaxHighlighterの実装直後にユーザー言語で使用可能になります。
IntelliJ IDEAリファレンスシステム
ユーザー言語プログラム構造の実装で最も重要でわかりにくい部分の1つは、リンク解決です。 要素の使用場所(式の変数、メソッド呼び出しなど)から定義の場所(変数、メソッドなどの宣言)に進む機能。 これは、「宣言に移動」(Ctrl-BおよびCtrl-Click)などの多くのIDEA機能をサポートするため、および使用、名前変更、およびオートコンプリートを検索する場合に必要です。
参照として動作する必要がある各PSI要素は、 PsiReferenceインターフェースの対応する実装を返すように、PsiElement.getReference()メソッドをオーバーライドする必要があります。 このインターフェイスは、PsiElementクラス自体によって、または個別のインターフェイスとして実装できます。 要素に複数のリンクを含めることができる場合(クラスをリストする行など)、この場合、リンクの配列を返すPsiElement.getReferences()メソッドを実装する必要があります。
PsiReferenceインターフェイスのメインメソッドはresolve()で、リンクが指す要素を返すか、リンクが解決できない場合(たとえば、未定義のクラスを指す場合)にnullを返します。 反対のメソッドisReferenceTo()は、リンクが特定の要素を指しているかどうかを確認します。 後者のメソッドは、resolve()を呼び出し、結果を渡されたPSI要素と比較することで実装できますが、開発者は追加の最適化を適用できます。
例:プロパティプラグインのResourceBundleへのリンク 。
IDEAは、リンクサポートを実装するためのベースとして使用できる多くのインターフェイス、つまりPsiScopeProcessorインターフェイスとPsiElement.processDeclarations()メソッドを提供します。 これらのインターフェースには、ほとんどのユーザー言語には必要ない多くの複雑さがありますが(例えば、ジェネリック型の置換のサポート)、ユーザー言語がJavaコードを参照できる場合に必要です。 Javaとの相互運用性が必要ない場合、または他の理由がある場合、プラグインはリンク解決の標準実装をオーバーライドする場合があります。
参照の解決に使用される標準IDEAヘルパークラスは、次のコンポーネントで構成されています。
- PsiScopeProcessorインターフェースを実装するクラス。これは、可能なリンク定義を収集し、完全に完了すると解決プロセスを停止します。 実装する必要があるメインメソッドはexecute()です。これは各定義を処理するために呼び出され、定義が見つかったときにfalseを返します。
- リンクの場所からその解決までツリーをトラバースするか、スコープから出る関数。
- PSIツリーの走査中にprocessDeclarations()メソッドが呼び出されるPSI要素。 要素が定義の場合、要素への参照をexecute()メソッドに渡します。 必要に応じて、スコープを決定するための言語規則に従って、要素はPsiScopeProcessorをその子要素に渡すことができます。
リンクが複数のターゲット要素を使用できるようにするPsiReferenceインターフェイスの拡張機能があります-PsiPolyVariantReference。 リンクターゲット要素はmultiResolve()メソッドによって返されます。 このタイプのリンクの「宣言に移動」アクションを使用すると、ナビゲーションに使用する要素を選択できます。 multiResolve()の実装は、最初の結果が見つかった後に検索を停止する代わりに、残りのターゲット要素の収集を続ける場合、PsiScopeProcessorに基づくことができます。
一方、IntelliJ IDEAには、参照コントリビューターおよび参照プロバイダーを介して参照システムを実装するアプローチがあります。
PsiReferenceContributorは各PsiElementをチェックし、ユーザーが設定した対応する説明に従って、このケースに登録されているリンクプロバイダーのオブジェクトを返します( 例 )。 同様に、 PsiReferenceProviderは、PSIツリーの単一要素内のリンクを見つけるように設計されたクラスです。 PsiReferenceオブジェクトの配列を返します( 例 )。
PsiReferenceProvider.getReferencesByElement()メソッドは、渡されたPsiElement要素に含まれるリンクのリスト(PsiReference)を返す必要があります。 この場合、1つのリンクのみが返されますが、一般的な場合は複数存在する可能性があり、各リンクには対応するtextRange(PSI要素のテキスト内のリンクの開始インデックスと終了インデックス)を含める必要があります。
参照コントリビューターは、適切な拡張ポイント-com.intellij.psi.referenceContributorのplugin.xmlファイルに登録する必要があります。
その後、PsiElement.getReferences()メソッドを実装するときに、彼の作業の結果を使用してリンクのリストを取得することができます。 各参照要素でこのコードを複製しないように、カスタムPsi要素の基本クラスを定義できます。
public class MyASTWrapperPsiElement extends ASTWrapperPsiElement { public MyASTWrapperPsiElement(@NotNull ASTNode astNode) { super(astNode); } @Override public PsiReference getReference() { PsiReference[] references = getReferences(); return references.length == 0 ? null : references[0]; } @NotNull @Override public PsiReference[] getReferences() { // , Contributor return ReferenceProvidersRegistry.getReferencesFromProviders(this); } }
コード補完
カスタム言語プラグインで使用できる自動補完には、単純なリンクアドオンとプロバイダーベースのアドオンの2つの主な種類があります。
シンプルなオートコンプリート
アドオンリストを作成するために、IDEAはカーソルの下のリンクまたはカーソルの下に配置されたダミー要素のいずれかでPsiReference.getVariants()メソッドを呼び出します。 このメソッドは、文字列、PSI要素、またはLookupElementクラスのインスタンスを含むオブジェクトの配列を返す必要があります。 返された配列でPsiElementのインスタンスが見つかった場合、対応するアイコンが追加のリストに表示されます。
getVariants()を実装する最も一般的な方法は、PsiReference.resolve()メソッドと同じツリートラバーサル関数を使用することですが、見つかったすべての定義を返します。
プロバイダーベースの自動補完
CompletionContributorインターフェースに基づくアドオンの実装により、コード補完の操作を最大限に制御できます。
Completion Contributorを使用する主なシナリオは、extend()メソッドを呼び出し、このアドオンオプションを適用できる「パターン」パラメーターに適切なコンテキストを渡すことで構成されます。
例:MANIFEST.MFファイル内のキーワードの自動補完のためのCompletionContributor 。
自動補完リストの項目は、 LookupElementインターフェイスのインスタンスによって表されます。 これらのオブジェクトは、通常LookupElementBuilderを使用して作成されます。 それぞれについて、次の属性を定義できます。
- メインテキスト、追加テキスト、タイプのある行-追加テキストはメインテキストの直後に表示されますが、一致の検索には使用されません。主にメソッドパラメーターのリストを表示することを目的としています。 追加リスト内の補完された式のタイプを含む行は右揃えで、通常、メソッドまたはそれを含むクラスの戻り値のタイプを示します。
- アイコン
- テキスト属性
- テキストを挿入するときのハンドラーは、追加リストから項目が選択されたときに実行されるコールバックメソッドであり、たとえば、メソッド呼び出しの後に括弧を挿入するために使用できます。
利用状況検索
IDEAの使用状況の検索アクションはマルチステッププロセスであり、その各ステップはプラグインからの参加を必要とします:拡張ポイントcom.intellij.lang.findUsagesProviderでのFindUsagesProviderの実装および登録の形式、およびプログラム構造(PsiNamedElementおよびPsiReferenceインターフェース)の実装の機能。
例:プロパティのFindUsagesProviderを実装します。
この機能を実装するには、次の手順を実行する必要があります。
- IDEAは、使用状況の検索アクションを実行する前に、各ユーザー言語ファイルで表される単語のインデックスを作成します。 IDEは、FindUsagesProvider.getWordsScanner()から取得したWordsScannerの実装を使用して、各ファイルのコンテンツをロードし、ワードハンドラーとともにワードスキャナーに渡します。 スキャナーはテキストを単語に分割し、各単語のコンテキスト(コード、コメント、行)を定義して、ハンドラーに渡します。 スキャナーを実装する最も簡単な方法は、DefaultWordsScannerクラスを使用することです。
- ユーザーが使用状況の検索アクションを呼び出すと、IDEAは検索するリンクを持つアイテムを識別します。 カーソルの下のPSI要素(またはカーソルの下のトークンツリーの直接の親)は、 PsiNamedElementまたはその参照である必要があります。 IDEAはワードキャッシュを使用して、PsiNamedElement.getName()によって返されるテキストを検索します。 PsiNamedElementテキスト範囲にgetName()によって返された識別子以外の他のテキストが含まれる場合、開始識別子オフセットを返すようにgetTextOffset()メソッドを書き換える必要があります。
- アイテムが見つかると、IDEAはFindUsagesProviderを呼び出します。 canFindUsagesFor()は、アクションがこの要素に適用されるかどうかを調べます。
- Find Usagesダイアログがユーザーに表示されると、IDEAはFindUsagesProvider.getType()およびFindUsagesProvider.getDescriptiveName()を呼び出して、この要素の表示方法を決定します。
- 見つかった単語を含む各ファイルに対して、IDEAはPSIツリーを構築し、再帰下降を実行します。 IDEAは各要素のテキストを単語に分割し、スキャンします。 要素に識別子としてインデックスが付けられている場合、単語ごとに、検索対象の要素を指しているかどうかがチェックされます。
- すべての使用が見つかった後、結果が使用状況パネルに表示されます。 ユーザーに表示するテキストは、FindUsagesProvider.getNodeText()メソッドから取得されます。
Find Usagesパネルの見出しに見つかった要素の名前を正しく表示するには、ElementDescriptionProviderインターフェイスの実装を提供する必要があります。 この場合、プロバイダーに渡されるElementDescriptionLocationオブジェクトは、実際のタイプUsageViewLongNameLocationである必要があります。
例:プロパティプラグインのElementDescriptionProvider 。
次の部分では、リファクタリング、フォーマットなど。