メインコンテンツまでスキップ

自分用にVSCodeのアウトライン拡張を作ってみました

· 約8分
mebiusbox
engineer

標準でアウトラインに表示されるシンボルは多すぎて使いづらいので、自分好みのシンボルをアウトラインに表示させるようにするために拡張機能を作りました.ここでは開発の備忘録としていくつかまとめておきます.

はじめに

VSCode の標準機能にあるアウトラインにはシンボル情報が表示されます.設定で一部を非表示に出来たり、Ctrl+Fキーを押すと検索で絞り込むことができます.

VSCode Outline View

また、シンボル検索(Ctrl+Shift+O)を使うこともできます.これはコマンドパレットで @ と入力しても同じ結果になります.

Symbol Search

ここで @: と入力すればカテゴリごとに分けて表示されます.

Symbol Search with Category

検索を使えば事足りそうな気がしますが、しばらく触っていなかったりするとそもそも関数名とか何があるのかを記憶していません. もう少し自分に優しいシンボル検索がとても欲しいと感じました.

目印と関数

アウトラインとして欲しいものに「目印(マーク)」と「関数(メソッド)」の2種類があります. 関数は標準の機能でありますが、目印は拡張機能を導入する必要があります. 今回は、アウトラインに目印を表示してくれる拡張機能「Marks To Outline」のソースコードを調整して自分好みのアウトライン機能を作りました.

Marks to outlineAdds MARKS symbols to outline view

次のようなアウトライン表示になります.

Pixy Outline View

目印は MARK: *** と記述するようになっています. また、シンボル名にはそれぞれ M: F: を付けています.これによってシンボル検索で、目印は @M: 、関数は @F: で絞り込むことができます.

Search Function Symbols

Search Mark Symbols

VSCode拡張機能の作成

Node.jsの環境で作成します.以下を参考にしました.

VSCode Extensions(拡張機能) 自作入門 〜VSCodeにおみくじ機能を追加する〜VSCode Extensions(拡張機能) 自作入門 〜VSCodeにおみくじ機能を追加する〜

まず、yo, generator-code パッケージが必要なのでインストールします.

npm i yo generator-code -g

Node.jsのバージョンも条件を満たすようにアップデートしました.

$ node -v
v18.17.1

$ npm -v
10.2.5

ひな形を作成します.

$ yo code

次に Marks to Outline を参考に実装していきます. 別に Marks to Outline をクローンして編集しても問題ありません.コードが比較的少ない場合は、どのような処理をやっているかを確認するためにもよく書き写しています.

機能の追加

Marks to Outline には目印をアウトラインに表示する機能がすでに入っています.そこに関数を追加します. 関数は目印と同様に正規表現で抽出します.ただし、1行でしか判定していないので正確な関数抽出は出来ません.これは妥協しました.

関数は無視パターンと一致パターンを使って、先に無視パターンで弾いてから一致パターンでチェックするようにしています.

const funcIgnorePatterns = [
"^\\s*[a-zA-Z_][a-zA-Z0-9_]+\\([^;]*\\)[^;\\{]*$",
"^\\s*[a-zA-Z_][a-zA-Z0-9_]+\\([^(=>);]*\\{.*$"
];
const funcSearchPatterns = [
"^\\s*([a-zA-Z_][a-zA-Z0-9_]+)\\([^;]*$",
"^\\s*([a-zA-Z_][a-zA-Z0-9_]+)<[^\\(]+>\\([^;]*$",
"^\\s*function\\s*([a-zA-Z_][a-zA-Z0-9_]+)\\([^;]*$",
"^\\s*function\\s*([a-zA-Z_][a-zA-Z0-9_]+)<[^\\(]+>\\([^;]*$",
"^\\s*(?:const|let|var)\\s*([a-zA-Z_][a-zA-Z0-9_]+)[^;]*=\\s*async\\s*\\([^;]*$",
];

一応、async やアロー関数も対応していますが、まだまだ調整は必要だと思います. また、JavaScript(+TypeScript)にしか対応していません.これは随時更新していけばいいかなと.

DocumentSymbol

Marks to Outline では vscode.SymbolInformation をシンボルプロバイダの生成物として返しているのですが、これだとアウトラインの階層表示に対応できません. 階層表示させるには vscode.DocumentSymbol を使います.詳しくは、以下を参考にしました.

VS Code拡張API - DocumentSymbolProvider

具体的には vscode.DocumentSymbol で親子関係を構築していけばよいみたいです. vscode.DocumentSymbol.childrenvscode.DocumentSymbol を追加していく感じです.

const vscodeSymbols: vscode.DocumentSymbol[] = [];
const markGroup: vscode.DocumentSymbol = new vscode.DocumentSymbol(
"MARKS",
"",
vscode.SymbolKind.Key,
new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 10)),
new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 10))
);
resultMarks.map((result: MarkTokens) => {
markGroup.children.push(
finder.makeDocumentSymbol(
{ ...result, document },
vscode.SymbolKind.Key,
"M: "
)
);
});
vscodeSymbols.push(markGroup);

const funcGroup: vscode.DocumentSymbol = new vscode.DocumentSymbol(
// (...)
);

// (...)

vscodeSymbols.push(funcGroup);

この vscodeSymbolsprovideDocumentSymbols メソッドで返すようにしています.

パッケージの生成とインストール

デバッグをしていい感じになったら、パッケージングします. この時 README.md を編集しないと怒られるので適当に編集します.以下のコマンドでパッケージが作成できます.

npx vsce package

拡張子が .vsix のファイルが生成されます.VSCode上ならこのファイルを右クリックからインストールできます.

役に立ったサイト

拡張機能のアクティベートの部分に関しては次のサイトを参考にしました.

Visual Studio Code 拡張機能のアクティベート activationEvents

合わせて使いたい拡張機能

おまけで TODO Highlight という拡張機能を使うと、目印のコードをハイライトすることができます.

TODO Highlighthighlight TODOs, FIXMEs, and any keywords, annotations...

インストールしただけではダメで、カスタマイズする必要があります.

設定で todohighlight.keywords を追加します.以下は私の設定です.

"todohighlight.keywords": [
{
"text": "NOTE:",
"color": "#242424",
"border": "1px solid #66D9EF",
"borderRadius": "2px",
"backgroundColor": "#66D9EF",
"overviewRulerColor": "transparent"
},
{
"text": "//!",
"color": "#242424",
"border": "1px solid #A6E22E",
"borderRadius": "2px",
"backgroundColor": "#A6E22E",
"overviewRulerColor": "transparent"
},
{
"text": "MARK:",
"color": "#242424",
"border": "1px solid #A6E22E",
"borderRadius": "2px",
"backgroundColor": "#A6E22E",
"fontWeight": "600",
"isWholeLine": true,
}
],

次のように表示されます:

TODO Highlight

これで少しは快適になった感じがします.もしかすると便利な拡張機能や標準で出来るかもしれません. ちなみに、今のところ作成した拡張機能は公開する予定はありません. 以上です.