Visual Studio Code 中的代码片段

代码片段是可以简化输入重复代码模式(如循环或条件语句)的模板。

在 Visual Studio Code 中,代码片段会与其他建议一起显示在 IntelliSense(⌃Space (Windows, Linux Ctrl+Space))中,也会显示在专门的代码片段选择器(命令面板中的 插入代码片段 (Insert Snippet))中。此外还支持制表符补全:通过 "editor.tabCompletion": "on" 启用它,输入代码片段前缀(触发文本),然后按 Tab 即可插入代码片段。

代码片段语法遵循 TextMate 代码片段语法,但“内插 shell 代码”和 \u 的使用除外;这两者均不受支持。

ajax snippet

内置代码片段

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

builtin javascript snippet

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

从应用商店安装代码片段

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

Searching for extensions with snippets

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

创建你自己的代码片段

你无需任何扩展即可轻松定义自己的代码片段。要创建或编辑你自己的代码片段,请在 文件 (File) > 首选项 (Preferences) 下选择 配置代码片段 (Configure Snippets),然后选择代码片段应在其中显示的语言(通过语言标识符),如果它们应在所有语言中显示,则选择 新建全局代码片段文件 (New Global Snippets file) 选项。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。占位符遍历顺序按数字升序排列,从 1 开始;零是一个可选的特殊情况,始终排在最后,并在指定位置退出代码片段模式并将光标停留在该位置。

文件模板代码片段

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

代码片段作用域

代码片段具有作用域,以便只推荐相关的代码片段。代码片段的作用域可以由以下因素限定:

  1. 代码片段的作用域所针对的语言(可能是全部)
  2. 代码片段的作用域所针对的项目(可能是全部)

语言代码片段作用域

每个代码片段的作用域限定为一种、几种或所有(“全局”)语言,具体取决于它定义在

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

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

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

大多数用户定义的代码片段的作用域限定为单一语言,因此定义在特定于语言的代码片段文件中。

项目代码片段作用域

你还可以拥有一个限定于你的项目的全局代码片段文件(带有文件后缀 .code-snippets 的 JSON)。项目文件夹代码片段是通过 Snippets: Configure Snippets 下拉菜单中的 New Snippets file for '<folder-name>'... 选项创建的,并位于项目根目录下的 .vscode 文件夹中。项目代码片段文件对于与在该项目中工作的所有用户共享代码片段非常有用。项目文件夹代码片段类似于全局代码片段,并且可以通过 scope 属性限定到特定语言。

文件模式作用域

你可以通过使用可选的 includeexclude 属性指定文件模式,来进一步控制代码片段何时出现。这些属性既适用于特定于语言的代码片段文件,也适用于全局代码片段文件,并且可以与 scope 属性结合使用,以便更精确地控制代码片段建议。

  • include - 指定代码片段应出现在哪些文件中的 glob 模式或 glob 模式数组。
  • exclude - 指定代码片段不应出现在哪些文件中的 glob 模式或 glob 模式数组。

模式匹配的工作方式如下

  • 仅文件名模式(例如 *.test.ts)根据文件名进行匹配,而不管文件在项目中的位置如何。
  • 基于路径的模式(例如 **/*.test.ts**/dist/**)针对完整的文件路径进行匹配。
  • 如果文件同时匹配 includeexclude 模式,则 exclude 模式优先。
  • 如果未指定任何属性,代码片段将根据 scope 属性出现在所有适用的文件中。
示例

示例:测试代码片段

此代码片段仅出现在 TypeScript 测试文件中

{
  "Test Block": {
    "prefix": "test",
    "body": ["test('${1:description}', () => {", "\t${0}", "});"],
    "description": "Insert a test block",
    "scope": "typescript",
    "include": ["**/*.test.ts", "**/*.spec.ts"]
  }
}

示例:排除目录

此代码片段出现在所有 JavaScript 文件中,但 distnode_modules 目录中的文件除外

{
  "Console Log": {
    "prefix": "log",
    "body": "console.log(${0});",
    "description": "Insert console.log",
    "scope": "javascript",
    "exclude": ["**/dist/**", "**/node_modules/**"]
  }
}

示例:配置文件代码片段

此代码片段仅使用仅文件名模式出现在 travis.yml 文件中

{
  "Travis CI Node": {
    "prefix": "travis-node",
    "body": ["language: node_js", "node_js:", "  - ${1:18}"],
    "description": "Travis CI Node.js configuration",
    "scope": "yaml",
    "include": ["travis.yml"]
  }
}

使用 includeexclude 模式有助于仅在相关位置显示代码片段,从而减少 IntelliSense 中的杂乱感。

代码片段语法

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

制表符停止位 (Tabstops)

通过制表符停止位,你可以使编辑器光标在代码片段内部移动。使用 $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_MILLISECOND 三位数的当前毫秒数(例如 078
  • CURRENT_SECONDS_UNIX 自 Unix 纪元以来的秒数
  • CURRENT_MILLISECONDS_UNIX 自 Unix 纪元以来的毫秒数
  • CURRENT_TIMEZONE_OFFSET+HH:MM-HH:MM 表示的当前 UTC 时区偏移量(例如 -07:00)。
  • CURRENT_TIMEZONE_NAME 当前时区的 IANA 名称(例如 America/Los_Angeles

用于插入随机值

  • 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' | '/snakecase' | '/kebabcase' '}'
                | '${' 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.jsonPreferences: Open Keyboard Shortcuts File),并添加一个传递 "snippet" 作为额外参数的键盘快捷方式

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

键盘快捷方式将调用 插入代码片段 (Insert Snippet) 命令,但它不会提示你选择代码片段,而是直接插入提供的代码片段。你可以像往常一样使用键盘快捷方式、命令 ID 和可选的启用快捷方式的 when 条件上下文来定义自定义按键绑定

此外,你可以使用 langIdname 参数引用现有的代码片段,而不是使用 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 中删除代码片段吗?

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

Hide from IntelliSense button in Insert Snippet dropdown

你仍然可以使用 插入代码片段 (Insert Snippet) 命令选择该代码片段,但隐藏的代码片段不会显示在 IntelliSense 中。

English 한국어 中文(简体) 中文(繁體)
© . This website operates independently and is not affiliated with or endorsed by Microsoft. All brand names, logos, and trademarks are the property of their respective owners.