エージェント型開発を探求する -

セマンティック ハイライト ガイド

セマンティックハイライトは、構文ハイライトガイドで説明されている構文ハイライトを補完する機能です。Visual Studio Code はトークン化エンジンとして主に TextMate 文法を使用します。TextMate 文法はファイルを単一の入力として扱い、正規表現で表現された字句規則に基づいてファイルを分割します。

セマンティックトークン化により、言語サーバーは、プロジェクトのコンテキスト内でシンボルを解決する方法に関する知識に基づき、追加のトークン情報を提供できるようになります。テーマはセマンティックトークンを使用するように設定することで、文法による構文ハイライトを改善・洗練させることができます。エディタは、文法によるハイライトの上にセマンティックトークンによるハイライトを適用します。

セマンティックハイライトで追加できる内容の例を以下に示します。

セマンティックハイライトなし

without semantic highlighting

セマンティックハイライトあり

with semantic highlighting

言語サービスのシンボル理解に基づく色の違いに注目してください。

  • 10行目: languageModes がパラメータとして色分けされています。
  • 11行目: RangePosition がクラスとして、document がパラメータとして色分けされています。
  • 13行目: getFoldingRanges が関数として色分けされています。

セマンティックトークンプロバイダー

セマンティックハイライトを実装するために、言語拡張機能はドキュメントの言語やファイル名ごとに セマンティックトークンプロバイダー を登録できます。エディタはセマンティックトークンが必要なときにプロバイダーにリクエストを送信します。

const tokenTypes = ['class', 'interface', 'enum', 'function', 'variable'];
const tokenModifiers = ['declaration', 'documentation'];
const legend = new vscode.SemanticTokensLegend(tokenTypes, tokenModifiers);

const provider: vscode.DocumentSemanticTokensProvider = {
  provideDocumentSemanticTokens(
    document: vscode.TextDocument
  ): vscode.ProviderResult<vscode.SemanticTokens> {
    // analyze the document and return semantic tokens

    const tokensBuilder = new vscode.SemanticTokensBuilder(legend);
    // on line 1, characters 1-5 are a class declaration
    tokensBuilder.push(
      new vscode.Range(new vscode.Position(1, 1), new vscode.Position(1, 5)),
      'class',
      ['declaration']
    );
    return tokensBuilder.build();
  }
};

const selector = { language: 'java', scheme: 'file' }; // register for all Java documents from the local file system

vscode.languages.registerDocumentSemanticTokensProvider(selector, provider, legend);

セマンティックトークンプロバイダー API には、言語サーバーの機能に合わせて2つの種類があります。

  • DocumentSemanticTokensProvider - 常にドキュメント全体を入力として受け取ります。

    • provideDocumentSemanticTokens - ドキュメント内のすべてのトークンを提供します。
    • provideDocumentSemanticTokensEdits - ドキュメント内のすべてのトークンを、前回のレスポンスからの差分として提供します。
  • DocumentRangeSemanticTokensProvider - 範囲に対してのみ動作します。

    • provideDocumentRangeSemanticTokens - ドキュメントの指定範囲内のすべてのトークンを提供します。

プロバイダーが返す各トークンには、トークンタイプ、任意の数のトークン修飾子、およびトークン言語から構成される分類情報が付随します。

上記の例で見られるように、プロバイダーは使用するタイプと修飾子を SemanticTokensLegend で指定します。これにより、provide API はトークンタイプと修飾子を凡例へのインデックスとして返すことができます。

セマンティックトークンの分類

セマンティックトークンプロバイダーの出力はトークンで構成されます。各トークンには範囲と、そのトークンがどのような構文要素を表すかを示すトークン分類があります。オプションとして、トークンが埋め込み言語の一部である場合、分類に言語名を指定することもできます。

構文要素の種類を記述するために、セマンティックトークンタイプと修飾子が使用されます。この情報は構文ハイライトガイドで説明されている TextMate スコープと似ていますが、より専用でクリーンな分類システムを目指しました。

VS Code には、すべてのセマンティックトークンプロバイダーが使用できる標準的なセマンティックトークンタイプと修飾子のセットが付属しています。それでも、セマンティックトークンプロバイダーは新しいタイプや修飾子を自由に定義し、標準タイプのサブタイプを作成できます。

標準トークンタイプと修飾子

標準タイプと修飾子は、多くの言語で使用される一般的な概念をカバーしています。各言語で一部のタイプや修飾子に異なる用語が使用される場合がありますが、標準の分類に従うことで、テーマ作成者は言語間で共通して機能するテーマ設定ルールを定義できるようになります。

これらは VS Code であらかじめ定義されている標準のセマンティックトークンタイプとセマンティックトークン修飾子です。

標準トークンタイプ

ID 説明
namespace 名前空間、モジュール、またはパッケージを宣言または参照する識別子用。
class クラス型を宣言または参照する識別子用。
enum 列挙型を宣言または参照する識別子用。
interface インターフェース型を宣言または参照する識別子用。
struct 構造体型を宣言または参照する識別子用。
typeParameter 型パラメータを宣言または参照する識別子用。
type 上記に含まれない型を宣言または参照する識別子用。
parameter 関数またはメソッドのパラメータを宣言または参照する識別子用。
variable ローカル変数またはグローバル変数を宣言または参照する識別子用。
property メンバープロパティ、メンバーフィールド、またはメンバー変数を宣言または参照する識別子用。
enumMember 列挙型のプロパティ、定数、またはメンバーを宣言または参照する識別子用。
decorator デコレータや注釈を宣言または参照する識別子用。
event イベントプロパティを宣言する識別子用。
function 関数を宣言する識別子用。
method メンバー関数またはメソッドを宣言する識別子用。
macro マクロを宣言する識別子用。
label ラベルを宣言する識別子用。
comment コメントを表すトークン用。
string 文字列リテラルを表すトークン用。
keyword 言語キーワードを表すトークン用。
number 数値リテラルを表すトークン用。
regexp 正規表現リテラルを表すトークン用。
operator 演算子を表すトークン用。

標準トークン修飾子

ID 説明
declaration シンボルの宣言用。
definition ヘッダーファイルなどにおけるシンボルの定義用。
readonly 読み取り専用の変数やメンバーフィールド(定数)用。
static クラスメンバー(静的メンバー)用。
deprecated 非推奨となったシンボル用。
abstract 抽象的な型やメンバー関数用。
async 非同期(async)としてマークされた関数用。
modification 値が代入される変数参照用。
documentation ドキュメント内に出現するシンボル用。
defaultLibrary 標準ライブラリの一部であるシンボル用。

標準タイプおよび修飾子に加えて、VS Code はタイプと修飾子を類似の TextMate スコープにマッピングする定義を保持しています。これは セマンティックトークンスコープマップ セクションで説明されています。

カスタムトークンタイプと修飾子

必要に応じて、拡張機能は package.jsonsemanticTokenTypes および semanticTokenModifiers 寄与ポイントを通じて、新しいタイプや修飾子を宣言したり、既存タイプのサブタイプを作成したりできます。

{
  "contributes": {
    "semanticTokenTypes": [
      {
        "id": "templateType",
        "superType": "type",
        "description": "A template type."
      }
    ],
    "semanticTokenModifiers": [
      {
        "id": "native",
        "description": "Annotates a symbol that is implemented natively"
      }
    ]
  }
}

上記の例では、拡張機能が新しいタイプ templateType と新しい修飾子 native を宣言しています。type をスーパークラスとして指定することで、type のテーマスタイルルールが templateType にも適用されます。

{
  "name": "Red Theme",
  "semanticTokenColors": {
    "type": "#ff0011"
  }
}

上記で示された semanticTokenColors"#ff0011" は、type および templateType を含むそのすべてのサブタイプに適用されます。

カスタムトークンタイプとともに、拡張機能はそれらをどのように TextMate スコープへマッピングするかを定義できます。これは カスタムマッピング セクションで説明されています。カスタムマッピングルールはスーパークラスから自動的に継承されないことに注意してください。サブタイプは、より具体的なスコープに対してマッピングを再定義する必要があります。

セマンティックハイライトの有効化

セマンティックトークンを計算してハイライトするかどうかは、設定 editor.semanticHighlighting.enabled によって決定されます。値として truefalseconfiguredByTheme を取ることができます。

  • true および false は、すべてのテーマに対してセマンティックハイライトをオンまたはオフにします。
  • configuredByTheme がデフォルトであり、各テーマがセマンティックハイライトを有効にするかどうかを制御できます。VS Code に付属するすべてのテーマ(例: デフォルトの "Dark+")は、デフォルトでセマンティックハイライトが有効になっています。

セマンティックトークンに依存する言語拡張機能は、package.json で自身の言語のデフォルトを上書きできます。

{
  "configurationDefaults": {
    "[languageId]": {
      "editor.semanticHighlighting.enabled": true
    }
  }
}

テーマ設定

テーマ設定とは、トークンに色やスタイルを割り当てることです。テーマ設定ルールはカラーテーマファイル(JSON形式)で指定されます。ユーザーはユーザー設定でテーマ設定ルールをカスタマイズすることもできます。

カラーテーマにおけるセマンティックカラー

セマンティックトークンに基づいたハイライトをサポートするため、カラーテーマファイルのフォーマットに2つの新しいプロパティが追加されました。

プロパティ semanticHighlighting は、そのテーマがセマンティックトークンを使用したハイライトに対応しているかどうかを定義します。デフォルトでは false ですが、すべてのテーマで有効にすることを推奨します。このプロパティは、設定 editor.semanticHighlighting.enabledconfiguredByTheme に設定されている場合に使用されます。

プロパティ semanticTokenColors を使用すると、テーマはセマンティックトークンプロバイダーから出力されるトークンタイプと修飾子に一致する新しい配色ルールを定義できます。

{
  "name": "Red Theme",
  "tokenColors": [
    {
      "scope": "comment",
      "settings": {
        "foreground": "#dd0000",
        "fontStyle": "italic"
      }
    }
  ],
  "semanticHighlighting": true,
  "semanticTokenColors": {
    "variable.readonly:java": "#ff0011"
  }
}

variable.readonly:java はセレクタと呼ばれ、(*|tokenType)(.tokenModifier)*(:tokenLanguage)? という形式を持ちます。

この値は、ルールが一致した場合のスタイルを記述します。文字列(前景色を表す)か、あるいは tokenColors 内の TextMate テーマルールで使用されるような { foreground: string, bold: boolean, italic: boolean, underline: boolean } または { foreground: string, fontStyle: string } 形式のオブジェクトのいずれかです。

前景色の指定は、カラーフォーマットで説明されている形式に従う必要があります。透過色はサポートされていません。

セレクタとスタイルのその他の例を以下に示します。

  • "*.declaration": { "bold": true } // すべての宣言を太字にする
  • "class:java": { "foreground": "#0f0", "italic": true } // Java のクラス

ルールが一致しない場合、またはテーマに semanticTokenColors セクションがない(が semanticHighlighting が有効である)場合、VS Code は セマンティックトークンスコープマップ を使用して、指定されたセマンティックトークンの TextMate スコープを評価します。そのスコープが、tokenColors 内のテーマの TextMate テーマルールと照合されます。

セマンティックトークンスコープマップ

特定のセマンティックルールを定義していないテーマに対してもセマンティックハイライトを機能させ、カスタムトークンタイプや修飾子のフォールバックとして機能させるために、VS Code はセマンティックトークンセレクタから TextMate スコープへのマップを保持しています。

テーマでセマンティックハイライトが有効になっているにもかかわらず、指定されたセマンティックトークンのルールが含まれていない場合、これらの TextMate スコープを使用して TextMate テーマルールが検索されます。

定義済みの TextMate スコープマッピング

以下の表は、現在定義済みのマッピングをリストしたものです。

セマンティックトークンセレクタ フォールバック TextMate スコープ
namespace entity.name.namespace
type entity.name.type
type.defaultLibrary support.type
struct storage.type.struct
class entity.name.type.class
class.defaultLibrary support.class
interface entity.name.type.interface
enum entity.name.type.enum
function entity.name.function
function.defaultLibrary support.function
method entity.name.function.member
macro entity.name.function.preprocessor
variable variable.other.readwrite , entity.name.variable
variable.readonly variable.other.constant
variable.readonly.defaultLibrary support.constant
parameter variable.parameter
property variable.other.property
property.readonly variable.other.constant.property
enumMember variable.other.enummember
event variable.other.event

カスタム TextMate スコープマッピング

このマップは、拡張機能の package.json にある semanticTokenScopes 寄与ポイントを通じて拡張できます。

拡張機能がこれを行うためのユースケースは2つあります。

  • カスタムトークンタイプとトークン修飾子を定義する拡張機能は、テーマが追加されたセマンティックトークンタイプや修飾子に対するテーマルールを定義していない場合のフォールバックとして TextMate スコープを提供します。

    {
      "contributes": {
        "semanticTokenScopes": [
          {
            "scopes": {
              "templateType": ["entity.name.type.template"]
            }
          }
        ]
      }
    }
    
  • TextMate 文法のプロバイダーは、言語固有のスコープを記述できます。これは、言語固有のテーマルールを含むテーマの場合に役立ちます。

    {
      "contributes": {
        "semanticTokenScopes": [
          {
            "language": "typescript",
            "scopes": {
              "property.readonly": ["variable.other.constant.property.ts"]
            }
          }
        ]
      }
    }
    

試してみる

セマンティックトークンプロバイダーの作成方法を示す セマンティックトークンのサンプル が用意されています。

スコープインスペクターツールを使用すると、ソースファイルにどのようなセマンティックトークンが存在し、どのテーマルールと一致するかを調べることができます。セマンティックトークンを確認するには、TypeScript ファイル上で組み込みテーマ(Dark+ など)を使用してください。

© . This site is unofficial and not affiliated with Microsoft.