参加你附近的 ,了解 VS Code 中的 AI 辅助开发。

Visual Studio Code 中的代码片段

代码片段(Snippets)是一些模板,可让您更轻松地输入重复的代码模式,例如循环或条件语句。

在 Visual Studio Code 中,代码片段会与其他建议一起出现在 IntelliSense (⌃Space (Windows, Linux Ctrl+Space)) 中,也会出现在专门的代码片段选择器(在命令面板中选择“插入代码片段”)中。此外,还支持 Tab 补全:通过 "editor.tabCompletion": "on" 启用此功能,然后键入一个代码片段前缀(触发文本),再按 Tab 即可插入代码片段。

代码片段的语法遵循 TextMate snippet syntax,但不支持“内插 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,它将通过 IntelliSense 显示。
  • prefix 定义了一个或多个触发词,用于在 IntelliSense 中显示代码片段。前缀支持子字符串匹配,因此在这种情况下,“fc”可以匹配到“for-const”。
  • body 是一行或多行内容,插入时会合并为多行。换行符和内嵌的制表符将根据插入代码片段的上下文进行格式化。
  • description 是一个可选的描述,由 IntelliSense 显示。

此外,上面示例的 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 可以使用特殊构造来控制光标和插入的文本。以下是支持的功能及其语法:

制表位

通过制表位,你可以让编辑器光标在代码片段内移动。使用 $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 月份的全称(例如 '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

占位符转换

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

转换示例

这些示例显示在双引号内,就像它们出现在代码片段主体中一样,以说明需要对某些字符进行双重转义。以下是针对文件名 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 代码片段

你也可以在 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

我可以从 IntelliSense 中移除代码片段吗?

是的,你可以在“插入代码片段”命令下拉列表中,通过选择代码片段项右侧的“从 IntelliSense 隐藏”按钮,来隐藏特定的代码片段,使其不在 IntelliSense(补全列表)中显示。

Hide from IntelliSense button in Insert Snippet dropdown

你仍然可以通过“插入代码片段”命令来选择该代码片段,但被隐藏的代码片段将不会显示在 IntelliSense 中。