在 VS Code 中试试

Visual Studio Code 中的代码片段

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

在 Visual Studio Code 中,代码片段会出现在智能感知(⌃Space (Windows, Linux Ctrl+Space))中,与其他建议混合显示,也会出现在专门的代码片段选择器中(在命令面板中选择插入代码片段)。还支持 Tab 补全:通过设置 "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 会为您管理底层代码片段文件的创建和刷新。

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,它将通过智能感知显示。
  • prefix 定义了一个或多个触发词,这些词会在智能感知中显示代码片段。会对前缀执行子字符串匹配,因此在此例中,“fc”可以匹配“for-const”。
  • body 是一行或多行内容,插入时将合并为多行。新行和内嵌的 Tab 将根据插入代码片段的上下文进行格式化。
  • description 是代码片段的可选描述,在智能感知中显示。

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

文件模板代码片段

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

代码片段作用域

代码片段是带作用域的,以便仅建议相关的代码片段。代码片段可以通过以下方式设置作用域

  1. 代码片段所针对的语言(可能为所有语言)
  2. 代码片段所针对的项目(可能为所有项目)

语言代码片段作用域

每个代码片段根据其定义位置,被限定于一种、几种或所有(“全局”)语言

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

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

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

大多数用户定义的代码片段仅限于单种语言,因此它们定义在语言特定的代码片段文件中。

项目代码片段作用域

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

代码片段语法

代码片段的 body 可以使用特殊构造来控制光标和要插入的文本。以下是支持的特性及其语法

Tab 停靠点

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

占位符

占位符是带有值的 Tab 停靠点,例如 ${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 月份的全称(例如 'July')
  • CURRENT_MONTH_NAME_SHORT 月份的短名称(例如 'Jul')
  • CURRENT_DATE 两位数字表示的月份中的日期(例如 '08')
  • CURRENT_DAY_NAME 星期几的名称(例如 'Monday')
  • 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

占位符转换

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

转换示例

示例显示在双引号中,就像它们出现在代码片段正文内一样,以便说明需要双重转义某些字符。文件名 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(扩展巴科斯-诺尔范式)。使用 \(反斜杠)可以转义 $}\。在 choice 元素中,反斜杠也转义逗号和竖线字符。只能转义需要转义的字符,因此在这些结构中不应转义 $,在 choice 结构内也不应转义 $}

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 代码片段

您也可以在 VS Code 中使用现有的 TextMate 代码片段 (.tmSnippets)。有关更多信息,请参阅我们扩展 API 部分的使用 TextMate 代码片段主题。

为代码片段分配键盘快捷方式

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

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

该键盘快捷方式将调用插入代码片段命令,但不会提示您选择代码片段,而是会插入提供的代码片段。您可以像往常一样定义自定义按键绑定,包括键盘快捷方式、命令 ID 以及可选的when 子句上下文,用于指定何时启用该键盘快捷方式。

此外,除了使用 snippet 参数值内联定义代码片段外,您还可以通过使用 langIdname 参数来引用现有代码片段。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

我可以从智能感知中移除代码片段吗?

是的,您可以通过在插入代码片段命令下拉列表中选择代码片段项右侧的从智能感知中隐藏按钮,来隐藏特定代码片段不在智能感知(完成列表)中显示。

Hide from IntelliSense button in Insert Snippet dropdown

您仍然可以使用插入代码片段命令选择该代码片段,但隐藏的代码片段将不会显示在智能感知中。