vscodeで自作のシンタックスハイライト・スニペット拡張機能を作る

# vscodeで自作のシンタックスハイライト・スニペット拡張機能を作る

ティラノスクリプトというエンジンを使うにあたって
vscode用の拡張機能が存在していませんでしたので
ハイライトとスニペットのみの簡素なものですが作ってみました。

# やること
* vscodeで独自の拡張機能プロジェクトを作る
* 拡張機能として自作のハイライト、スニペットを作る
* 作った拡張機能を公開する

## 各種ツールのインストール

nodejsインストール前提です。

```shell
npm install -g yo generator-code #vscodeの雛形インストール
npm install -g vsce #拡張機能のインストール、公開時に必要なツールのインストール
```

## 雛形の生成
  **yo codeコマンドを実行したディレクトリ**にプロジェクトが生成されます。

```shell
yo code#雛形生成コマンド
```

対話形式での質問が出るのでY もしくはNを選択

We're constantly looking for ways to make yo better!
May we anonymously report usage statistics to improve the tool over time?
More info: https://github.com/yeoman/insight & http://yeoman.io
（私たちは常にあなたをより良くする方法を探しています！
時間の経過とともにツールを改善するために、使用統計を匿名で報告できますか？
詳細：https：//github.com/yeoman/insight＆http：//yeoman.io）

```shell
? What type of extension do you want to create?
  New Extension (TypeScript)
  New Extension (JavaScript)
  New Color Theme
> New Language Support
  New Code Snippets
  New Keymap
  New Extension Pack
  New Language Pack (Localization)
```

今回はティラノスクリプトの言語パックを作るので「New Language Support」を選択します。

Enter the URL (http, https) or the file path of the tmLanguage grammar or press ENTER to start with a new grammar.
(tmLanguage文法のURL（http、https）またはファイルパスを入力するか、Enterキーを押して新しい文法を開始します。)

? URL or file to import, or none for new: ()
(？インポートするURLまたはファイル、または新規の場合はなし:())
>(なし)

? What's the name of your extension? ()
(拡張機能の名前は？)
>TyranoScript Syntax

? What's the identifier of your extension? (tyranoscript-syntax)
(？あなたの拡張機能の識別子は何ですか？ )
拡張機能の検索で出る名前です。
>tyranosyntax


? What's the description of your extension? ()
(？拡張機能の説明はなんですか？)
>Provides TyranoScript Adventure Game syntax for Visual Studio Code

Enter the id of the language. The id is an identifier and is single, lower-case name such as 'php', 'javascript'
(Enter the id of the language. The id is an identifier and is single, lower-case name such as 'php', 'javascript')
>tyrano

Enter the name of the language. The name will be shown in the VS Code editor mode selector.
(言語の名前を入力します。名前はVSCodeエディターモードセレクターに表示されます。)
>tyranoscript


Enter the file extensions of the language. Use commas to separate multiple entries (e.g. .ruby, .rb)
? File extensions: ()
言語のファイル拡張子を入力します。カンマを使用して複数のエントリを区切ります（例：.ruby、.rb）
？ファイル拡張子:（）
>.ks


Enter the root scope name of the grammar (e.g. source.ruby)
? Scope names: ()
文法のルートスコープ名を入力します（例：source.ruby）
？スコープ名:（）
>source.ks

## シンタックスハイライトの作成

雛形プロジェクトができたら、
./IDENTIFER/LANGUAGE_NAME.tmLanguage.jsonを修正します。

### tmlanguageの修正


textmate形式と呼ばれるものです。

最低限、以下の３つを覚えておきます。
1. nameの名前によって色が変わる(名前一覧は、[2]の命名規則や、https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.jsonを参照)
2. matchに正規表現を定義
3. もしくはbeginとendで複数行の正規表現を定義


参考URL 

* https://qiita.com/maxfie1d/items/51af2984b7a628c41a94
* https://macromates.com/manual/ja/regular_expressions
* https://macromates.com/manual/en/language_grammars

### 色の変更

場合によっては、tmlanguageファイルで設定してもハイライトされないものもあります。
その場合は、ハイライト設定はされてても、肝心の色が設定されていない可能性があります。
setting.jsonに以下の設定を追加して対処しましょう。

```json
"editor.tokenColorCustomizations":{
	"keywords": "#FF0000",
	"textMateRules": [
		{
			"scope": "keyword.operator",
			"settings": {
				"foreground": "#f3b8b8"
			}
		},
		{
			"scope": "keyword.other",
			"settings": {
				"foreground": "#fce770"
			}
		}
	]
}
```
ここまで終われば、以下のように単語がハイライトされます。
![tyranosyntaxスクショ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/728667/a7cf8b6b-73bf-bc16-1380-42fb9efd11e7.png)

## スニペットを作る

package.jsonに、以下のようにスニペットを読み込む設定を追加します。

```json:package.json
    "contributes": {
        "languages": [{
            "id": "tyrano",
            "aliases": ["tyranoscript", "tyrano"],
            "extensions": [".ks"],
            "configuration": "./language-configuration.json"
        }],
        "grammars": [{
            "language": "tyrano",
            "scopeName": "source.ks",
            "path": "./syntaxes/tyrano.tmLanguage.json"
        }],
		"snippets": [
			{
				"language": "tyrano",
				"scopeName":"source.ks",
				"path": "./snippet/tyrano.snippet.json"
			}
		]
    }
```

追加したらpathで指定したファイルを修正していきます。
以下は一例。

```json:snippet/tyrano.snippet.json
{
	"[playbgm]":{
		"prefix":"playbgm",
		"body":[
		"[playbgm storage=\"\" loop=\"\" sprite_time=\"\" volume=\"\"]"
		],
		"description":[
		"BGMを再生します",
		"再生するファイルはプロジェクトフォルダのbgmフォルダに格納してください",
		"ogg形式、HTML5標準をサポートします",
		"動作させる環境によって対応フォーマットが異なります",
		"基本的にogg形式を指定しておけば問題ありません",
		"ただし、複数のブラウザ形式の場合、IEとSafariにも対応させるためにはbgmフォルダに同名でaac形式(m4a)ファイルも配置して下さい",
		"すると自動的に適切なファイルを選択して再生します",
		"デフォルト設定ではmp3は再生できません",
		"Confit.tjs の mediaFormatDefaultをmp3に変更して下さい",
		"ただしこの場合 PCアプリとしては動作しません",
		"",
		"パラメータ 必須 解説",
		"storage ◯ 再生する音楽ファイルを指定してください",
		"loop × true（デフォルト）またはfalse を指定してください。trueを指定すると繰り返し再生されます。",
		"sprite_time × 再生の開始時間と終了時間を指定することができます。ミリ秒で指定します。例えば 6000-10000 と指定すると 6:00～10:00　の間のみ再生できます。loopがtrueの場合はこの間のみループ再生します。",
		"volume × 再生する音量を指定できます。0～100 の範囲で指定して下さい。（デフォルトは100） "
		]},
}
```
正しく設定できれば、以下のようにスニペットが表示されます。

![スクリーンショット 2021-05-16 120611.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/728667/bca9459a-a594-b405-0530-45f37308c4ef.png)


## 拡張機能を取り込む

完成したら、自身の環境で実際に使えるようにしてみましょう。
C:\\Users\\USER_NAME\\.vscode\\extensions
にプロジェクトごと拡張機能を入れてください。
VScodeを再起動すれば使えるようになります。
自分専用の拡張機能なら以上で終了です。


## 拡張機能を公開する

十分なものが作れたら、マーケットプレイスで公開してみましょう。

### パーソナルアクセストークンを取得する

https://dev.azure.com/vscode
にアクセスして、「Poersonal access tokens」をクリック。
新規にトークンを作成します。
スコープのMarketplaceでManageにチェックを入れます。
ここで発行されたトークンはサイド表示できません。ですのですぐにコピーしてください。

参考リンク

* https://code.visualstudio.com/api/working-with-extensions/publishing-extension

### パブリッシャーの設定
https://marketplace.visualstudio.com/manage に行き、
パブリッシャーを作成。
IDにはユニークなかぶらないものを入れてください。

package.jsonに以下を追記します。

```
	"publisher": "PUBLISHER_NAME",
```

### パッケージングする

```shell
vsce package
```
yo codeから生成している場合、README.mdも生成されていますが、それは一度消去し、
その語新規にREADMEを作成してください。
消していない場合、エラーが出ます。

成功すると、プロジェクトファイル内に.vsix拡張子のパッケージされた拡張機能が生成されます。

### 公開

https://marketplace.visualstudio.com/manage/publishers/
にアクセスし、create publisherを選択。
パッケージ化した拡張機能をドラッグ＆ドロップで配置して公開完了です。

### 作ったもの
インテリセンスやアウトラインなどに関しては、以下のリポジトリを参照ください。
https://github.com/orukRed/tyranosyntax
src/extension.tsがエンドポイントになってて、そこから各種クラスに定義した諸々の機能を呼び出しています。