Vim Latex 的使用和配置技巧 (四): 用 snippet 编辑 latex 文档

前几天, 在知乎上看到一篇文章:

1700页数学笔记火了!全程敲代码,速度飞快易搜索,硬核小哥教你上手LaTeX+Vim.

文章中的外国小哥, 用vim编辑latex, 甚至可以做到与板书同步. 这是怎么做出来的呢? 除了我之前提到的vim-latex-suite插件和vimtex插件, 还有一个强力插件: snippet!

snippet和UltiSnips的安装

用 vim-plug 插件管理器的话, 可以用下面几行代码安装 UltiSnips 插件:


Plug 'sirver/ultisnips'

Plug ‘honza/vim-snippets’

let g:UltiSnipsExpandTrigger = '<tab>'

let g:UltiSnipsJumpForwardTrigger = '<tab>'

let g:UltiSnipsJumpBackwardTrigger = '<s-tab>'

" If you want :UltiSnipsEdit to split your window.

let g:UltiSnipsEditSplit="vertical"

我们解释一下这几个命令:

1. Plug 'sirver/ultisnips’: 加载插件.

2. Plug ‘honza/vim-snippets’: 加载vim-snippets插件. 这个插件提供了很多默认snippet命令.

2. let g:UltiSnipsExpandTrigger = '<tab>’: 用<tab>展开片段代码.

3. let g:UltiSnipsJumpForwardTrigger = '<tab>’: 用<tab>跳到下一个位置.

4. let g:UltiSnipsJumpBackwardTrigger = '<s-tab>': 用shift+<tab>跳到上一个位置.

将上述代码复制到你的~/.vimrc文件中的plug代码管理区, 用:so %重新加载一下, 然后用:PlugInstall命令安装插件. 重启vim, 即可使用.

默认的代码块存到哪里了呢? 比如, 我的插件安装在~/.vim/plug 文件夹下, 那么, 在这个文件夹里, 又一个叫做vim-snippets/UltiSnips的命令, 在这里, 找到tex.snippets文件, 打开, 就可以看到许多自定义的snippet命令. 以这些为例, 可以自己写出自己想要的snippet代码块.

另外多说一句, 可以参考neocomplete等补全插件配合snippet使用, 效果更佳.

几个自带的代码块的讲解

1. enumerate 环境:

tex.snippets中, 我们找到了这么几行:


snippet enum "Enumerate" b

\begin{enumerate}

\item $0

\end{enumerate}

endsnippet

如果定义了这个, 在tex文本中, 输入 enum, 在自动补全插件的作用下, 会出现

image

那么, 这时按一下<tab>键, 就可以得到

image

神不神奇? 意不意外?

在这里, 我们解释一下snippet的定义. 下面是一个基本结构:


snippet Tab_trigger "Description" b

endsnippet

是一个基本格式.

Tab_trigger 就是你要输入的东西, 比如上面例子里的enum.

在引号里, 也就是这里的Description部分, 你可以写一下这个片段代码的功能, 比如在enum的例子里, 它会显示, 说这是Enumerate.

后面一个东西 b, 是这个片段代码的选项. 这里, 共有下面几个选项:

选项 | 解释

---|---

b | 只有当 trigger在行首才有效

i | 默认情况下, trigger是自成一个单词才有用. 加了这个选项, 即使是在单词中, 只要出现了这几个字母, 就可以使用.
比如 aaatrigger, 也可以使用.

w | 与 i 相反, 只有是一个单词(前面是空格) 才可以使用.

r | 支持正则表达式

t | 在这里, <tab>的其他功能失效, 就当成空格使用.

A | trigger不需要按<tab>就可以直接展开.

lp 代码块

下面看接下来的一个代码块:


snippet lp "Long parenthesis"

\left(${1:${VISUAL:contents}}\right)$0

endsnippet

这里没有任何选项, 那就是默认. 这里我们看到有两个东西: $1$0.

1指的是片段展开之后, 光标所在的位置, 那么如果有`2, 按<tab>`, 就可以跳到下一个. $0就是最后都跳完了, 光标所在的位置. 这样可以很快地跳出一些环境.

${VISUAL:contents}: 是指, 光标在这里时, content是显示出来的. 如图所示:

image

begin end 代码块

看看下面这个:


snippet "b(egin)?" "begin{} / end{}" br

\begin{${1:something}}

${0:${VISUAL}}

\end{$1}

endsnippet

我们看到, 选项部分有br, 是说1. 只有在行首才有用; 2. 使用了正则表达. 那么我们看到, 这里, triggle 部分加了单/双引号, 这也正是正则表达的规则: 要加单/双引号.

b(egin)? 什么意思呢? 就是说, 或者只输入了b, 或者输入begin, 都能用这个代码块展开. 在自动补全插件的帮助下, 如图:

image
image

这里, 光标落在$1处, 并默认显示了something.

我们注意到, 在代码区, 有两个$1, 那么就是说, 只要我们在\begin部分输入了somethingelse, 那么在\end区, 也自动有somethingelse. 那么继续<tab>, 就可以跳到中间区域, 开心写环境里的东西了.

image

不过, 我建议可以改成这样:


snippet "b(egin)?" "begin{} / end{}" br

\begin{${1:something}}

${2:${VISUAL}Write your words here}

\end{$1}$0

这样一来, 继续tab, 就可以跳出区域了. 这时, 也可以配合latex-suite插件使用, 在$0处换成<++>, 这样, 用<Ctrl-J>就可以跳出环境了.

X_1 代码块


snippet '([A-Za-z])([\d])' "auto subscript" wrA

`!p snip.rv = match.group(1)`_`!p snip.rv = match.group(2)`

endsnippet

这里, 我们看到, 选项部分是wrA. A, 代表自动展开. 同样地, 我们用到了正则表达式.

在代码区, 我们还看到了有snip.rv. 这时用了python的情况. !p snip.rv = 这后面就是要输出的部分.

在trigger里, 我们看到两个括号, 一个是([a-z]), 另一个是([\d]), 这是正则表达式, a-zA-Z代表所有大小写字母, \d代表数字. 按照括号的顺序, 可以分出两个部分, 第一个就叫match.group(1), 第二个就叫match.group(2). 从code里看出, 这两个代码块用_下划线连接了.

那么好, 如果我们用了这个代码块, 输入x1, 就会自动输出x_1.

如果在数学公式环境里, 这么自动展开还可以, 在非数学模式, 这么做显然有很多不便. 那么可以规定数学环境吗? 答案是可以.

math 环境

我们定义math 环境如下, 并把这段代码放在snippets文档的开头部分.


global !p

texMathZones = ['texMathZone'+x for x in ['A', 'AS', 'B', 'BS', 'C',

'CS', 'D', 'DS', 'E', 'ES', 'F', 'FS', 'G', 'GS', 'H', 'HS', 'I', 'IS',

'J', 'JS', 'K', 'KS', 'L', 'LS', 'DS', 'V', 'W', 'X', 'Y', 'Z']]

texIgnoreMathZones = ['texMathText']

texMathZoneIds = vim.eval('map('+str(texMathZones)+", 'hlID(v:val)')")

texIgnoreMathZoneIds = vim.eval('map('+str(texIgnoreMathZones)+", 'hlID(v:val)')")

ignore = texIgnoreMathZoneIds[0]

def math():

synstackids = vim.eval("synstack(line('.'), col('.') - (col('.')>=2 ? 1 : 0))")

try:

first = next(

            i for i in reversed(synstackids)

            if i in texIgnoreMathZoneIds or i in texMathZoneIds

        )

return first != ignore

except StopIteration:

return False

endglobal

定义好了以后, 在上面的代码前加上一行, 变成:


context "math()"

snippet '([A-Za-z])([\d])' "auto subscript" wrA

`!p snip.rv = match.group(1)`_`!p snip.rv = match.group(2)`

endsnippet

这样一来, 刚才那个片段代码, 就只有在数学公式的模式下才有用了.

在哪新加snippets命令?

那位说了, 你讲了这么多, 在哪里添加自定义的命令呢?

1. 你可以在刚才说的tex.snippets文档里添加. 但是, 这样做是有风险的, 改动了自带的文档, 当那个插件更新时, 你的自定义命令可以就被覆盖了. (别问我是怎么知道的, 谢谢. )

2. 可以建一个文档: ~/.vim/UltiSnips/tex.snippets. 你的新定义的代码块放在这里, 就可以放心用了.

3. [推荐]通过:UltiSnipsEdit 命令. 这是插件自带的一个命令, 运行它, 便可以出现这样的画面:

image

在另一个标签页, 出现你的本地snippets文件, 在这里编辑, 保存之后, 就可以回到右面的窗口开心继续texing了.

本文是我自己使用snippets插件编辑latex的一些经验和心得, 部分参考了这篇文章: 1700页数学笔记火了!全程敲代码,速度飞快易搜索,硬核小哥教你上手LaTeX+Vim. 欢迎各位批评指正, 谢谢!

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

推荐阅读更多精彩内容