现已推出!阅读 10 月份发布的新功能和修复。

Visual Studio Code 中的代码片段

代码片段是模板,使您更容易输入重复的代码模式,例如循环或条件语句。

在 Visual Studio Code 中,代码片段会出现在 IntelliSense (⌃Space (Windows、Linux Ctrl+Space)) 中,与其他建议混合在一起,还会出现在专门的代码片段选择器 (插入代码片段 命令面板) 中。还支持制表符补全:使用 "editor.tabCompletion": "on" 启用它,键入代码片段前缀 (触发文本),然后按 Tab 插入代码片段。

代码片段语法遵循 TextMate 代码片段语法,但以下情况除外:“插值 shell 代码”和使用 \u;这两者都不支持。

ajax snippet

内置代码片段

VS Code 为多种语言内置了代码片段,例如:JavaScript、TypeScript、Markdown 和 PHP。

builtin javascript snippet

您可以通过在命令面板中运行插入代码片段命令来查看某语言可用的代码片段,从而获取当前文件语言的代码片段列表。但是,请记住,此列表还包括您定义的用户代码片段以及您安装的扩展提供的任何代码片段。

从市场安装代码片段

VS Code 市场上的许多 扩展 都包含代码片段。您可以在扩展视图 (⇧⌘X (Windows、Linux Ctrl+Shift+X)) 中使用 @category:"snippets" 过滤器搜索包含代码片段的扩展。

Searching for extensions with snippets

如果您找到要使用的扩展,请安装它,然后重新启动 VS Code,新的代码片段将可用。

创建您自己的代码片段

您无需任何扩展即可轻松定义自己的代码片段。要创建或编辑您自己的代码片段,请在 文件 > 首选项 中选择配置用户代码片段,然后选择代码片段应该出现的语言 (按 语言标识符),或者选择新建全局代码片段文件选项(如果代码片段应在所有语言中出现)。VS Code 会为您管理底层代码片段文件(s) 的创建和刷新。

snippet dropdown

代码片段文件使用 JSON 编写,支持 C 风格注释,可以定义无限数量的代码片段。代码片段支持大多数 TextMate 语法以实现动态行为,会根据插入上下文智能地格式化空格,并允许轻松进行多行编辑。

下面是 JavaScript 的 for 循环代码片段示例

// in file 'Code/User/snippets/javascript.json'
{
  "For Loop": {
    "prefix": ["for", "for-const"],
    "body": ["for (const ${2:element} of ${1:array}) {", "\t$0", "}"],
    "description": "A for loop."
  }
}

在上面的示例中

  • "For Loop" 是代码片段名称。如果未提供 description,则通过 IntelliSense 显示它。
  • prefix 定义一个或多个触发词,这些触发词会显示 IntelliSense 中的代码片段。对前缀执行子字符串匹配,因此在这种情况下,“fc”可以匹配“for-const”。
  • body 是一个或多行内容,这些内容将在插入时作为多行连接。换行符和嵌入的制表符将根据插入代码片段的上下文进行格式化。
  • description 是代码片段的可选描述,由 IntelliSense 显示。

此外,上面的示例的 body 包含三个占位符 (按遍历顺序排列):${1:array}${2:element}$0。您可以使用 Tab 快速跳转到下一个占位符,此时您可以在占位符中进行编辑或跳转到下一个占位符。冒号 : 后的字符串 (如果有) 是默认文本,例如 ${2:element} 中的 element。占位符遍历顺序是按数字递增,从 1 开始;0 是一个可选的特殊情况,它始终排在最后,并以光标位于指定位置退出代码片段模式。

文件模板代码片段

如果您要将代码片段用于填充或替换文件的全部内容,则可以在代码片段定义中添加 isFileTemplate 属性。当您在一个新文件或现有文件中运行代码片段:从代码片段填充文件命令时,文件模板代码片段会显示在下拉列表中。

代码片段范围

代码片段具有范围,因此只建议相关的代码片段。代码片段的范围可以是:

  1. 代码片段所限定的语言 (可能是所有语言)
  2. 代码片段所限定的项目 (可能是所有项目)

语言代码片段范围

每个代码片段都限定到一种、多种或所有 (“全局”) 语言,具体取决于它是定义在:

  1. 语言 代码片段文件中
  2. 全局 代码片段文件中

单语言用户定义的代码片段是在特定语言的代码片段文件中定义的 (例如 javascript.json),您可以通过代码片段:配置用户代码片段按语言标识符访问它。只有在编辑代码片段定义的语言时,才能访问代码片段。

多语言和全局用户定义的代码片段都是在“全局”代码片段文件中定义的 (带有文件后缀 .code-snippets 的 JSON),也可以通过代码片段:配置用户代码片段访问它。在全局代码片段文件中,代码片段定义可能包含一个额外的 scope 属性,该属性接受一个或多个 语言标识符,这使得代码片段仅适用于那些指定的语言。如果未指定 scope 属性,则全局代码片段在所有语言中都可用。

大多数用户定义的代码片段都限定到一种语言,因此是在特定语言的代码片段文件中定义的。

项目代码片段范围

您还可以拥有一个限定到项目的全局代码片段文件 (带有文件后缀 .code-snippets 的 JSON)。项目文件夹代码片段使用为“”新建代码片段文件...选项在代码片段:配置用户代码片段下拉菜单中创建,并位于项目的根目录中的 .vscode 文件夹中。项目代码片段文件对于与在该项目中工作的用户共享代码片段很有用。项目文件夹代码片段与全局代码片段类似,可以通过 scope 属性限定到特定语言。

代码片段语法

代码片段的 body 可以使用特殊结构来控制光标和插入的文本。以下列出了支持的功能及其语法

制表符停靠点

使用制表符停靠点,您可以使编辑器光标在代码片段中移动。使用 $1$2 指定光标位置。数字表示访问制表符停靠点的顺序,而 $0 表示最终光标位置。相同制表符停靠点的多次出现是关联的,会同步更新。

占位符

占位符是带有值的制表位,例如 `${1:foo}`。占位符文本将被插入并选中,以便于更改。占位符可以嵌套,例如 `${1:another ${2:placeholder}}`。

选择

占位符可以有选择作为值。语法是用竖线字符括起来的用逗号分隔的值枚举,例如 `${1|one,two,three|}`。当片段插入并且占位符被选中时,选择会提示用户选择一个值。

变量

使用 `$name` 或 `${name:default}`,您可以插入变量的值。当变量未设置时,将插入其 **默认值** 或空字符串。当变量未知(即其名称未定义)时,将插入变量的名称,并将它转换为占位符。

可以使用以下变量

  • TM_SELECTED_TEXT 当前选定的文本或空字符串
  • TM_CURRENT_LINE 当前行的内容
  • TM_CURRENT_WORD 光标下的单词的内容或空字符串
  • TM_LINE_INDEX 基于零的行号
  • TM_LINE_NUMBER 基于一的行号
  • TM_FILENAME 当前文档的文件名
  • TM_FILENAME_BASE 当前文档的文件名,不包括扩展名
  • TM_DIRECTORY 当前文档的目录
  • TM_FILEPATH 当前文档的完整文件路径
  • RELATIVE_FILEPATH 当前文档相对于打开的工作区或文件夹的相对文件路径
  • CLIPBOARD 剪贴板的内容
  • WORKSPACE_NAME 打开的工作区或文件夹的名称
  • WORKSPACE_FOLDER 打开的工作区或文件夹的路径
  • CURSOR_INDEX 基于零的光标编号
  • CURSOR_NUMBER 基于一的光标编号

用于插入当前日期和时间

  • CURRENT_YEAR 当前年份
  • CURRENT_YEAR_SHORT 当前年份的后两位数字
  • CURRENT_MONTH 月份,用两位数字表示(例如“02”)
  • CURRENT_MONTH_NAME 月份的完整名称(例如“七月”)
  • CURRENT_MONTH_NAME_SHORT 月份的简短名称(例如“Jul”)
  • CURRENT_DATE 月份中的日期,用两位数字表示(例如“08”)
  • CURRENT_DAY_NAME 星期几的名称(例如“星期一”)
  • CURRENT_DAY_NAME_SHORT 星期几的简短名称(例如“Mon”)
  • CURRENT_HOUR 当前小时,使用 24 小时制
  • CURRENT_MINUTE 当前分钟,用两位数字表示
  • CURRENT_SECOND 当前秒,用两位数字表示
  • CURRENT_SECONDS_UNIX 自 Unix 纪元以来的秒数
  • CURRENT_TIMEZONE_OFFSET 当前 UTC 时区偏移量,以 `+HH:MM` 或 `-HH:MM` 格式表示(例如 `-07:00`)。

用于插入随机值

  • RANDOM 6 个随机的十进制数字
  • RANDOM_HEX 6 个随机的十六进制数字
  • UUID 版本 4 的 UUID

用于插入行或块注释,遵循当前语言

  • BLOCK_COMMENT_START 示例输出:在 PHP 中为 `/*`,在 HTML 中为 `<!--`
  • BLOCK_COMMENT_END 示例输出:在 PHP 中为 `*/`,在 HTML 中为 `-->`
  • LINE_COMMENT 示例输出:在 PHP 中为 `//`

下面的片段在 JavaScript 文件中插入 `/* Hello World */`,在 HTML 文件中插入 `<!-- Hello World -->`

{
  "hello": {
    "scope": "javascript,html",
    "prefix": "hello",
    "body": "$BLOCK_COMMENT_START Hello World $BLOCK_COMMENT_END"
  }
}

变量转换

转换允许您在插入变量的值之前对其进行修改。转换的定义由三个部分组成

  1. 与变量的值匹配的正则表达式,或者当变量无法解析时使用空字符串。
  2. 允许引用正则表达式中匹配组的“格式字符串”。格式字符串允许条件插入和简单的修改。
  3. 传递给正则表达式的选项。

以下示例插入当前文件名,不包括其结尾,因此从 `foo.txt` 中生成 `foo`。

${TM_FILENAME/(.*)\\..+$/$1/}
  |           |         |  |
  |           |         |  |-> no options
  |           |         |
  |           |         |-> references the contents of the first
  |           |             capture group
  |           |
  |           |-> regex to capture everything before
  |               the final `.suffix`
  |
  |-> resolves to the filename

占位符转换

与变量转换类似,占位符的转换允许在移动到下一个制表位时更改插入的占位符文本。插入的文本与正则表达式匹配,匹配项(取决于选项)将被指定的替换格式文本替换。每个占位符的出现都可以使用第一个占位符的值独立地定义自己的转换。占位符转换的格式与变量转换相同。

转换示例

示例显示在双引号内,因为它们会出现在片段主体中,以说明对某些字符进行双重转义的必要性。对于文件名 `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-9a-z]//gi}" example123456TESTjs 删除非字母数字字符

语法

以下是片段的 EBNF (扩展巴科斯范式)。使用 `\`(反斜杠),您可以转义 `$`、`}` 和 `\`。在选择元素中,反斜杠还会转义逗号和竖线字符。只有需要转义的字符才能转义,因此 `$` 不应该在这些结构中转义,并且 `$` 或 `}` 不应该在选择结构中转义。

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

使用 TextMate 代码片段

您还可以使用现有的 TextMate 片段(.tmSnippets)与 VS Code。请参阅扩展 API 部分中的 使用 TextMate 片段 主题以了解更多信息。

为代码片段分配键绑定

您可以创建自定义 键盘快捷键 来插入特定的片段。打开 `keybindings.json`(**首选项:打开键盘快捷键文件**),它定义了所有键盘快捷键,并添加一个键盘快捷键,传递 `“snippet”` 作为额外的参数

{
  "key": "cmd+k 1",
  "command": "editor.action.insertSnippet",
  "when": "editorTextFocus",
  "args": {
    "snippet": "console.log($1)$0"
  }
}

键盘快捷键将调用 **插入片段** 命令,但不会提示您选择片段,而是会插入提供的片段。您像往常一样使用键盘快捷键、命令 ID 和可选的 when 子句上下文 定义自定义 键盘快捷键,以启用键盘快捷键。

此外,您还可以使用 `langId` 和 `name` 参数引用现有的片段,而不是使用 `snippet` 参数值来内联定义片段。`langId` 参数选择用于插入由 `name` 表示的片段的语言,例如下面的示例选择适用于 `csharp` 文件的 `myFavSnippet`。

{
  "key": "cmd+k 1",
  "command": "editor.action.insertSnippet",
  "when": "editorTextFocus",
  "args": {
    "langId": "csharp",
    "name": "myFavSnippet"
  }
}

后续步骤

  • 命令行 - VS Code 具有丰富的命令行界面,用于打开或比较文件并安装扩展。
  • 扩展 API - 了解扩展 VS Code 的其他方法。
  • 片段指南 - 您可以打包片段供 VS Code 使用。

常见问题

如果我想使用 .tmSnippet 文件中的现有 TextMate 片段怎么办?

您可以轻松地打包 TextMate 片段文件供 VS Code 使用。请参阅扩展 API 文档中的 使用 TextMate 片段

如何让片段在粘贴的脚本中放置一个变量?

要在粘贴的脚本中放置一个变量,您需要转义 `$variable` 名称的 `$`,这样它就不会被片段扩展阶段解析。

"VariableSnippet":{
    "prefix": "_Var",
    "body": "\\$MyVar = 2",
    "description": "A basic snippet that places a variable into script with the $ prefix"
  }

这将导致粘贴的片段为

$MyVar = 2

我可以从 IntelliSense 中删除片段吗?

是的,您可以隐藏特定片段,使其不显示在 IntelliSense(完成列表)中,方法是在 **插入片段** 命令下拉列表中片段项的右侧选择 **从 IntelliSense 中隐藏** 按钮。

Hide from IntelliSense button in Insert Snippet dropdown

您仍然可以使用 **插入片段** 命令选择片段,但隐藏的片段不会显示在 IntelliSense 中。