VSCode snippets 如何帮助我们提高开发效率

编写代码的痛点

你是一位程序员,三年代码十万行,号称自身早已精通一套 Ctrl+C/V 组合拳,走遍天下都不怕!但每当深夜来临,你又心生不甘,觉得自己天资聪颖,怎可在这些无甚大用的重复字符上虚度光阴。自己是干大事的!自己的时间是无比珍贵的!

你痛下决心,要掌握降龙十八掌此般武艺,彻底摆脱被 Ctrl+C/V 操弄的命运!

提高撸码效率的方式

经过你的仔细研究,你发现现今世界上已经存在了如下这些高效率方案:

  • AI 直接生成 —— 这个有点用。但自己仍需要编写绝大部分代码呢,还是看看其他方案吧。
  • 代码工程化 —— 这个很有用。主是把公共的代码都抽象出来,需要用到时通过代码引用的方式引入。另外也包括使用一些预处理方案(例如用来表示 HTML 的 Pug)来减少代码量。
  • 模板生成器 —— 这个很有用。例如 plop 这种微型生成器框架,通过命令行窗口输入简短命令的方式,直接生成带有模板内容的代码文件。
  • 编辑器插件 —— 这个很有用。其实就是使用别人编写好的模板代码插入方案(如 Emmet),能帮助提高编码效率,总归是好的。
  • 版本管理器 —— 这个很有用。特别是出于某些不可明说的原因需要使用以前版本的代码时。不过作为一个敲码三年的程序员,早就掌握 GitSvn 啦!
  • Snippets —— 这个也很有用呢。通过给编辑器添加一些必要的配置,在工作区输入提示词后即能选择配置中的代码模板。
  • ……

为何要掌握 Snippets

因为 Snippets 是程序员最快提升编码速度的利器。像代码工程化、模板生成器,需要系统化地学习后,才能发挥足够的生产力。编辑器插件,则存在切换语言或环境后会找不到提低方案的窘境。几乎所有的代码编辑器都支持 Snippets,而 VSCode 在登录后更是能把 Snippets 同步到云端来实现异地共用,所以大可放心使用。

Snippets 的优点

  1. 编辑器内置支持,可指定性较高,能编写符合自己风格的代码模板;
  2. 作为一种实质上的文本模板,能被几乎所有的编程语言所用;
  3. 简洁高效,只需要掌握少量的知识点,就能编写出强大的代码模板;
  4. 可根据使用者自身的编码习惯定制提示词,让模板的引用适应程序员,而不是让程序员适应模板的引用方法。

Snippets 的不足

  1. 不能制作出一些特殊的模板,例如像 IDEA 那样的提示词转代码:variable.log -> console.log(variable)
  2. 纯手写 Snippets 配置时,需要考虑各种转义字符。不过已经有snippet generator
  3. 如果需要编写一些极其通用的模板,则需要精通正则表达式才可以,而且写出的模板看起来很复杂,维护难度较高。

Snippets 的关键知识点

这里以 VSCode 的 Snippets 为例,具体可参考Snippets in Visual Studio Code

编辑器如何打开 Snippets ?

  • 首先编辑器中的配置项 "editor.tabCompletion": "on" 是必需的。
  • 在编辑器左下角选择 管理(Manage) -> 用户代码片段(User Snippets) -> 编程语言名称或全局.json,即可以进入 Snippets 编写界面。
  • VSCode 内置了大量的 Snippets 模版,如 forforeachfunctiontrycatch 等,我们声明模板前缀时尽量避开这些名称。

每个模板的结构是怎样的?

  • key: 模板对象在当前 JSON 中的唯一标识,即 key 可以是任意的唯一的字符串。下面则是 key 所指向的对象的各个属性。
    • scope: String,作用范围,多个可用英文版逗号分隔,如 "javascript,html"。省略则表示支持所有语言。
    • prefix: String|[String],提示词,是工作区输入关键词后触发模板的入口。
    • body: String|[String],模板内容,使用字符串数组时,每个字符串元素表示一行。
    • description: String,描述当前模板用途的文案,可省略。

Snippet 具体语法有哪些?

  • Tabstops: Tab 键跳转的断点,如 $1$2……,另外 $0 表示最后一个 Tab 落脚点。另外 ${1} 等价于 $1
  • Placeholders: Tab 键断点默认的填充串,如 ${1:Hello World!},工作区出现模板内容后,鼠标落脚点定格在 $1 处,而且选中了 Hello World! 这段文字。程序员可以按下 Tab 跳过(即采用默认文本),或者输入内容来替换掉 Hello World!,然后再按 Tab 键跳到下一个落脚点。
  • Choice: Tab 键断点处的选项,如 ${1|Hello,World,!|},工作区出现模板内容后,鼠标落脚点定格在 $1 处,并且弹出选择框,让程序员选择 HelloWorld! 中的其中一项来填充到 $1 处。
  • Variables: Tab 键断点处使用变量的值作为默认填充,如 $name${name:default},前者如果未赋值,则在断点处插入空字符串,后者如果未赋值,则在断点处插入 default 字符串。如果 $name 是未定义的,那么 name 将会作为默认文本填充到断点处。内置的已定义变量包括:
    • TM_SELECTED_TEXT: 键入关键词前选中的文本(如果没有选中文件直接键入则为空字符串)
    • TM_CURRENT_LINE: 当前行的内容,不包括正在键入的提示词部分。触发后不会替换掉已存在的内容,而是在当前行内容和键入的提示词之间插入模板内容
    • TM_CURRENT_WORD: 光标所位于的单词的内容,或者空字符串
    • TM_LINE_INDEX: 从 0 开始计数,当前文档总行数
    • TM_LINE_NUMBER: 从 1 开始计数,当前文档总行数
    • TM_FILENAME: 当前文档的文件名,包括后缀部分
    • TM_FILENAME_BASE: 当前文档的文件名,不包括后缀部分
    • TM_DIRECTORY: 当前文档的所在目录,是个绝对地址
    • TM_FILEPATH: 当前文档的文件路径,是个绝对地址
    • RELATIVE_FILEPATH: 当前文档的相对于 VSCode 所打开的工作区或文件夹的路径,是个相对地址
    • CLIPBOARD: 你的粘贴板中当前的内容,就是你刚刚复制的文本
    • WORKSPACE_NAME: VSCode 所打开的工作区或文件夹的名称,仅仅是名称
    • WORKSPACE_FOLDER: VSCode 所打开的工作区或文件夹的绝对路径,包括自身的名称
    • CURSOR_INDEX: 从 0 开始计数,当前属于第几个在闪的光标
    • CURSOR_NUMBER: 从 1 开始计数,当前属于第几个在闪的光标
    • CURRENT_YEAR: 当前年份
    • CURRENT_YEAR_SHORT: 当前年份的最后两位数字
    • CURRENT_MONTH: 当前月份,不足两位在在前方补 0
    • CURRENT_MONTH_NAME: 当前月的完整英文名称
    • CURRENT_MONTH_NAME_SHORT: 当前月的英文名称简写(通常是三个字母)
    • CURRENT_DATE: 今天是当前月的第几天,不足两位在在前方补 0
    • CURRENT_DAY_NAME: 今天是星期几,显示英文名称
    • CURRENT_DAY_NAME_SHORT: 今天是星期几,显示英文名称简写(通常是三个字母)
    • CURRENT_HOUR: 现在是二十四小时制的第几个小时,不足两位在在前方补 0
    • CURRENT_MINUTE: 现在是当前小时的第几分钟,不足两位在在前方补 0
    • CURRENT_SECOND: 现在是当前分钟的第几秒,不足两位在在前方补 0
    • CURRENT_SECONDS_UNIX: 现在距离 1997年01月01日 00:00:00 有多少毫秒
    • CURRENT_TIMEZONE_OFFSET: 当前地区与 UTC 标准 0 时区相差多少时间,格式为 [+-]HH:MM
    • RANDOM: 一个六位的十进制随机数
    • RANDOM_HEX: 一个六位的十六进制随机数
    • UUID: 一个第 4 版的 UUID 串
    • BLOCK_COMMENT_START: 块级注释起始部分,例如在 JavaScript 文件中是 /*,在 HTML 中则是 <!--
    • BLOCK_COMMENT_END: 块级注释结尾部分,例如在 JavaScript 文件中是 */,在 HTML 中则是 -->
    • LINE_COMMENT: 行级注释,例如在 JavaScript 文件中是 //

Snippets 最强大的武器是什么?

当然是 EBNF 中的转换结构!,标准格式如下:

${variable/regex/format/options}
  • variable 就是上面的 Variables 中的其中一个;
  • regex 则是一个标准的 JavaScript 正则字面量;
  • format 则可以是普通的文本,也可以是一个正则结果变量与文本的结合:
    • $0 表示整个正则匹配到的完整内容
    • $1 表示第一个捕获组匹配到的内容
    • $2 表示第二个捕获组匹配到的内容
    • ……
    • $9 也可能不存在第九个捕获组,那么它就是空字符串。由此我们可知,在 format 中,$0 ~ $N 不会表示 Tab 断点,而是表示正则匹配的结果集。这是重点,务必牢记。另外,这里捕获结果的内容还可以进一步处理,就拿当前 $9 为例:
      • ${9:/downcase} 表示把第九个捕获组匹配到的内容全部转换为小写
      • ${9:/upcase} 表示把第九个捕获组匹配到的内容全部转换为大写
      • ${9:/capitalize} 表示把第九个捕获组匹配到的内容转换为首字母大写的形式
      • ${9:/camelcase} 表示把第九个捕获组匹配到的内容转换为驼峰形式
      • ${9:/pascalcase} 表示把第九个捕获组匹配到的内容转换为帕斯卡形式
  • options 就是 JavaScript 正则选项,如 ig

有了以上的基础,我们就可以通过案例来进一步理解如何编写极其实用的代码模板了!

Snippets 的案例一

{
    // 这是一个立即执行函数模板
    // 当你选中一行或多行代码后
    // 再输入 iife 并选择本模板
    // 选中的代码内容会自动成为立即执行函数的函数体并默认选中
    // 你可以快速保留或替换这些选中的内容
    "iife": {
        "prefix": "iife",
        "body": [
            "(function () {",
            "\t${1:$TM_SELECTED_TEXT}",
            "}());",
            "$0"
        ],
        "description": "立即执行函数包装选中的代码"
    },
}

Snippets 的案例二

{
    // 这是一个打印变量的模板
    // 你需要先复制一个变量名如 age
    // 然后在新的一行输入 logv 并选择本模板
    // 然后该行就会生成一行代码,如 `console.log('age: ', age);`
    "logv": {
        "prefix": "logv",
        "body": [
            "console.log('${CLIPBOARD}: ', ${CLIPBOARD});$0"
        ],
        "description": "打印粘贴板上的变量"
    },
}

Snippets 的案例三

本人编写 Vue3 页面的风格如下:

  • 每个页面文件都用一个文件夹包裹着
  • 页面文件直接使用 index.vue 命名
  • 每个页面都必须标记上作者、生成日期、页面描述
  • 页面在 Vue3 的识别名采用父级文件夹的名称
  • 页面根节点的类名采用父级文件夹的名称的全小写

最终生成的模板格式如下:

{
    "vue3page": {
        "prefix": "vue3page",
        "body": [
            "<script setup>",
            "/**",
            " * @author ZhongyiChen",
            " * @date ${CURRENT_YEAR}-${CURRENT_MONTH}-${CURRENT_DATE}",
            " * @description $1",
            " */",
            "defineOptions({",
            "\tname: '${2:${TM_DIRECTORY/(.*\\\\)//}}'",
            "})",
            "</script>",
            "",
            "<template>",
            "\t<${4:section} class=\"${3:${TM_DIRECTORY/.*\\\\([^\\\\]*)$/${1:/downcase}/}}\">",
            "\t\t$5",
            "\t</${4:section}>",
            "</template>",
            "",
            "<style lang=\"scss\">",
            ".${3:${TM_DIRECTORY/.*\\\\([^\\\\]*)$/${1:/downcase}/}}{$6",
            "}",
            "</style>",
            "$0"
        ],
        "description": "新增一个 Vue3 的模板页面"
    },
}

可以看到:由于没有直接引用父级目录名称的变量,所以这里采用了 ${TM_DIRECTORY/(.*\\\\)//} 来把父级目录的路径清除(format 为空表示替换的内容为空)。

另外,由于构建正则符号 \ 时需要转义,所以正则字面量中需要出现 \\,而在 body 字符串中,生成正则字面量前,也需要为 \ 转义,所以匹配一个 \,就需要共四个即 \\\\ 来构建 format

其他部分如果不理解,那么你应当回到文章开头继续学习一遍。

写在最后

写这篇文章,花了我两个晚上。希望对你有用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值