
「VSCodeで、シンタックスハイライトを作りたい」
「シンタックスハイライトで、拡張機能を使いやすくしたい」
「設定できたけど、他のシンタックスハイライトを上書きしてしまう…」
シンタックスハイライトとは、あらかじめ指定された記号などを異なる色やスタイルで表示する機能のことです[1]。
VSCodeは拡張機能を作成できるため、「シンタックスハイライトを自作して使いやすくしたい」方もいらっしゃるでしょう。しかし拡張機能に直接実装しようとすると、実は他のシンタックスハイライトを上書きしてしまいます。
筆者はVSCode拡張機能の開発経験[2]があります。特にMarkdownに関する拡張機能が多く、%文字%{色}とするだけ色付きの生成できたり、:::note infoとすると注釈を作成できたりします。
より使いやすくするためにそれぞれの拡張機能でシンタックスハイライトを作成しましたが、その際に一方が他方を上書きする問題に遭遇しました。
そこで、この記事ではシンタックスハイライトが上書きされてしまう問題を解説した上で、初心者でも簡単にシンタックスハイライトを実装できる手順を紹介します。
具体的には拡張機能に直接実装するのではなく、自作テーマを用意しそこにシンタックスハイライトを追記していきます。
この記事を読むだけで、シンタックスハイライトを自由に追加作成できる環境を構築できます。どんなシンタックスハイライトでも追加できるようになるため、拡張機能がより使いやすくなるでしょう。
私が直面した問題への対処法を記事に凝縮しました。VSCodeでシンタックスハイライトを作成したい方は是非最後まで読んでください。
シンタックスハイライトの概要
シンタックスハイライトとは、特定の記号群やキーワードを任意の色やスタイルで表示する、エディタの文字表示に関する機能です[1:1]。
例えば、Markdown MojiColorは%文字%{色}と入力すると指定した色でレンダリングされる拡張機能ですが、Markdownファイル上では通常の文字同様「白」のままです。


シンタックスハイライトを適用すると、他の文字とは異なる色やスタイルを適用できます。%%{}の記号部分のみをオレンジにしてみましょう。


このようにシンタックスハイライトを活用すると、自作拡張機能をより使いやすくできます。
シンタックスハイライトの作成ステップ(記号の検出と色割り当て)
ではさっそくシンタックスハイライトを実装してみましょう。
- 拡張機能の作成
- 記号の検出
- 色の割当て
- 拡張機能の公開
拡張機能の作成
まずは、VSCode拡張機能を作成します。以下の記事を参照してください。


ステップ1.記号の検出
シンタックスハイライトを適用する文字を検出させます。
package.jsonの"contributes": {}の中に、"grammars": []を設定しましょう。
grammarsはファイルを参照するため、拡張機能にsyntaxes/任意の名前.tmLanguage.jsonを作成します。


任意の名前.tmLanguage.jsonは、TextMate形式のシンタックス定義ファイル(tmLanguage.json)です。
以下のような書き方で記号を検出させます。
// test.tmLanguage.json
{
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", // スキーマ(構造や型の定義)
"name": "test", // シンタックス定義ファイルの名前
"scopeName": "source.markdown", // 適用されるファイル種別
"patterns": [ // 適用されるルール
{
"include": "#markdown-mojicolor"
},
{
"include": "text.html.markdown"
}
],
"repository": { // ルールの倉庫
"markdown-mojicolor": {
"patterns": [
{
"begin": "(%)(.*?)(%)(\\{)",
"end": "\\}",
"beginCaptures": {
"1": { "name": "markdown-mojicolor.begin.markdown" },
"2": { "name": "markdown-mojicolor.color-text.markdown" },
"3": { "name": "markdown-mojicolor.end.markdown" },
"4": { "name": "markdown-mojicolor.bracket.begin.markdown" }
},
"endCaptures": {
"0": { "name": "markdown-mojicolor.bracket.end.markdown" }
}
}
]
}
}
}各項目の役割を詳しく解説します。
1. "$schema":
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json"このJSONファイルのスキーマ(構造や型の定義)を示します。 エディタの補完やバリデーションに使われますが、実行時には特に影響しません。
2. "name":
"name": "test"このシンタックス定義ファイルの名前です。エディタのUIなどで参照されることがあります。
3. "scopeName":
"scopeName": "source.markdown"この文法が適用されるファイル種別(スコープ名)です。ここではMarkdownファイル(source.markdown)に適用されます。
4. "patterns": []
"patterns": [
{
"include": "#markdown-mojicolor"
},
{
"include": "text.html.markdown"
}
]文法のトップレベルで適用するパターン(ルール)のリストです。
{"include": "#markdown-mojicolor"}"repository": {}内の"markdown-mojicolor": {}というルールを適用します。
{"include": "text.html.markdown"}- 既存のMarkdown文法(TextMateの標準スコープ)を取り込みます。
これにより、独自ルールと標準Markdownルールの両方が適用されます。
5. "repository": {}
"repository": {
"markdown-mojicolor": {
"patterns": [
{
"begin": "(%)(.*?)(%)(\\{)",
"end": "\\}",
"beginCaptures": {
"1": { "name": "markdown-mojicolor.begin.markdown" },
"2": { "name": "markdown-mojicolor.color-text.markdown" },
"3": { "name": "markdown-mojicolor.end.markdown" },
"4": { "name": "markdown-mojicolor.bracket.begin.markdown" }
},
"endCaptures": {
"0": { "name": "markdown-mojicolor.bracket.end.markdown" }
}
}
]
}
}複数のルール(パターン)を再利用・整理するための「ルールの倉庫」です。
"begin": "(%)(.*?)(%)(\{)"- この正規表現にマッチしたら「ここからハイライト開始」
- 例:
%文字%{
- 例:
- この正規表現にマッチしたら「ここからハイライト開始」
"end": "\}"- この正規表現にマッチしたら「ここでハイライト終了」
- 例:
}
- 例:
- この正規表現にマッチしたら「ここでハイライト終了」
"beginCaptures": {}"1": { "name": "markdown-mojicolor.begin.markdown" }- 最初の
%にこのスコープを付与
- 最初の
"2": { "name": "markdown-mojicolor.color-text.markdown" }%と%の間の文字列(色名など)にこのスコープを付与
"3": { "name": "markdown-mojicolor.end.markdown" }- 2つ目の
%にこのスコープを付与
- 2つ目の
"4": { "name": "markdown-mojicolor.bracket.begin.markdown" }{にこのスコープを付与
"endCaptures": {}"0": { "name": "markdown-mojicolor.bracket.end.markdown" }- 終了の
}にこのスコープを付与
- 終了の
このようにtmLanguage.jsonは、Markdownファイル内で%文字%{色名}のような独自記法を認識し、各部分に独自のスコープ名を割り当てます。
これでシンタックスハイライトが適用される文字が検出されました。
ステップ2.色の割り当て
ステップ1 で検出した文字に独自の色やスタイルを割り当てます。
package.jsonの"contributes": {}の中に、"themes": []を設定しましょう。themesもまたファイルを参照するため、拡張機能にthemes/任意の名前-color-theme.jsonを作成します。


任意の名前-color-theme.jsonは、Visual Studio Code用のカラーテーマファイルです。
ステップ1で検出した特定のTextMateスコープに対して、シンタックスハイライトの色やスタイルを設定する役割を持ちます。今回は各記号をオレンジにしましょう。
// 任意の名前-color-theme.json
{
"tokenColors": [ // カラーテーマの中核となる配列
{
"scope": "markdown-mojicolor.begin.markdown, markdown-mojicolor.end.markdown, markdown-mojicolor.bracket.begin.markdown, markdown-mojicolor.bracket.end.markdown", // 色を適用したいTextMateスコープ名をカンマ区切りで指定
"settings": { // スコープに適用する色や装飾を指定
"foreground": "#F57900"
}
}
]
}各項目の役割を解説します。
"tokenColors": [{}]- カラーテーマの中核となる配列です。
- ここに、どのスコープ(構文要素)にどんな色やスタイルを適用するかを定義します。
"scope":- 色を適用したいTextMateスコープ名をカンマ区切りで指定します。
- ここでは、
markdown-mojicolor.begin.markdown、markdown-mojicolor.end.markdown、markdown-mojicolor.bracket.begin.markdown、markdown-mojicolor.bracket.end.markdownの4つのスコープに対して色を指定しています。 - これらのスコープは、独自のTextMate文法(test.tmLanguage.json)で設定したものです。
"settings": {}- スコープに適用する色や装飾を指定します。
foregroundは文字色を表します。ここでは#F57900(オレンジ系)を指定しています。
このテーマファイルをVSCodeが読み込むことで、指定したスコープの文字色が自動的に#F57900で表示されます。検出した文字に独自の色が適用されるでしょう。
拡張機能の公開
最後に、拡張機能を公開しましょう。公開された拡張機能をインストールすると、シンタックスハイライトが適用されます。
拡張機能の公開方法は以下をご参照ください。


拡張機能をインストールしたあとに、テーマを変更します。今回は「test」という名前のテーマなので、「設定 → テーマ → 配色テーマ → test」を選びましょう。


シンタックスハイライトが適用され、%%{}がオレンジになりました。
シンタックスハイライトの競合問題


package.jsonの"contributes": {}の中に"grammars": []と"themes": []を設定し、syntaxes/任意の名前.tmLanguage.jsonとthemes/任意の名前-color-theme.jsonを作成すると、シンタックスハイライトが適用されます。
しかし、実はこのままだと既存のシンタックスハイライトを上書きしてしまいます。なぜなら、VSCodeの仕組み上、1つの言語に同時に複数のgrammarを適用することはできない からです。
// package.json
"contributes": {
"grammars": [
{
"language": "markdown", // Markdownひとつに一つのgrammarしか適用できない
"scopeName": "source.markdown",
"path": "./syntaxes/test.tmLanguage.json"
}
],
}そのため、「自作の拡張機能を使いやすくしよう!」と善意でシンタックスハイライトを実装すると、思わぬトラブルを引き起こすでしょう。
拡張機能ごとのシンタックスハイライトを同時に適用する方法
シンタックスハイライトの上書き問題は、テーマを作成し、そこにシンタックスハイライトを追記する形で回避できるでしょう。
VSCodeは拡張機能だけでなく、テーマも作成できます。yo codeを実行したあとに「New Color Theme」を選びましょう。中身は通常の拡張機能よりシンプルです。


先程と同様、package.jsonの"contributes": {}の中に"grammars": []と"themes": []を設定し、syntaxes/任意の名前.tmLanguage.jsonとthemes/任意の名前-color-theme.jsonを作成します。
そして、ひとつのgrammarに全ての拡張機能のパターンを書き込みます。
// 任意の名前.tmLanguage.json
{
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": "test",
"scopeName": "source.markdown",
"patterns": [
{
"include": "#markdown-info" // 拡張機能「Markdown Info」のシンタックスハイライト
},
{
"include": "#markdown-mojicolor" // 拡張機能「Markdown MojiColor」 のシンタックスハイライト
},
{
"include": "text.html.markdown" // 既存のMarkdownのシンタックスハイライトをそのまま取り込む
}
],
"repository": {
"markdown-info": {
"patterns": [
{
"name": "markdown-info.info.markdown",
"begin": "^:::(note|message) info",
"end": "^:::$",
"patterns": [
{
"include": "$self"
}
]
},{
"name": "markdown-info.warn.markdown",
"begin": "^:::(note|message) warn",
"end": "^:::$",
"patterns": [
{
"include": "$self"
}
]
},{
"name": "markdown-info.alert.markdown",
"begin": "^:::(note|message) alert",
"end": "^:::$",
"patterns": [
{
"include": "$self"
}
]
},{
"name": "markdown-info.question.markdown",
"begin": "^:::(note|message) question",
"end": "^:::$",
"patterns": [
{
"include": "$self"
}
]
}
]
},
"markdown-mojicolor": {
"patterns": [
{
"begin": "(%)(.*?)(%)(\\{)",
"end": "\\}",
"beginCaptures": {
"1": { "name": "markdown-mojicolor.begin.markdown" },
"2": { "name": "markdown-mojicolor.color-text.markdown" },
"3": { "name": "markdown-mojicolor.end.markdown" },
"4": { "name": "markdown-mojicolor.bracket.begin.markdown" }
},
"endCaptures": {
"0": { "name": "markdown-mojicolor.bracket.end.markdown" }
}
}
]
}
}
}"patterns": []を見れば、拡張機能ごとにパターンを取り込んでいることが分かります。text.html.markdownを読み込むと既存のMarkdownのシンタックスハイライトをそのまま取り込むため、忘れずに書き込みましょう。
新しい拡張機能をインストールしたり自作したりした際に、この自作テーマに書き込むことでシンタックスハイライトを追記できます。これで、シンタックスハイライトを自由に追加作成できる環境を構築できました。
まとめ
この記事では、VSCodeでシンタックスハイライトを自作する方法についてまとめました。VSCodeで独自のシンタックスハイライトを作成したい場合、他のシンタックスハイライトを上書きしてしまう問題について考慮しましょう。
VSCodeでシンタックスハイライトをより自由にカスタマイズ・追加したい方は、今回紹介した自作テーマを活用した方法をぜひ試してみてください。