来源:https://code.visualstudio.com/docs/editor/userdefinedsnippets
用途:供大家深入了解如何运用VSCode中代码片段功能

VSCode中的代码片段(snippets)

代码片段是一种方便重复输入代码的模板。(例如循环或条件语句)

在VSCode中代码片段出现的场景有:1.与其他建议混合的IntelliSense(Ctrl+Space)中;2.专用代码段选择器中(在命令面板中插入代码段)。它还支持通过制表符完成:使用启用它的配置 "editor.tabCompletion": "on",键入片段前缀(触发文本),然后按Tab键插入片段。

代码片段的语法遵循TextMate 代码段语法,但内插shell代码和使用\u; 两者都不支持。

内置片段

VSCode 已经包含了多种语言的内置片段,例如:JavaScript、TypeScript、Markdown 和 PHP。

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

从插件市场上安装片段

VSCode Marketplace上有许多扩展都包含代码片段。您可以使用过滤器在“扩展”视图 (Ctrl+Shift+X) 中搜索包含片段的扩展@category:"snippets"

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

创建你自己的片段

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

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

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

// 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快速跳转到下一个占位符**,此时您**可以编辑占位符或再次跳转到下一个**。`冒号后面的字符串`(如果有)是`默认文本`,例如element在\){2:element}. 占位符遍历顺序按数字升序,从一开始;是一个可选的特殊情况,它总是最后出现,并在光标位于指定位置时退出片段模式。

片段范围

片段是有范围的,因此只建议相关片段。片段可以通过以下任一方式确定范围:

  1. 片段范围内的语言(可能是所有)
  2. 该项目范围,其片段的作用域(可能是所有)

语言片段范围

根据是否在以下位置定义,每个代码段都适用于一种、几种或所有(“全局”)语言:

  1. 一个语言片断文件
  2. 一个全局性片段文件

单语言用户定义片段在特定语言的片段文件(例如javascript.json)中定义,您可以通过Preferences: Configure User Snippets通过语言标识符访问该文件。片段仅在编辑为其定义的语言时才可访问

多语言和全局用户定义片段都定义在“全局”片段文件(带有文件后缀的JSON .code-snippets)中,也可以通过Preferences: Configure User Snippets 访问。在全局代码段文件中,代码段定义可能有一个附加scope属性,该属性采用一个或多个语言标识符,这使得代码段仅可用于那些指定的语言。如果未提供任何scope属性,则全局代码段可用于所有语言

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

项目片段范围

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

片段语法

body片段可以使用特殊的结构控制插入光标和文字。以下是支持的功能及其语法:

标签

使用制表位(Tab),您可以使编辑器光标在片段内移动。使用$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 打开的工作区或文件夹的路径

插入当前日期和时间:

  • CURRENT_YEAR 本年度
  • CURRENT_YEAR_SHORT 当前年份的最后两位数字
  • CURRENT_MONTH 月份为两位数(例如“02”)
  • CURRENT_MONTH_NAME 月份的全名(例如“七月”)
  • CURRENT_MONTH_NAME_SHORT 月份的简称(例如“Jul”)
  • CURRENT_DATE 一个月中的哪一天
  • CURRENT_DAY_NAME 日期名称(例如“星期一”)
  • CURRENT_DAY_NAME_SHORT 一天的简称(例如“星期一”)
  • CURRENT_HOUR 24 小时制的当前小时
  • CURRENT_MINUTE 当前分钟
  • CURRENT_SECOND 当前秒
  • CURRENT_SECONDS_UNIX 自 Unix 纪元以来的秒数

插入随机值:

  • RANDOM 6位随机 Base-10 数字
  • RANDOM_HEX 6位随机 Base-16 数字
  • UUID V4版本 UUID

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

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

下面的代码片段插入/* Hello World */JavaScript 文件和HTML 文件:

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

变量变换

转换允许您在插入变量之前修改它的值。转换的定义由三部分组成:

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

下面的示例插入当前文件的名称而没有结尾,因此从foo.txt它生成foo。

${TM_FILENAME/(.*)\\..+$/$1/}
  |           |         |  |
  |           |         |  |-> 没有其他选项
  |           |         |
  |           |         |-> 引用第一个捕获组的内容
  |           |
  |           |
  |           |-> 正则捕获文件名的`.后缀名`之前的所有内容
  |
  |
  |-> 得到当前文件名

就是常用的正则:/(.*)\..+$/ 加上一个捕获组。

占位符转换

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

转换示例

这些示例显示在双引号内,因为它们将出现在片段正文中,以说明对某些字符进行双重转义的必要性。示例转换和文件名的结果输出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(扩展的 Backus-Naur 形式)。随着\(反斜线),你可以逃脱$}\。在选择元素中,反斜杠也会转义逗号和管道字符。

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        ::= .*

使用 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参数是JSON用户代码段文件的名称,name从这个文件中的代码段的唯一的名称:

{
  "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(完成列表)中。

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