编写代码的痛点
你是一位程序员,三年代码十万行,号称自身早已精通一套 Ctrl+C/V
组合拳,走遍天下都不怕!但每当深夜来临,你又心生不甘,觉得自己天资聪颖,怎可在这些无甚大用的重复字符上虚度光阴。自己是干大事的!自己的时间是无比珍贵的!
你痛下决心,要掌握降龙十八掌此般武艺,彻底摆脱被 Ctrl+C/V
操弄的命运!
提高撸码效率的方式
经过你的仔细研究,你发现现今世界上已经存在了如下这些高效率方案:
- AI 直接生成 —— 这个有点用。但自己仍需要编写绝大部分代码呢,还是看看其他方案吧。
- 代码工程化 —— 这个很有用。主是把公共的代码都抽象出来,需要用到时通过代码引用的方式引入。另外也包括使用一些预处理方案(例如用来表示 HTML 的
Pug
)来减少代码量。 - 模板生成器 —— 这个很有用。例如
plop
这种微型生成器框架,通过命令行窗口输入简短命令的方式,直接生成带有模板内容的代码文件。 - 编辑器插件 —— 这个很有用。其实就是使用别人编写好的模板代码插入方案(如
Emmet
),能帮助提高编码效率,总归是好的。 - 版本管理器 —— 这个很有用。特别是出于某些不可明说的原因需要使用以前版本的代码时。不过作为一个敲码三年的程序员,早就掌握 Git、
Svn
啦! - Snippets —— 这个也很有用呢。通过给编辑器添加一些必要的配置,在工作区输入提示词后即能选择配置中的代码模板。
- ……
为何要掌握 Snippets
因为 Snippets 是程序员最快提升编码速度的利器。像代码工程化、模板生成器,需要系统化地学习后,才能发挥足够的生产力。编辑器插件,则存在切换语言或环境后会找不到提低方案的窘境。几乎所有的代码编辑器都支持 Snippets,而 VSCode 在登录后更是能把 Snippets 同步到云端来实现异地共用,所以大可放心使用。
Snippets 的优点
- 编辑器内置支持,可指定性较高,能编写符合自己风格的代码模板;
- 作为一种实质上的文本模板,能被几乎所有的编程语言所用;
- 简洁高效,只需要掌握少量的知识点,就能编写出强大的代码模板;
- 可根据使用者自身的编码习惯定制提示词,让模板的引用适应程序员,而不是让程序员适应模板的引用方法。
Snippets 的不足
- 不能制作出一些特殊的模板,例如像 IDEA 那样的提示词转代码:
variable.log
->console.log(variable)
; - 纯手写 Snippets 配置时,需要考虑各种转义字符。不过已经有跨编辑器解决方案;
- 如果需要编写一些极其通用的模板,则需要精通正则表达式才可以,而且写出的模板看起来很复杂,维护难度较高。
Snippets 的关键知识点
这里以 VSCode 的 Snippets 为例,具体可参考官方文档。
编辑器如何打开 Snippets ?
- 首先编辑器中的配置项
"editor.tabCompletion": "on"
是必需的。 - 在编辑器左下角选择
管理(Manage)
->用户代码片段(User Snippets)
->编程语言名称或全局.json
,即可以进入 Snippets 编写界面。 - VSCode 内置了大量的 Snippets 模版,如
for
、foreach
、function
、trycatch
等,我们声明模板前缀时尽量避开这些名称。
每个模板的结构是怎样的?
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
处,并且弹出选择框,让程序员选择Hello
、World
、!
中的其中一项来填充到$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
: 当前月份,不足两位在在前方补 0CURRENT_MONTH_NAME
: 当前月的完整英文名称CURRENT_MONTH_NAME_SHORT
: 当前月的英文名称简写(通常是三个字母)CURRENT_DATE
: 今天是当前月的第几天,不足两位在在前方补 0CURRENT_DAY_NAME
: 今天是星期几,显示英文名称CURRENT_DAY_NAME_SHORT
: 今天是星期几,显示英文名称简写(通常是三个字母)CURRENT_HOUR
: 现在是二十四小时制的第几个小时,不足两位在在前方补 0CURRENT_MINUTE
: 现在是当前小时的第几分钟,不足两位在在前方补 0CURRENT_SECOND
: 现在是当前分钟的第几秒,不足两位在在前方补 0CURRENT_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 就是上面的
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 正则选项,如
i
、g
等
有了以上的基础,我们就可以通过案例来进一步理解如何编写极其实用的代码模板了!
Snippets 的案例一
Snippets 的案例二
Snippets 的案例三
本人编写 Vue3 页面的风格如下:
- 每个页面文件都用一个文件夹包裹着
- 页面文件直接使用 index.vue 命名
- 每个页面都必须标记上作者、生成日期、页面描述
- 页面在 Vue3 的识别名采用父级文件夹的名称
- 页面根节点的类名采用父级文件夹的名称的全小写
最终生成的模板格式如下:
可以看到:由于没有直接引用父级目录名称的变量,所以这里采用了 ${TM_DIRECTORY/(.*\\\\)//}
来把父级目录的路径清除(format
为空表示替换的内容为空)。
另外,由于构建正则符号 \
时需要转义,所以正则字面量中需要出现 \\
,而在 body 字符串中,生成正则字面量前,也需要为 \
转义,所以匹配一个 \
,就需要共四个即 \\\\
来构建 format
。
其他部分如果不理解,那么你应当回到文章开头继续学习一遍。
原文链接:https://juejin.cn/post/7398231828220723215