Skip to content

使用VSCode自定义Snippet功能提升编码效率

Published: at 13:51

TOC

背景

日常开发中很多代码是模式高度一致的或重复的,对于这些代码片段,往往会到 VSCode 商店中寻找各种 Snippet 插件。然而 VSCode 和插件提供的 Snippet 很可能不符合日常使用和记忆的习惯,或者干脆并没有插件能提供想要的代码片段。

对于这些重复的内容,从 import 到生命周期方法到整个组件,都可以通过 VSCode 的自定义 Snippet 功能实现快速输入。目前运营后台的表格和弹窗都是通过 Snippet 快速生成的。

本文介绍了 VSCode 中自定义 Snippet 的基本姿势,期望能让更多人能够通过这种方式提升编码效率。

配置文件

VSCode 的 Snippet 存储在一系列 json 文件中,一般通过「CMD + Shift + P」快捷键打开 Command Palette 快速搜索配置项,从而进行代码片段的管理。 CMD+Shift+P

分类

选择「首选项: 配置用户代码片段」后,将显示以下创建和管理代码片段的入口

首选项: 配置用户代码片段

可以看到,配置文件主要分为几种:

数据结构

代码段的配置包含几个部分:

一个最基本的例子如下:

// globalOrProjectLevel.code-snippet
{
  "Print to console": {
    "scope": "javascript,typescript",
    "prefix": "log",
    "body": ["console.log('$1');", "$2"],
    "description": "Log output to console"
  }
}

其中 Print to console 仅用于标识配置。

语法

Tab Stops

在 Snippet 中,可以通过 ${number} 形式定义光标位置,如 $1 代表初始光标位置,$2 代表在 $1 处输入完成后按 tab 光标将会到达的位置。同样序号的 TabStop 还能存在多个,他们将同时产生多个光标。 特殊的,$0 代表光标最终的位置。

Placeholders

Placeholder 是带默认值的 Tab Stop,通过类似 ${1:text} 的形式定义。Placeholder 的文本将显示在 TabStop 处,并默认选中,可以快捷的编辑或者干脆按 tab 使用默认值。

{
  "For_Loop": {
    "prefix": "for",
    "scope": "javascript,typescript",
    "body": ["for (const ${2:element} of ${1:array}) {", "\t$0", "}"],
    "description": "For Loop"
  }
}

Choice

有时候我们想提供几个选项,而不是一个默认值,此时可以使用 Choice。Choice 的格式为 ${1|one,two,three|},在光标处于该位置时,编辑器将提供对应的选项供使用者选择。 Choice

Comment

Snippet 中还支持根据文件类型插入注释符号。可以使用 BLOCK_COMMENT_STARTBLOCK_COMMENT_END 插入多行注释或用 LINE_COMMENT 加入单行注释。以下是官方给的例子,在 js 文件中将插入 /* Hello World */ 而在 HTML 文件中将插入 <!-- Hello World -->

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

Variables

Snippet 中支持通过 $varName 或者 ${varName:defaultText} 的形式使用内置的一些变量,包括当前选择的内容、当前文件路径、时间、剪切板内容等。 可用的变量列表可参考官方文档中的相应章节。

Variables Transforms

内置变量的格式很可能不是我们想要的,或者我们只需要提取出其中一部分,此时可以使用对变量进行一定的转换。 格式分为变量名、正则表达式、替换字符串、正则选项几部分:

${TM_FILENAME/(.*)\\..+$/$1/}
  |            |         | |
  |            |         | |-> 正则的选项,此处没有
  |            |         |
  |            |         |-> 指代匹配中的第一个group
  |            |
  |            |
  |            |-> 匹配除了后缀之前的内容
  |
  |
  |-> 内置变量,将解析为当前文件名

上面官方文档中的一个例子,将 foo.txt 变为 foo 插入到代码中。 此外我常用的转换还有:

//显示当前文件所在文件夹名,适用于在ComponentName/index.ts内插入ComponentName
${TM_DIRECTORY/.*\\/(.+)$/${1}/}

// 文件名转换,用于将文件名从kebab-case转化为PascalCase
// declare-file.d.ts => DeclareFile
${TM_FILENAME_BASE/(-|^)(\\w+)(\\..+)?/${2:/capitalize}/g}

Placeholder Transforms

Placeholder Transforms 和变量的转换一致,不过读取的不是内置变量而是你的输入。 此外,标号相同的 TabStop 都可以有不同转换方式。如下面的 snippet 中,在光标处于 $1 处时输入 foo 将在两行分别打出 Foo 和 foo。

{
  "test": {
    "prefix": "test",
    "description": "测试Placeholder Transforms",
    "body": ["${1/^(.+)$/${1:/capitalize}/}", "${1/^(.+)$/$1/}"]
  }
}

进阶

总结

优点

缺点

Reference