🈳

【VS Code拡張機能】どんなファイルもフォーマットできるフォーマッタ(ただしフォーマットはしない)を作った

2023/04/10に公開

はじめに

Visual Studio Code用の「どんなファイルもフォーマットできるフォーマッタ(ただしフォーマットはしない)」を作りました。

経緯

この記事に辿りつくような人であればおそらく、フォーマッタの利便性の高さはすでに体感したことがあるでしょう。どれだけ乱れた書き方をされたコードもキーボードショートカット一発できれいに整えられるその利便性、そして快感……。とりあえずフォーマットしておく手癖がついてしまった人もいることでしょう、私のように。

しかし世の中には、フォーマットしてはいけないファイルというのもあります。そういったファイルを編集中、ついつい手癖でフォーマットしてしまったら? ctrl+zを使えば元に戻すことはできますが、面倒ですし、自責の念が生まれます。

さてそれでは、次のような設定をしてみるのはどうでしょうか。ここでは、あるワークスペースにおいてどんなファイルもフォーマットしたくないとします。

// .vscode/settings.json
{
  "editor.defaultFormatter": null
}

これは一見するとうまく動くように思えてしまいますが、実際にはそうはいきません。これは「どのフォーマッタでフォーマットするか明示的には設定しない」という設定であり、この設定がされた状態でも普通にフォーマットはされます。もしくは「There are multiple formatters」というメッセージが表示され、複数のフォーマッタのいずれか1つを選ぶよう促されます。明示的にフォーマッタを選択しないので暗黙的に選択されたフォーマッタが使われる、ということです。

それではこの事態はどうすれば解決するでしょうか?

どんなファイルもフォーマットできるフォーマッタ(ただしフォーマットはしない)を作る

暗黙的に選択されたフォーマッタがどんな編集もしなければいい、という考え方です。

VS Codeにフォーマッタを追加するには、拡張機能を自作する必要があります。とはいえこの程度の拡張機能は数時間あれば作れます(作れました)。

https://github.com/okayurisotto/yaf

仕組み

import * as vscode from "vscode";

class DocumentFormattingEditProvider
  implements vscode.DocumentFormattingEditProvider
{
  provideDocumentFormattingEdits() {
    return [];
  }
}

class DocumentRangeFormattingEditProvider
  implements vscode.DocumentRangeFormattingEditProvider
{
  provideDocumentRangeFormattingEdits() {
    return [];
  }
}

export const activate = (context: vscode.ExtensionContext) => {
  context.subscriptions.push(
    vscode.languages.registerDocumentFormattingEditProvider(
      "*",
      new DocumentFormattingEditProvider(),
    ),
    vscode.languages.registerDocumentRangeFormattingEditProvider(
      "*",
      new DocumentRangeFormattingEditProvider(),
    ),
  );
};

registerDocumentFormattingEditProvider()を使うと自作フォーマッタを登録できます。第1引数がそのフォーマッタが対応しているファイルのセレクタ、第2引数がフォーマッタです。今回は第1引数に"*"を渡しているので、どんなファイルもフォーマットできることになっています。

第2引数に渡しているDocumentFormattingEditProviderprovideDocumentFormattingEdits()というメソッドを持ちます。引数としてフォーマット前の文字列などが渡され、適用したい編集(TextEdit)の配列を返さなければなりません。ここでは空の配列を返しているので、適用される編集はありません。

DocumentRangeFormattingEditProviderについても同様です。こちらは選択範囲のフォーマット機能になります。

おわりに

なんでもフォーマットする悪癖やめたい。

補足

VS Codeでは設定は言語単位に行います。ファイル単位ではなくファイルと関連付けされた言語単位で、というところがミソで、要するに、ファイル名に応じた設定などはできません。つまりファイル名に応じてフォーマット機能を無効化するためにこの拡張機能を使うという使い方はできません。

しかしそれもなんとかすることができないわけではありません。VS Codeにはfiles.associationsという設定があり、これを使うことで任意のファイルを任意の言語と紐付けることができます。あとはダミーとしての「任意の言語」を用意すればいいだけです。その方法についてもすでに記事にしてありますので、ぜひどうぞ。

https://zenn.dev/okayurisotto/articles/088de70c4b4952

Discussion