VSCode スニペット

スニペットとはfor文やif文など繰り返しのコードパターンを簡単に入力できるようにするテンプレートです。

VSCodeではJavascript, typescript, pythonなど多くの言語用に標準でいくつかスニペットが組み込まれており、 さらに拡張機能を入れることでもスニペットを追加することができます。 スニペットはIntelliSenseに他の候補と混在して表示される他、コマンドパレットからスニペットの挿入コマンドを実行すると、 現在開いているファイルの言語に登録されているスニペットの一覧が表示されます。 設定でタブ補完を有効("editor.tabCompletion": "on")にしているとタブ補完のサポートも受ける事も可能です。
タブ補完はデフォルトでonになっています。 スニペットのプレフィックス(トリガーテキスト)を入力し、Tabキーを押してスニペットを挿入します。

スニペットの展開
図0-1 javascriptファイルでforスニペットを展開してみる

便利なスニペットですが実はユーザー定義のスニペットを作成することも可能です。ユーザー定義のスニペットを作成するにはスニペットファイルにスニペットを記載していく必要があるのですが、スニペットファイルには大きく分けて以下の3種類があります。

  1. 現在のフォルダだけで使用するスニペットを記載するスニペットファイル
  2. 特定の言語だけで使用するスニペットを記載するスニペットファイル
  3. 全体にわたって使用したいスニペットを記載するスニペットファイル

2と3に関しては現在のフォルダだけでなく全体に影響が出るので、最初は1の現在のフォルダだけで使用できるスニペットファイルで練習するのがおすすめです。 現在のプロジェクト以外でも使えそうなスニペットが出来たら2と3に記載してもいいと思います。

1. スニペットファイルの作成

ユーザー定義のスニペットを作成するにはスニペットファイルがまずは必要です。

スニペットファイルを作成するにはVSCodeの左下の歯車アイコンからユーザースニペットを選択してください。 選択すると以下のようなダイアログが出てきます。

スニペットファイルの作成
図1-1 作成するスニペットファイルの種類を選択する

新しいグローバルスニペット ファイル...を選択した場合、全体にわたって使用したいスニペットを記述するスニペットファイルが開かれます。
"現在開いているフォルダ名"の新しいスニペットファイル...を選択した場合、現在のフォルダのみで使用するスニペットを記述するスニペットファイルが開かれます。
上記二つのスニペットファイルは作成する際にファイル名の入力を求められますが、できるだけわかりやすい名前をつけましょう。

ファイル名の入力
図1-2 ファイル名を入力。わかりやすい名前をつけよう。

その下に記載の言語を選択するとその言語専用のスニペットを記述するJSonファイルが開かれます。


一度スニペットファイルを作成していると上段に作成済みのスニペットファイルが選択できるようになっているので、スニペットを追加したい場合は作成済みのスニペットファイルを選択しましょう。

作成済のスニペットファイル
図1-3 作成済みのスニペットファイルは上段に表示される。

2. スニペットファイルの構成

現在開いているフォルダ名のスニペットファイルを新規で作成した場合は下記のような形で英語の説明とサンプルがコメントで記載されています。

{
// Place your VSCode ワークスペース snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
// description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
// is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
// used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders.
// Placeholders with the same ids are connected.
// Example:
// "Print to console": {
// "scope": "javascript,typescript",
// "prefix": "log",
// "body": [
// "console.log("$1");",
// "$2"
// ],
// "description": "Log output to console"
// }
}
図2-1 スニペットファイルを新規作成

javascriptとtypescript用のスニペットのサンプルがコメントアウトされて記載されています。

// "Print to console": {から// }の行までを選択し、 Ctrl + /(Macの場合はCommand + /)でコメントを解除します。

{
// コメントは省略
 "Print to console": {
 "scope": "javascript,typescript",
 "prefix": "log",
 "body": [
 "console.log("$1");",
 "$2"
 ],
 "description": "Log output to console"
 }
}
図2-2 コメントアウトを解除

これでユーザー定義のスニペット"Print to console"が作成できましたが、 "prefix"欄のトリガーテキスト"log"はJavascript,typescriptともにVSCode標準のスニペットとしてすでに登録されてるため"log"から"user-log"と書き換えましょう。

{
// コメントは省略
 "Print to console": {
 "scope": "javascript,typescript",
 "prefix": "user-log", // "log"から"user-log"に書き換える
 "body": [
 "console.log("$1");",
 "$2"
 ],
 "description": "Log output to console"
 }
}
図2-3 重複するとわかりづらいので重複しないように書き換える

現在のフォルダでjavascriptファイルを作成しuser-logと入力すると展開直前に以下のように表示されます。

展開例
図2-4 該当位置

トリガーテキスト"user-log"の横にスニペット名"Print to console"、さらにその横に"description"欄に記載した説明、"body"欄の実際に展開した時のプレビューが表示されます。

2-1. スニペット名

[図2-3]に記載の"Print to console"がスニペット名となります。
トリガーテキストの横に短く表示されるのでスニペットがどんなものか短くわかりやすく書きましょう
スニペットファイルの中で一意の値になる必要があります。

2-2. スコープ

スニペットを使用する言語を"scope"欄にカンマ区切りで羅列します。 言語専用のスニペットファイルではこの項目自体がありません。

この項目はオプションなのでなくてもいいですが可能な限り記載した方がいいでしょう。

2-3. スニペット

展開したいコードを"body"欄に記載します。

複数行になる場合は図2-3のように[]で囲ってください。

スニペットには展開した後のカーソル位置を指定できるタブストップや タブストップの位置にデフォルトの文字を入力しておくプレースホルダー、 選択肢から選択できるチョイス、現在の時刻などを入力できる変数、 正規表現などいろいろな機能があります。
機能については次の章で説明します。

2-4. 説明文

"description"欄にスニペット名で説明しきれなかったスニペットの詳細な説明を記載します。

この項目はオプションです。不要な場合は記載しなくても問題ありません。

2-4. ファイルテンプレート

サンプルに出てこなかった項目として"isFileTemplate"という項目があります。

この値をtrueにした場合、スニペットがファイルテンプレートとなります。

ファイルテンプレートになった場合、コマンドパレットからスニペットをファイルで満たすという項目にそのスニペットが登録されます。

コマンドを実行してスニペットを挿入すると、現在のファイルの中身がスニペットの内容になります。
htmlなど雛形がある程度決まっているような場合に使うといいでしょう。

注意点としてすでに何かファイルに記載していた場合、記載していた内容は全て消えます。
この項目をtrueにする場合はうっかり呼び出さないように"prefix"欄は記載しないほうがいいでしょう。

{
"HTML Template": {
  "scope": "html",
  "body": [
    "<!DOCTYPE html>",
    "<html lang=\"${1:ja}\">",
    "<head>",
    "  <meta charset=\"UTF-8\">",
    "  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">",
    "  <title>${2:title}</title>",
    "</head>",
    "<body>",
    "$0",
    "</body>",
    "</html>",
  ],
  "isFileTemplate": true, // このスニペットはファイルテンプレートです
  "description": "HTMLファイルの雛形の例。"
}
}
図2-5 HTMLの雛形のスニペットの例

3. スニペットの機能

スニペットの"body"欄で使用可能な機能の一覧です。

3-1. タブストップ

タブストップはスニペットを展開した後にTabキーで移動する位置を指定するための機能です。

サンプルでも記載があった$1,$2...$0が該当します。

文中の$1に展開後のカーソルが移動します。 $1の位置を修正後、Tabキーを押せば次の数字のタブストップに移動します。
$0は特別なタブストップで一番最後に移動する場所です。

タブストップは同じ数字を複数記載してもかまいません。 複数記載した場合、カーソルが移動した時にマルチカーソルとして複数選択された状態になります。

3-2. プレースホルダー

プレースホルダーはタブストップにデフォルトの文字列を入力しておく機能です。 構文は${N: "デフォルトの文字列"}のようになり、Nにタブストップのインデックス、"デフォルトの文字列"に文字列を入力します。 図2-5でも"<html lang=\"${1:ja}\">",で使われています。

3-3. チョイス

チョイスを使用した場合、候補の中から選ぶことが可能です。 構文は${N|選択肢1,選択肢2,...選択肢N|}のように記載します。

"variable": {
  "prefix": "var",
  "scope": "javascript",
  "body": "${1|const,let|} ${2:var} = ${0: element};"
}
choice
図2-6 チョイスの例

3-4. 変数

現在の時刻やファイル名など時と場所で変わるものは変数で定義されています。

変数の構文$変数名もしくは${変数名:デフォルト文字列}のように記載します。
二つ目の構文は変数が設定されていない場合デフォルト文字列が挿入されます。
変数が定義されていない場合変数名が挿入され、プレースホルダーに変換されます。

現在定義されている変数の一覧を記載します。

  • TM_SELECTED_TEXT現在選択されているテキスト
  • TM_CURRENT_LINE現在の行の内容
  • TM_CURRENT_WORDカーソルの下の単語の内容
  • TM_LINE_INDEX0から始まる行番号
  • TM_LINE_NUMBER1から始まる行番号
  • TM_FILENAME現在のドキュメントのファイル名
  • TM_FILENAME_BASE現在のドキュメントの拡張子を除いたファイル名
  • TM_DIRECTORY現在のドキュメントのディレクトリ
  • TM_FILEPATH現在のドキュメントの完全なファイルパス
  • RELATIVE_FILEPATH現在のドキュメントのVSCodeで現在開いているトップフォルダもしくはワークスペースに対する相対パス
  • CLIPBOARDクリップボードの内容
  • WORKSPACE_NAME開いているワークスペースまたはフォルダーの名前
  • WORKSPACE_FOLDER開いているワークスペースまたはフォルダーのパス
  • CURSOR_INDEXマルチカーソルにおける0から始まるカーソル番号
  • CURSOR_NUMBERマルチカーソルにおける1から始まるカーソル番号
  • CURRENT_YEAR今年の4桁の数字(例: 2023)
  • CURRENT_YEAR_SHORT今年の下2桁の数字(例: 23)
  • CURRENT_MONTH今月の完全な名前(例: July)
  • CURRENT_MONTH_NAME今月の短縮名(例: Jul)
  • CURRENT_MONTH_NAME_SHORT今月の2桁の数字(例: 08)
  • CURRENT_DATE今日の日付の2桁の数字(例: 31)
  • CURRENT_DAY_NAME曜日の名前(例: Monday)
  • CURRENT_DAY_NAME_SHORT曜日の短縮名(例: Mon)
  • CURRENT_HOUR24時間形式の現在の時刻
  • CURRENT_MINUTE現在の分を2桁で表示します。
  • CURRENT_SECOND現在の秒を2桁で表示します。
  • CURRENT_SECONDS_UNIXUnixエポックからの秒数
  • CURRENT_TIMEZONE_OFFSET現在のUTCタイムゾーンオフセット(+HH:MMもしくは-HH:MM)
  • RANDOM6桁の10進数のランダムな値(例: 123456)
  • RANDOM_HEX6桁の16進数のランダムな値(例: F5E4CC)
  • UUIDバージョン4 UUID
  • BLOCK_COMMENT_STARTHTMLの場合<!--, CSSの場合/*
  • BLOCK_COMMENT_ENDHTMLの場合-->, CSSの場合*/
  • LINE_COMMENTjavascriptの場合//

3-5. 正規表現

変数に対して正規表現で変換することが可能です。またプレースホルダーも変数の対象です。

その場合の構文は${変数/正規表現/置換後のテキスト/正規表現オプション}となります。

正規表現の置換に関してはJavascriptの正規表現を参照願います。

置換後のテキストで通常$1と書く部分に対して、独自機能として大文字化などのオプションがあります。

3-5-1. 変換の例

ファイル名「example-123.456-TEST.js」に対して正規表現を使用したサンプルです。
出力 説明
"${TM_FILENAME/[\\.]/_/}" example-123_456-TEST.js 最初に出現した._に変換します
"${TM_FILENAME/[\\.]/_/g}" example-123_456-TEST_js 出現した.を全て_に変換します
"${TM_FILENAME/(.*)/${1:/upcase}/}" EXAMPLE-123.456-TEST.JS 全て大文字に変換します
"${TM_FILENAME/[^0-9^a-z]//gi}" example123456TESTjs 英数字以外の文字を削除する。

3-6. 文法

any ::= tabstop | placeholder | choice | variable | text
tabstop ::= '$' int
| '${' int '}'
| '${' int transform '}'
placeholder ::= '${' int ':' any '}'
choice ::= '${' int '|' text (',' text)* '|}'
variable ::= '$' var | '${' var '}'
| '${' var ':' any '}'
| '${' var transform '}'
transform ::= '/' regex '/' (format | text)+ '/' options
format ::= '$' int | '${' int '}'
| '${' int ':' '/upcase' | '/downcase' | '/capitalize' | '/camelcase' | '/pascalcase' '}'
| '${' int ':+' if '}'
| '${' int ':?' if ':' else '}'
| '${' int ':-' else '}' | '${' int ':' else '}'
regex ::= JavaScript Regular Expression value (ctor-string)
options ::= JavaScript Regular Expression option (ctor-options)
var ::= [_a-zA-Z] [_a-zA-Z0-9]*
int ::= [0-9]+
text ::= .*
if ::= text
else ::= text
図3-1 EBNF記法

下記では正規表現置換後オプションを説明します。

3-6-1. /upcase

マッチした範囲を大文字に変換する。

3-6-2. /downcase

マッチした範囲を小文字に変換する。

3-6-3. /capitalize

マッチした範囲をキャピタライズ形式に変換する。

動作確認したら最初の一文字を大文字に変換だけしかしていない。

3-6-4. /camelcase

マッチした範囲をキャメルケース形式に変換する。

all-user text.txtallUserTextTxtのように変換する。

全て大文字の文字をキャメルケースにした場合、最初の一文字だけ小文字に変換する。

3-6-5. /pascalcase

マッチした範囲をパスカルケース形式に変換する。

all-user text.txtAllUserTextTxtのように変換する。

3-6-6. if

${1:+ マッチした場合のテキスト}のように記載するとマッチした場合のテキストを記述できます。

3-6-7. if else

${1:? マッチした場合のテキスト: マッチしなかった場合のテキスト}のように記載するとマッチしたかどうかで文字を変えることができます。

3-6-8. else

${1:- マッチしなかった場合のテキスト}のように記載するとマッチしなかった場合のテキストを記述できます。
${1: マッチしなかった場合のテキスト}の記載でも同じです。

4. ショートカットキー

スニペットはショートカットから呼び出す方法もあります。 キーボードショートカットキーの設定ファイルを開き、keybindings.jsonファイルに以下のように追加します。

{
  "key": "cmd+k 1", // ショートカットキー
  "command": "editor.action.insertSnippet", // スニペットを挿入するコマンド
  // editorTextFocusは必須、editorLangIdは言語を指定する場合
  "when": "editorTextFocus && editorLangId == html", 
  "args": {
    //選択したテキストをタグで囲む
    //属性が続いて書きやすいように開始タグの末にカーソルが移動するようにする。
    "snippet": "<${1:span}$0>$TM_SELECTED_TEXT</$1>"
  }
}
図4-1 直接スニペットを記載する

言語専用のスニペットファイルに記載したスニペットを呼び出す方法もあります。

{
  "key": "cmd+k 2", // ショートカットキー
  "command": "editor.action.insertSnippet", // スニペットを挿入するコマンド
  "when": "editorTextFocus",
  "args": {
    "langId": "cpp",
    "name": "include-guard"
  }
  //参考: cpp.jsonのinclude-guardスニペット
  //"include-guard": { // name欄にはここの値を指定
  //"prefix": "#hdr",  // prefixではありません
  //"body": [
  //"#ifndef ${1:${TM_FILENAME/(?:(\\w+)(\\.)?)/${1:/upcase}${2:+_}/gi}}",
  //"#define $1",
  //"$0",
  //"#endif // $1"
  //]
}
図4-2 既存のスニペットを呼び出す

図4-2のショートカットキーではC++のスニペットファイルに登録している"include-guard"の名前のスニペットを呼び出します。

ここの"name""prefix"欄ではありません。

サンプル

スニペットのサンプルをまとめてみます。自分用に改変して使用するのがお勧めです。