从零开始配置vim(27)——代码片段

我们之前介绍过缩写相关的内容,缩写是可以自动帮我们将缩写的单词展开成一段完整的话。但是代码本身是结构话的,仅仅使用缩写来配置是无法完成自动生成代码这个步骤的。好在我们大量的插件来进行配置。本篇我们将要来讨论如何使用相关插件来完成代码片段自动完成的功能

vsnip 插件

我们之前在配置自动补全的时候已经下载了 vim-vsnip这个插件。

vsnip是一个非常强大的插件,它支持我们使用与 VS Code 类似的方式来扩展定义我们自己的代码片段,同时它也内置了不同语言版本的代码片段。在之前的配置中我们还加了另外一个 friendly-snippets 。它提供了丰富的已定义好的可以直接使用的代码片段,加快了我们的编码效率。在前面介绍补全的时候我们已经安装并配置了它们。它们的效果如下图所示:

1.gif

自定义代码片段

虽说这些插件预定义了大量的代码片段。但是他们都是通用型的代码片段,总有那么些时候无法满足我们的需求。一个明显的例子就是不同的公司有不同的代码和注释的风格。这个时候就需要我们自定义了。本篇也准备将重点放在如何自定义代码片段上。如果小伙伴们已经有了在 vscode 上自定义代码片段的经历,那么请跳过本篇以节省各位的时间。

入门

下面我们以 C 为例来说明如何自定义代码片段来满足我们的需求。其他语言只是填入的内容不同,在定义上并没有什么大的差别。这里我采用 C 语言一个原因是静态类型的语言更方便的演示其中的各项功能,另一个原因就是我对C/C++ 比较熟悉

首先我们要找到代码片段的配置文件所在位置,这个位置保存在变量 g:vsnip_snippet_dir 中。我们可以通过 :echo g:vsnip_snippets_dir 找到它。

当然也有更简单的办法,我们可以执行 :VsnipOpen 来打开该语言对应的配置文件,如果该文件不存在,命令将创建一个以对应语言名称命名的 json 文件,例如这里它会创建一个 c.json 的文件

这里我们先来写一个最简单的代码片段——自动生成一个 Hello WorldC 程序

"example": {
    "prefix": ["hello"],
    "body": [
        "#include <stdio.h>",
        "int main(int argc, char* argv[])",
        "{",
            "\tprintf(\"hello world\");",
            "\treturn 0;",
         "}"
    ],
    "description": "create a hello world"
}

我们来试试效果,输入 hello 将自动生成一段代码

2.gif

现在我们来看看这些字段都代表什么含义

  • example:它代表该代码段的名称,也可以认为它是一个id,用于标识一个代码片段
  • prefix:用于触发该代码片段,这里也就是我们输入 hello将会触发补全,当选择对应项的时候会调用该代码片段进行补全
  • body:补全时自动生成的代码。它可以是一个字符串或者字符数组。虽然它本身也支持 \r\n来进行换行。但是我更倾向于使用字符数组的形式,每一行是数组中的一个字符串。
  • description :描述信息

使用占位符

如果我们仅仅只能生成像上述 hello world 那样给写死的代码的话,那么它也没什么太大的用处。有时候我们的代码需要生成一个模板,关键地方应该由我们自己进行填充。这个时候可以用到占位符,例如我们使用下面的来生成一个函数

"ifunc": {                                              
  "prefix": ["ifunc"],
  "body": [
    "int $1()",
    "{",
        "\treturn 0;",
    "}"
  ],
  "description": "create a function return int"
  }
}
3.gif

占位符内容可选

我们现在已经可以生成函数了,但是有一个问题摆在我们的面前。函数的返回类型多种多样,如果我们每一个类型都定义一个片段,例如 返回 int 的定义一个 ifunc,返回 float 的定义一个 ffunc。显得多此一举了,代码的重复度太高了。这个时候我们我们给占位符一些预选项以供我们选择。它的语法格式如下

${1|sel1, sel2, sel3,...|}

前面的1代表是第一个占位符。如果是后面的占位符需要提供选项,那么就可以依次类推

例如我们将上述生成函数的代码片段改为

"func": {                                              
  "prefix": ["func"],
  "body": [
    "${1|int,float,double,char,short,*|} $2()",
    "{",
        "\treturn $3;",
    "}"
  ],
  "description": "create a function"
  }
}
4.gif

占位符间跳转

生成函数的代码片段中有3个占位符,其中第一个是可以选的,第二个第三个需要我们手动填写。按照习惯,我们一般使用 <Tab> 键来进行跳转,但是这个时候我们发现它没有用。vsip 有自己的命令来跳转到占位符,因此为了保持使用习惯不变,我们需要定义快捷键

vim.cmd[[imap <expr> <Tab>   vsnip#jumpable(1)   ? '<Plug>(vsnip-jump-next)'      : '<Tab>']]
vim.cmd[[smap <expr> <Tab>   vsnip#jumpable(1)   ? '<Plug>(vsnip-jump-next)'      : '<Tab>']]
vim.cmd[[imap <expr> <S-Tab> vsnip#jumpable(-1)  ? '<Plug>(vsnip-jump-prev)'      : '<S-Tab>']]
vim.cmd[[smap <expr> <S-Tab> vsnip#jumpable(-1)  ? '<Plug>(vsnip-jump-prev)'      : '<S-Tab>']]

由于该插件是使用 vimscript 脚本写的,它还没有提供 lua 的接口,因此这里我也就使用 vimscript 的方式来定义快捷键。

使用变量

使用语法 $name 或者 ${name: default} 可以插入一个变量。如果未设置变量,则会插入其默认值或空字符串。当变量未知(未定义其名称)时,会将插入的变量名称转换为占位符。这里的变量一般是环境变量或者是 vim 自带的一些变量。我们直接拿来用但是在不同的环境下得到的结果是不一样的。

我们可以使用变量来丰富一些信息。例如我们使用下面的代码片段来生成注释

"doc-header": {
    "prefix": ["doc-header"],
    "body": [
        "/**",
        "* @file ${TM_FILENAME}",
        "* @bref ${1}",
        "* @details ${2}",
        "* @date ${CURRENT_YEAR}/${CURRENT_MONTH}/${CURRENT_DATE}",
        "* @commit history:",
        "* \t v${3}: ${4}",
        "*/${0}"
    ],
    "description": "create a doc header"
}

这样我们就生成了一个 .cpp 文件开头的注释了。其中用到了 TM_FILENAME 来表示文件名,使用 CURRENT_YEAR CURRENT_MONTH CURRENT_DATE 来分别获取到年月日。它的效果如下:

5.gif

这里的 ${0} 一般用来截断 Tab键的跳转,也就说遇到 ${0} 之后 <Tab> 键就不再起到跳转到下一个占位符位置这个作用了。

具体有哪些变量可以使用,可以参考 visual studio code 官方给出的文档

本篇主要谈论了该如何定义自己的代码片段。如果想要更完整的内容可以参考 Visual Studio Code 官方的文档。我们也可以从Visual Studio Code 相关代码片段中 Copy 部分来进行使用。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容