代码片段简介 🦉

snippet[ˈsnɪpɪt],或者说「code snippet」,也即代码片段,指的是能够帮助输入重复代码模式,比如循环或条件语句的模板。通过 snippet ,我们仅仅输入一小段字符串,就可以在代码片段引擎的帮助下,生成预定义的模板代码,接着我们还可以通过在预定义的光标位置之间跳转,来快速补全模板。

代码片段配置流程 🐸

首先,进入代码片段设置文件,这里提供了三种方法:

  1. 通过快捷键「Ctrl + Shift + P」打开命令窗口(All Command Window),输入「snippet」,点选「首选项:配置用户代码片段片段」;
  2. 点击界面最左侧竖栏(也即活动栏)最下方的齿轮按钮,在弹出来的菜单中点选「用户代码片段」;
  3. 按下「Alt」键切换菜单栏,通过文件 > 首选项 > 用户代码片段;

接着,在设置文件里补全代码片段。以 Javascript 语言为例,选中后你将打开一个设置文件,javascript.json,在文件头部你会看见一个注释,这其实是一个示例和对它的介绍。你可以试着将第 7~14 行反注释掉(选中后 Ctrl + “/”)。

1
2
3
4
5
6
7
8
9
10
11
12
{
// Place your snippets for javascript here. Each snippet is defined under a snippet name and has a prefix, body and
// description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the
// same ids are connected.
// Example:
"Print to console": {
"prefix": "log",
"body": ["console.log('$1');", "$2"],
"description": "Log output to console"
}
}

这个示例中定义了一个描述为「Print to console」的代码片段,其功能为:在编辑 .js 文件时输入 log 并选中对应代码片段后,可将原文本替换为 console.log(‘’);。

代码片段详细介绍 🦁

语法结构

上一节,你已经接触到了代码片段最简单的功能,而 VSCode 的代码片段引擎所能做的远不止这些。详细地为大家介绍代码片段。

代码片段由四部分组成:

prefix:前缀。代码片段从智能提示中呼出的「关键字」;
scope: 域。代码片段适用的语言;
body:主体。代码片段的「布局与控制」,每个字符串表示一行。
description:描述。代码片段在智能提示中的「介绍」。

Prefix

前缀部分没有什么好介绍的,唯一值得注意的是,前缀支持 N:1,也即允许多条前缀对应同一条代码片段。在使用时,只需将前缀定义为数组即可,数组中的每一个前缀都能对应本代码片段。下面就是一个很简单的示例。

1
2
3
4
5
6
{
"prefix": ["header", "stub", "copyright"],
"scope": "javascript",
"body": "Copyright. Foo Corp 2028",
"description": "Adds copyright..."
}

Scope

scope 的作用是规定该代码片段可以在哪些文件类型中使用。符合条件的文件在编辑时输入 prefix 将出现在智能提示候选列表。

针对语言的代码片段配置文件 scope 不会生效,在全局或者工作区代码片段文件中有效,可设置多种文件类型,中间以英文逗号隔开,如下:

1
2
3
4
5
6
7
8
"插入当前时间": {
"prefix": "now",
"scope":"javascript,typescript,html,vue-html",
"body": [
"2021-02-19 12:40:35"
],
"description": "插入当前时间"
}

Body

基本结构

Body 部分可以使用特殊语法结构,来控制光标和要插入的文本,其支持的基本结构如下

Tabstops:制表符

用「Tabstops」可以让编辑器的指针在 snippet 内跳转。使用 $1$2 等指定光标位置。这些数字指定了光标跳转的顺序。特别地,$0表示最终光标位置。相同序号的「Tabstops」被链接在一起,将会同步更新,比如下列用于生成头文件封装的 snippet 被替换到编辑器上时,光标就将同时出现在所有$1 位置。

1
2
3
"小明今年 $1 岁"
"小红今年 $1 岁"
"小刚今年 $1 岁"

Placeholders:占位符

「Placeholder」是带有默认值的「Tabstops」,如${1:foo}。「placeholder」文本将被插入「Tabstops」位置,并在跳转时被全选,以方便修改。占位符还可以嵌套,例如${1:another ${2:placeholder}}
比如,结构体的代码片段主体可以这样写:

1
"function ${1:functionName}() {\n\t$2\n};"

functionName 一方面可以提供默认的结构名称,另一方面可以作为输入的提示。

Choice:可选项

「Choice」是提供可选值的「Placeholder」。其语法为一系列用逗号隔开,并最终被两个竖线圈起来的枚举值,比如 ${1|one,two,three|}。当光标跳转到该位置的时候,用户将会被提供多个值(one 或 two 或 three)以供选择。

1
"function ${1|functionName,one,two|}() {\n\t$2\n};"

Variables:变量

使用$name${name:default}可以插入变量的值。当变量未赋值时(如),将插入其缺省值或空字符串。 当varibale未知(即,其名称未定义)时,将插入变量的名称,并将其转换为「Placeholder」。可以使用的「Variable」如下:

TM_SELECTED_TEXT:当前选定的文本或空字符串;注:选定后通过在命令窗口点选「插入代码片段」插入。
TM_CURRENT_LINE:当前行的内容;
TM_CURRENT_WORD:光标所处单词或空字符串注:所谓光标一般为文本输入处那条闪来闪去的竖线,该项可定制。单词使用 VSCode 选词(Word Wrap)器选择。你最好只用它选择英文单词,因为这个选择器明显没有针对宽字符优化过,它甚至无法识别宽字符的标点符号。
TM_LINE_INDEX:行号(从零开始);
TM_LINE_NUMBER:行号(从一开始);
TM_FILENAME:当前文档的文件名;
TM_FILENAME_BASE:当前文档的文件名(不含后缀名);
TM_DIRECTORY:当前文档所在目录;
TM_FILEPATH:当前文档的完整文件路径;
WORKSPACE_NAME:当前工作目录的名称(而非完整路径);
CLIPBOARD:当前剪贴板中内容。

此外,还有一些用于插入当前时间的变量,这里单独列出:
CURRENT_YEAR: 当前年份;
CURRENT_YEAR_SHORT: 当前年份的后两位;
CURRENT_MONTH: 格式化为两位数字的当前月份,如 02;
CURRENT_MONTH_NAME: 当前月份的全称,如 July;
CURRENT_MONTH_NAME_SHORT: 当前月份的简称,如 Jul;
CURRENT_DATE: 当天月份第几天;
CURRENT_DAY_NAME: 当天周几,如 Monday;
CURRENT_DAY_NAME_SHORT: 当天周几的简称,如 Mon;
CURRENT_HOUR: 当前小时(24 小时制);
CURRENT_MINUTE: 当前分钟;
CURRENT_SECOND: 当前秒数;
CURRENT_SECONDS_UNIX:Unix 时间戳。

此外,还有一些用于插入行/块注释的变量,其将根据当前文件的语言模式自动调整:
BLOCK_COMMENT_START 块注释上半段,输出示例:
PHP: /*
HTML:<!--
BLOCK_COMMENT_END 块注释下半段,输出示例:
PHP: _/
HTML: -->
LINE_COMMENT 行注释,输出示例:
PHP://

变量转换

变量转换可将变量的值格式化处理后插入预定的位置。

语法结构

我们可以通过 ${var_name/regular_expression/format_string/options} 插入格式化后的代码片段。显然,「variable transformations」由 4 部分构成:
var_name:变量名;
regular_expression:正则表达式;
format_string:格式串;
options:正则表达式匹配选项。

format_string

根据其 EBNF 范式,我们可以知道 format_string 其实是 format 或 text 的线性组合:
text:也即没有任何作用的普通文本,你甚至可以使用汉字;
format:格式串,分为 7 种:

  1. $sn:表示插入匹配项;
  2. ${sn}:同 $sn
  3. ${sn:/upcase}${sn:/downcase}${sn:/capitalize}:表示将匹配项变更为「所有字母均大写/所有字母均小写/首字母大写其余小写」后,插入;
  4. ${sn:+if}:表示当匹配成功时,并且捕捉括号捕捉特定序号的捕捉项成功时,在捕捉项位置插入「if」所述语句;
  5. ${sn:?if:else}:表示当匹配成功,并且捕捉括号捕捉特定序号的捕捉项成功时,在捕捉项位置插入「if」所述语句;否则当匹配成功,但当捕捉括号捕捉特定序号的捕捉项失败时,在捕捉项位置插入「else」所述语句;
  6. ${sn:-else}:表示当匹配成功,但当捕捉括号捕捉特定序号的捕捉项失败时,在捕捉项位置插入「else」所述语句;
  7. ${sn:else}:同 ${sn:-else}

下面介绍一个简单的例子,帮助大家理解「variable transformations」。
假设有一个名为「demo.js」的文件中,并且我们已经定义如下 snippet。

1
2
3
4
5
6
"插入文件名函数": {
"prefix": "fileNameFunction",
"body": [
"function ${1:${TM_FILENAME/(.*)\\.js$/${1:/capitalize}/i}}Function() {\n\t$2\n}\n//$1 函数"
],
},

其中最复杂的模式为${1:${TM_FILENAME/(._)\\.js$/${1:/capitalize}/i}},我们将之拆解为如下五部分:

${1:...}:嵌套的 placeholder
${TM_FILENAME/.../.../.}:「variable transformations」中的「var*name」,表示带后缀的文件名;
${.../(.*)\\.js$/.../.}:「variable transformations」中的「regular_expression」,表示匹配任意以「.js」为后缀的字符串;
${.../.../${1:/capitalize}/.}}:「variable transformations」中的「format_string」,表示将第一个捕捉项第一个字符替换为大写的;
${.../.../.../i}:「variable transformations」中的「options」,表示无视大小写。

编辑器配置 🐣

自定义的代码片段在智能提示的时候优先度较低,好在编辑器为我们提供了相关的配置。

在设置中加入下列代码,或者直接在设置中搜索相关配置修改,自定义代码片段将出现在智能提示候选列表的最上面。

1
"editor.snippetSuggestions": "top"

在 markdown 文件中,代码提示会被禁用,可以针对语言开启代码提示:

1
2
3
"[markdown]": {
"editor.quickSuggestions": true
}

编辑器默认情况下,光标处于占位符内时,无法触发新的智能提示,添加以下配置,可以嵌套触发

1
"editor.suggest.snippetsPreventQuickSuggestions": true

 引用

https://code.visualstudio.com/docs/editor/userdefinedsnippets
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/RegExp
https://blog.csdn.net/maokelong95/article/details/54379046