Prismはそのまま使っても素晴らしいですが、ニーズに合わせてカスタマイズするとさらに素晴らしくなります。このセクションでは、新しい言語定義、プラグイン、そしてPrismのハッキング全般について説明します。
すべての言語はトークンの集合として定義され、トークンは正規表現として表現されます。たとえば、これはJSONの言語定義です。
コアな部分では、言語定義は単なるJavaScriptオブジェクトであり、トークンは言語定義のエントリにすぎません。最も単純な言語定義は空のオブジェクトです。
Prism.languages['some-language'] = { };
残念ながら、空の言語定義はあまり役に立たないので、トークンを追加してみましょう。トークンを表現する最も簡単な方法は、正規表現リテラルを使用することです。
Prism.languages['some-language'] = {
'token-name': /regex/,
};
または、オブジェクトリテラルも使用できます。この表記では、トークンを記述する正規表現がオブジェクトのpattern
プロパティになります。
Prism.languages['some-language'] = {
'token-name': {
pattern: /regex/
},
};
これまでのところ、機能は正規表現とオブジェクト表記の間でまったく同じです。ただし、オブジェクト表記では追加のオプションが可能です。これについては後で詳しく説明します。
トークンの名前は、理論的には有効なCSSクラスでもある任意の文字列にできますが、従うべきガイドラインがいくつかあります。これについては後で詳しく説明します。
言語定義には任意の数のトークンを含めることができますが、各トークンの名前は一意である必要があります。
Prism.languages['some-language'] = {
'token-1': /I love regexes!/,
'token-2': /regex/,
};
Prismは、入力テキストに対して、トークンを順番にマッチングさせ、トークンは以前のトークンの一致と重複することはできません。したがって、上記の例では、token-2
は、token-1
の一致の中のサブストリング"regex"と一致しません。 Prismのマッチングアルゴリズムの詳細については後で説明します。
最後に、多くの言語では、同じ構文(コメント、文字列など)を宣言する方法が複数あり、場合によっては、それらすべてを1つの正規表現でマッチングするのが困難または非現実的な場合があります。1つのトークン名に複数の正規表現を追加するには、配列を使用できます。
Prism.languages['some-language'] = {
'token-name': [
/regex 1/,
/regex 2/,
{ pattern: /regex 3/ }
],
};
注:配列はpattern
プロパティでは使用できません。
単なる正規表現を使用する代わりに、Prismはトークンのオブジェクト表記もサポートしています。この表記では、次のオプションが有効になります。
pattern: RegExp
これは唯一の必須オプションです。トークンの正規表現を保持します。
lookbehind: boolean
このオプションは、JavaScriptの先読みに対するブラウザのサポートが不十分なことを緩和します。true
に設定すると、このトークンをマッチングする際にpattern
正規表現の最初のキャプチャグループが破棄されるため、事実上、先読みとして機能します。
この例として、Cライクな言語定義でclass-name
トークンが見つかる方法を確認してください。
Prism.languages.clike = {
// ...
'class-name': {
pattern: /(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+)\w+/i,
lookbehind: true
}
};
greedy: boolean
このオプションは、トークンの貪欲マッチングを有効にします。詳細については、マッチングアルゴリズムに関するセクションを参照してください。
alias: string | string[]
このオプションは、トークンの1つ以上のエイリアスを定義するために使用できます。その結果、トークン名とエイリアスのスタイルが組み合わされます。これは、ほとんどのテーマで既にサポートされている標準トークンのスタイルを、より正確なトークン名と組み合わせるのに役立ちます。このトピックの詳細については、粒度の高いハイライトを参照してください。
たとえば、トークン名latex-equation
はほとんどのテーマでサポートされていませんが、次の例では文字列と同じようにハイライトされます。
Prism.languages.latex = {
// ...
'latex-equation': {
pattern: /\$.*?\$/,
alias: 'string'
}
};
inside: Grammar
このオプションは、このトークン内でネストできるトークンを持つ別のオブジェクトリテラルを受け入れます。inside
文法のすべてのトークンは、このトークンによってカプセル化されます。これにより、特定の言語を簡単に定義できます。
ネストされたトークンの例として、CSS言語定義のurl
トークンを確認してください。
Prism.languages.css = {
// ...
'url': {
// e.g. url(https://example.com)
pattern: /\burl\(.*?\)/i,
inside: {
'function': /^url/i,
'punctuation': /^\(|\)$/
}
}
};
inside
オプションは、再帰的な言語を作成するためにも使用できます。これは、1つのトークンが任意の式を含めることができる言語(例:文字列補間構文を持つ言語)に役立ちます。
たとえば、JavaScriptがテンプレート文字列補間を実装する方法を次に示します。
Prism.languages.javascript = {
// ...
'template-string': {
pattern: /`(?:\\.|\$\{[^{}]*\}|(?!\$\{)[^\\`])*`/,
inside: {
'interpolation': {
pattern: /\$\{[^{}]*\}/,
inside: {
'punctuation': /^\$\{|\}$/,
'expression': {
pattern: /[\s\S]+/,
inside: null // see below
}
}
}
}
}
};
Prism.languages.javascript['template-string'].inside['interpolation'].inside['expression'].inside = Prism.languages.javascript;
再帰的な文法を作成するときは、無限再帰につながり、スタックオーバーフローが発生する可能性があるため、注意してください。
トークンの名前は、トークンのマッチしたテキストの意味的な意味を決定します。トークンは、コメントのような単純な言語構文から、テンプレート文字列補間式のようなより複雑な構文まで、あらゆるものをキャプチャできます。トークン名は、これらの言語構文を区別します。
トークン名は、理論的には有効なCSSクラス名である任意の文字列にできます。ただし、実際には、トークン名がいくつかの規則に従うことは理にかなっています。Prismのコードでは、すべてのトークン名がケバブケース(foo-bar
)を使用し、小文字のASCII文字、数字、およびハイフン文字のみを含むことを強制しています。たとえば、class-name
は許可されますが、Class_name
は許可されません。
Prismは、ほとんどのトークンに使用する必要がある標準トークン名も定義しています。
Prismのテーマは、トークン名(およびエイリアス)に基づいて、トークンに色(およびその他のスタイル)を割り当てます。つまり、言語定義はトークンの色を制御せず、テーマが制御します。
ただし、テーマは、既知のトークン名の限られた数のみをサポートしています。テーマが特定のトークン名を認識しない場合、スタイルは適用されません。テーマによってサポートされるトークン名は異なる場合がありますが、すべてのテーマがPrismの標準トークンをサポートすることが保証されています。標準トークンは、特定の意味を持つ特別なトークン名です。それらは、すべての言語定義とテーマが合意し、従う必要のある共通の基盤です。トークン名を選択する場合は、標準トークンを優先する必要があります。
標準トークンを優先する必要がありますが、それらは非常に一般的でもあります。これらは、多数のさまざまな言語に適用する必要があるため、意図的に設計されていますが、よりきめ細かいトークン化(およびその後のハイライト)が望ましい場合があります。
粒度の高いハイライトは、すべてのテーマとの互換性を確保しながら、テーマの細かい制御を可能にするトークン名を選択する方法です。
例を見てみましょう。10進数と2進数の両方のリテラルをサポートする言語があり、2進数に特別なハイライトを付けたいとします。次のように実装できます。
Prism.languages['my-language'] = {
// ...
'number': /\b\d+(?:\.\d+)?\b/,
'binary-number': /\b0b[01]+\b/,
};
しかし、これには問題があります。binary-number
は標準トークンではないため、ほとんどのテーマは2進数に色を付けません。
この問題の解決策は、エイリアスを使用することです。
Prism.languages['my-language'] = {
// ...
'number': /\b\d+(?:\.\d+)?\b/,
'binary-number': {
pattern: /\b0b[01]+\b/,
alias: 'number'
},
};
エイリアスを使用すると、テーマは複数の名前のスタイルを1つのトークンに適用できます。これは、binary-number
トークン名をサポートするテーマは特別な色を割り当てることができ、それをサポートしないテーマは、通常の数値の色にフォールバックすることを意味します。
これが粒度の高いハイライトです。非標準トークン名と標準トークンをエイリアスとして使用します。
Prismのマッチングアルゴリズムの役割は、言語定義とテキストに基づいてトークンストリームを生成することです。トークンストリームは、Prismの(部分的または完全に)トークン化されたテキストの表現であり、文字列(リテラルテキストを表す)とトークン(トークン化されたテキストを表す)のリストとして実装されます。
注:ここで、「トークン」という言葉はあいまいです。「トークン」は、言語定義のエントリ(上記のセクションで説明したとおり)とトークンストリーム内のトークンオブジェクトの両方を指すために使用します。どのタイプの「トークン」を意味するかは、コンテキストから推測できます。
このセクションでは、簡略化されたトークンストリーム表記を使用します。簡単に言うと、表記はJSONを使用してトークンストリームを表します。たとえば、["foo ", ["keyword", "bar"], " baz"]
は、文字列foo
で始まり、タイプkeyword
でテキストbar
のトークンが続き、文字列 baz
で終わるトークンストリームの簡略化されたトークンストリーム表記です。
マッチングアルゴリズムに戻りましょう。Prismのマッチングアルゴリズムは、先着順(FCFS)マッチングと貪欲マッチングの2つのモードを持つハイブリッドです。
これはPrismのデフォルトのマッチングモードです。すべてのトークンは順番にマッチングされ、トークンは重複できず、トークンは以前のトークンによってすでにマッチングされたテキストとマッチングできません。
アルゴリズム自体は非常に単純です。JSコードmax(3, 5, exp2(7));
をトークン化したいとして、関数トークンがすでに処理されているとします。現在のトークンストリームは次のようになります。
[
["function", "max"],
"(3, 5, ",
["function", "exp2"],
"(7));"
]
次に、トークン'number': /[0-9]+/
を使用して数値をトークン化します。
FCFSマッチングは、現在のトークンストリーム内のすべての文字列を調べて、数値正規表現の一致を見つけます。最初の文字列は"(3, 5, "
なので、一致3
が見つかります。3
の新しいトークンが作成され、一致するテキストを置き換えるためにトークンストリームに挿入されます。トークンストリームは次のようになります。
[
["function", "max"],
"(",
["number", "3"],
", 5, ",
["function", "exp2"],
"(7));"
]
次に、アルゴリズムは次の文字列", 5, "
に進み、別のマッチを見つけます。5
の新しいトークンが作成され、トークンストリームは次のようになります。
[
["function", "max"],
"(",
["number", "3"],
", ",
["number", "5"],
", ",
["function", "exp2"],
"(7));"
]
次の文字列は", "
であり、一致は見つかりません。その後の文字列は"(7));"
であり、7
の新しいトークンが作成されます。
[
["function", "max"],
"(",
["number", "3"],
", ",
["number", "5"],
", ",
["function", "exp2"],
"(",
["number", "7"],
"));"
]
最後にチェックする文字列は"));"
であり、一致は見つかりません。数値トークンの処理が完了し、アルゴリズムは言語定義の次のトークンの処理に進みます。
FCFSマッチングがexp2
の2
を見つけられなかったことに注意してください。FCFSマッチングはトークンストリーム内の既存のトークンを完全に無視するため、数値正規表現はすでにトークン化されたテキストを表示できません。これは非常に便利なプロパティです。上記の例では、2
は関数名exp2
の一部であるため、それを数値としてハイライトするのは正しくありません。
貪欲マッチングはFCFSマッチングと非常によく似ています。すべてのトークンは順番にマッチングされ、トークンは重複できません。決定的な違いは、貪欲なトークンが前のトークンのテキストと一致できることです。
貪欲マッチングがなぜ便利で、どのように概念的に機能するかを理解するために、例を見てみましょう。非常に簡略化されたJavaScriptのコメントと文字列の構文は、次のように実装できます。
Prism.languages.javascript = {
'comment': /\/\/.*/,
'string': /'(?:\\.|[^\\\r\n])*'/
};
貪欲マッチングがなぜ便利かを理解するために、FCFSマッチングがテキスト'http://example.com'
をトークン化する方法を見てみましょう。
FCFSマッチングはトークンストリーム["'http://example.com'"]
から始まり、'comment': /\/\/.*/
の一致を見つけようとします。一致//example.com'
が見つかり、トークンストリームに挿入されます。
[
"'http:",
["comment", "//example.com'"]
]
次に、FCFSマッチングは、'string': /'(?:\\.|[^'\\\r\n])*'/
に一致するものを検索します。トークンストリームの最初の文字列 "'http:"
は、文字列の正規表現に一致しないため、トークンストリームは変更されません。文字列トークンの処理が完了し、上記のトークンストリームが最終結果となります。
明らかに、これは問題です。コード 'http://example.com'
は、URLを含む単なる文字列ですが、FCFSマッチングはこれを理解しません。
明白ですが、誤った修正は、comment
と string
の順序を入れ替えることかもしれません。これで 'http://example.com'
は修正されます。しかし、問題は単に移動しただけです。// it's my co-worker's code
のようなコメント(単一引用符が2つあることに注意)は、トークン化が正しく行われなくなります。
これは、貪欲マッチングが解決する問題です。トークンを貪欲にし、これが結果にどのように影響するかを見てみましょう。
Prism.languages.javascript = {
'comment': {
pattern: /\/\/.*/,
greedy: true
},
'string': {
pattern: /'(?:\\.|[^'\\\r\n])*'/,
greedy: true
}
};
実際の貪欲マッチングアルゴリズムは非常に複雑で、微妙なエッジケースが散りばめられていますが、その効果は非常にシンプルです。貪欲なトークンのリストは、単一の正規表現によってマッチングされたかのように動作します。これが貪欲マッチングが概念的にどのように機能し、貪欲なトークンについてどのように考えるべきかです。
これは、貪欲なコメントトークンと文字列トークンが、次の言語定義のように動作することを意味しますが、結合されたトークンは元の貪欲なトークンの正しいトークン名を生成します。
Prism.languages.javascript = {
'comment-or-string': /\/\/.*|'(?:\\.|[^'\\\r\n])*'/
};
上記の例では、'http://example.com'
は /\/\/.*|'(?:\\.|[^'\\\r\n])*'/
によって完全にマッチングされます。正規表現の '(?:\\.|[^'\\\r\n])*'
部分がマッチングを引き起こしたため、string
型のトークンが作成され、次のトークンストリームが生成されます。
[
["string", "'http://example.com'"]
]
同様に、// it's my co-worker's code
の例でも、トークン化は正しく行われます。
トークンを貪欲にするかどうかを決定する際には、以下のガイドラインを使用してください。
ほとんどのトークンは貪欲ではありません。
ほとんどの言語のほとんどのトークンは貪欲である必要がないため、貪欲ではありません。通常、コメント、文字列、正規表現リテラルのトークンのみが貪欲である必要があります。他のすべてのトークンはFCFSマッチングを使用できます。
一般的に、トークンは別のトークンの開始部分を含む可能性がある場合にのみ貪欲である必要があります。
貪欲なトークンより前のすべてのトークンも貪欲である必要があります。
貪欲なトークンの前に貪欲でないトークンがある場合、貪欲マッチングの動作はわずかに異なります。これは通常、発見が難しい微妙なバグにつながり、発見に数年かかることもあります。
貪欲マッチングが期待どおりに機能するように、貪欲なトークンは言語の最初のトークンである必要があります。
貪欲なトークンはグループで現れます。
言語定義に単一の貪欲なトークンのみが含まれている場合、その貪欲なトークンは貪欲であるべきではありません。上記で説明したように、貪欲マッチングは概念的にすべての貪欲なトークンの正規表現を1つに結合します。貪欲なトークンが1つしかない場合、貪欲マッチングはFCFSマッチングのように動作します。
Prismは、言語定義の作成と変更に役立ついくつかの便利な関数も提供しています。Prism.languages.insertBefore
は既存の言語定義を変更するために使用できます。Prism.languages.extend
は、言語が既存の別の言語に非常によく似ている場合に役立ちます。
言語定義の rest
プロパティは特別です。Prismは、このプロパティがトークンの代わりに別の言語定義であることを期待します。rest
プロパティ内の文法のトークンは、rest
プロパティを持つ言語定義の末尾に追加されます。これは、組み込みのオブジェクトスプレッド演算子と考えることができます。
これは、他の場所で定義されたトークンを参照するのに役立ちます。ただし、rest
プロパティは控えめに使用する必要があります。別の言語を参照する場合は、通常、言語のテキストをトークンにカプセル化し、代わりにinside
プロパティを使用する方が適切です。
このセクションでは、新しい言語定義を作成する通常のワークフローについて説明します。
例として、架空のFoo's Binary, Artistic Robots™言語、略してFoo Barの言語定義を作成します。
新しいファイル components/prism-foo-bar.js
を作成します。
この例では、新しい言語のIDとして foo-bar
を選択します。言語IDは一意である必要があり、Prismが言語定義を参照するために使用する language-xxxx
CSSクラス名とうまく連携する必要があります。言語IDは、理想的には正規表現 /^[a-z][a-z\d]*(?:-[a-z][a-z\d]*)*$/
に一致する必要があります。
components.json
を編集し、languages
オブジェクトに追加して新しい言語を登録します。(すべての言語エントリは、タイトルでアルファベット順にソートされていることに注意してください。)
この例の新しいエントリは次のようになります。
"foo-bar": {
"title": "Foo Bar",
"owner": "Your GitHub name"
}
言語定義が他の言語に依存する場合は、ここで "require"
プロパティを追加して指定する必要があります。例:"require": "clike"
、または "require": ["markup", "css"]
。依存関係の詳細については、依存関係の宣言セクションをお読みください。
注: components.json
に行った変更は、再構築が必要です(ステップ3を参照)。
npm run build
を実行してPrismを再構築します。
これにより、テストページ、より正確にはローカルバージョンで言語を使用できるようになります。ローカルの test.html
ページを任意のブラウザで開き、言語を選択して、入力したコードを言語定義がどのように強調表示するかを確認できます。
注: prism-foo-bar.js
に行った変更を適用するにはテストページをリロードする必要がありますが、Prism自体を再構築する必要はありません。ただし、components.json
を変更した場合(依存関係を追加したなど)、これらの変更はPrismを再構築するまでテストページに表示されません。
言語定義を作成します。
上記のセクションで、言語定義の構成について説明しました。
エイリアスの追加。
エイリアスは、言語が複数の名前で知られている場合や、言語の非常に一般的な略語(JavaScriptのJSなど)がある場合に役立ちます。エイリアスは、言語IDと同様に、一意である必要があり(つまり、別の言語IDまたはエイリアスと同じエイリアスは存在できません)、CSSクラス名として機能することに留意してください。
この例では、Foo Barコードが .foo
ファイルに保存されているため、foo-bar
のエイリアス foo
を登録します。
エイリアスを追加するには、prism-foo-bar.js
の最後に次の行を追加します。
Prism.languages.foo = Prism.languages['foo-bar'];
エイリアスは、components.json
で、言語エントリに alias
プロパティを追加することによって登録する必要があります。この例では、更新されたエントリは次のようになります。
"foo-bar": {
"title": "Foo Bar",
"alias": "foo",
"owner": "Your GitHub name"
}
注: 複数のエイリアスを登録する必要がある場合は、alias
を文字列配列にすることもできます。
aliasTitles
を使用すると、エイリアスに特定のタイトルを付けることもできます。この例では、これは必要ありませんが、これが役立つ良い例は、マークアップ言語です。
"markup": {
"title": "Markup",
"alias": ["html", "xml", "svg", "mathml"],
"aliasTitles": {
"html": "HTML",
"xml": "XML",
"svg": "SVG",
"mathml": "MathML"
},
"option": "default"
}
テストの追加。
tests/languages/foo-bar/
フォルダを作成します。ここにテストファイルが置かれます。テスト形式とテストの実行方法については、こちらで説明されています。
言語の主要な機能ごとにテストを追加する必要があります。テストファイルは、一般的なケースと特定のエッジケース(存在する場合)をテストする必要があります。JavaScript言語のテストは良い例です。
新しい .test
ファイルには、このテンプレートを使用できます。
The code to test.
----------------------------------------------------
----------------------------------------------------
Brief description.
テストファイルごとに
テストするコードと簡単な説明を追加します。
言語定義がテストコードを正しく強調表示することを確認します。これは、ローカルバージョンのテストページを使用して行うことができます。
注:Show tokensオプションを使用すると、言語定義によって作成されたトークンストリームが表示されます。
テストケースが正しく処理されていることを慎重に確認したら(つまり、テストページを使用して)、次のコマンドを実行します。
npm run test:languages -- --language=foo-bar --accept
このコマンドは、言語定義が現在生成しているトークンストリームを取得し、テストファイルに挿入します。コードとテストケースの説明を区切る2行の間の空白は、トークンストリームの簡略化されたバージョンに置き換えられます。
挿入されたトークンストリームJSONが期待どおりであることを慎重に確認してください。
npm run test:languages -- --language=foo-bar
を再実行して、テストに合格することを確認します。サンプルページの追加。
新しいファイル examples/prism-foo-bar.html
を作成します。これが、サンプルマークアップを含むテンプレートになります。これらのファイルの構造を確認するには、他の例を参照してください。
例として何がカウントされるかに関するルールはないため、言語の主要な機能の強調表示を示す単一のフルサンプルセクションで十分です。
npm test
を実行して、言語テストだけでなく、すべてのテストに合格することを確認します。
これは通常、問題なく合格します。すべてのテストに合格できない場合は、このステップをスキップしてください。
npm run build
を再度実行します。
言語定義の準備ができました!
言語とプラグインは相互に依存する可能性があるため、Prismには依存関係を宣言および解決するための独自の依存関係システムがあります。
依存関係を宣言するには、components.json
ファイルで、言語またはプラグインのエントリにプロパティを追加します。プロパティの名前は依存関係の種類になり、その値は依存先のコンポーネントIDになります。複数の言語またはプラグインが依存している場合は、コンポーネントIDの配列を宣言することもできます。
次の例では、require
依存関係の種類を使用して、架空の言語FooがJavaScript言語に依存し、別の架空の言語BarがJavaScriptとCSSの両方に依存することを宣言します。
{
"languages": {
"javascript": { "title": "JavaScript" },
"css": { "title": "CSS" },
...,
"foo": {
"title": "Foo",
"require": "javascript"
},
"bar": {
"title": "Bar",
"require": ["css", "javascript"]
}
}
}
依存関係には3種類あります。
require
modify
としても宣言されていない限り、依存先を変更することは許可されていません。この種の依存関係は、別の言語を拡張したり、組み込み言語として依存したりする場合(たとえば、PHPがHTMLに埋め込まれている場合)に最も役立ちます。
optional
require
依存関係とは異なり、optional
依存関係は、ロードされたコンポーネントの順序のみを保証します。modify
として宣言してください。この種の依存関係は、埋め込み言語がある場合に便利ですが、ユーザーに埋め込み言語を含めるかどうかを選択させたい場合に役立ちます。optional
依存関係を使用することで、ユーザーは必要な言語のみを含めることで、Prismのバンドルサイズをより適切に制御できます。
たとえば、HTTPはJSONとXMLペイロードを強調表示できますが、ユーザーにこれらの言語を含めることを強制しません。
modify
optional
依存関係であり、依存元が依存先を変更する可能性があることも宣言します。この種の依存関係は、言語が別の言語を変更する場合(たとえば、トークンを追加する場合)に役立ちます。
たとえば、CSS ExtrasはCSS言語に新しいトークンを追加します。
さまざまな依存関係の種類のプロパティをまとめると、次のようになります。
非オプション | オプション | |
---|---|---|
読み取り専用 | require |
optional |
変更可能 | modify |
注:コンポーネントを require
と modify
の両方として宣言できます。
コンポーネントの依存関係は実装の詳細と見なしているため、リリースごとに変更される可能性があります。Prismは通常、依存関係を自動的に解決します。したがって、バンドルをダウンロードするか、NodeJS、AutoLoader、またはBabelプラグインで loadLanguages
関数を使用する場合、依存関係のロードについて心配する必要はありません。
依存関係を手動で解決する必要がある場合は、dependencies.js
によってエクスポートされる getLoader
関数を使用してください。例:
const getLoader = require('prismjs/dependencies');
const components = require('prismjs/components');
const componentsToLoad = ['markup', 'css', 'php'];
const loadedComponents = ['clike', 'javascript'];
const loader = getLoader(components, componentsToLoad, loadedComponents);
loader.load(id => {
require(`prismjs/components/prism-${id}.min.js`);
});
getLoader
API の詳細については、インラインドキュメントを参照してください。
Prism のプラグインアーキテクチャは非常にシンプルです。コールバックを追加するには、Prism.hooks.add(hookname, callback)
を使用します。hookname
は、コードが実行されるフックを一意に識別するフック ID を持つ文字列です。callback
は、JavaScript ではオブジェクトが参照渡しされるため、変更可能なさまざまな変数を持つオブジェクトを 1 つのパラメータとして受け取る関数です。たとえば、以下はマークアップ言語定義のプラグインで、エンティティトークンにエンコードされた実際の文字を示すツールチップを追加するものです。
Prism.hooks.add('wrap', function(env) {
if (env.token === 'entity') {
env.attributes['title'] = env.content.replace(/&/, '&');
}
});
もちろん、どのフックを使用するかを理解するには、Prism のソースコードを読む必要があります。どこにコードを追加するかを想像し、適切なフックを見つけてください。使用できるフックがない場合は、追加をリクエストし、なぜそこにそれが必要なのかを詳しく説明してください。