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

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

.

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

1. 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命令.
  3. let g:UltiSnipsExpandTrigger = '<tab>’: 用<tab>展开片段代码.
  4. let g:UltiSnipsJumpForwardTrigger = '<tab>’: 用<tab>跳到下一个位置.
  5. let g:UltiSnipsJumpBackwardTrigger = '<s-tab>': 用shift+<tab>跳到上一个位置.

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

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

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

2. 几个自带的代码块的讲解

2.1. enumerate 环境:

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

snippet enum "Enumerate" b
begin{enumerate}item $0
end{enumerate}
endsnippet

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

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

神不神奇? 意不意外?

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

snippet Tab_trigger "Description" bendsnippet

是一个基本格式.

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

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

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

  • b :只有当 trigger在行首才有效
  • i :默认情况下, trigger是自成一个单词才有用. 加了这个选项, 即使是在单词中, 只要出现了这几个字母, 就可以使用. 比如 aaatrigger, 也可以使用.
  • w:与i相反, 只有是一个单词(前面是空格) 才可以使用.
  • r:支持正则表达式t在这里,的其他功能失效, 就当成空格使用.
  • A:trigger不需要按tab就可以自动展开.

2.2. lp 代码块

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

snippet lp "Long parenthesis"
left(${1:${VISUAL:contents}}right)$0
endsnippet

这里没有任何选项, 那就是默认. 这里我们看到有两个东西: $1$0.
$1指的是片段展开之后, 光标所在的位置, 那么如果有$2, 按<tab>, 就可以跳到下一个. $0就是最后都跳完了, 光标所在的位置. 这样可以很快地跳出一些环境.

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

2.3. begin end 代码块

看看下面这个:

snippet "b(egin)?" "begin{} / end{}" br
begin{${1:something}}${0:${VISUAL}}
end{$1}
endsnippet

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

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

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

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

snippet "b(egin)?" "begin{} / end{}" br
begin{${1:something}}${2:${VISUAL}Write your words here}
end{$1}$0

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

2.4. 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.

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

2.5. 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 != ignoreexcept 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 命令. 这是插件自带的一个命令, 运行它, 便可以出现这样的画面:

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

本文是我自己使用snippets插件编辑latex的一些经验和心得, 部分参考了这篇文章:

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

欢迎各位批评指正, 谢谢!


下面是我写的其他关于用vim写latex的文章:

李老师的好学生:Vim Latex 的使用和配置技巧 (一)​zhuanlan.zhihu.com

李老师的好学生:Vim Latex 的使用和配置技巧 (二)​zhuanlan.zhihu.com

latex 下划线_Vim Latex 的使用和配置技巧 (三): 用 snippet 编辑 latex相关推荐

  1. latex 下划线_备战美赛!论文写作必备Latex排版教程之单词间隔、标题及交叉引用...

    LaTex排版学习往期回顾: Latex源文件及文档布局教程 Latex排版之断行.分页与字符串教程 今日学习 单词的间隔 为了使输出的右边界对齐,LATEX 在单词间插入不等的间隔.在句子的末尾插入 ...

  2. jackson驼峰转下划线注解_springboot与web前端的下划线与驼峰的json转换配置

    核心配置:spring.jackson.property-naming-strategy= CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES 配置写在apllicat ...

  3. [翻译] [Overleaf] LaTeX 中的粗体、斜体、下划线

    原  文:Bold, italics and underlining 译  者:Xovee 翻译时间:2020年5月25日 LaTeX 中的粗体.斜体.下划线 在一个文档中,简单的文字排版可以对某些概 ...

  4. python 给文本加下划线_python-matplotlib图例中的下划线文本

    我的图例中需要带下划线.我发现一个问题回答here 但我完全不了解LaTeX.我需要在图例中强调"由伽马光谱确定的含量"(代码的第53行).我尝试从链接中执行以下操作: r'\un ...

  5. 解决springdatajpa 在解析实体类的字段时候驼峰自动转为下划线问题

    解决springdatajpa 在解析实体类的字段时候驼峰自动转为下划线问题 问题描述 springboot 在配置jpa时,利用idea自带工具逆向工程生成实体类,结果在调用findOne的时候,报 ...

  6. vc 文本框 只显示下划线_Word手动添加下划线就out了?虚线、波浪线、双下划线一键搞定...

    相信许多朋友在使用Word编辑文档内容的时候,经常会有涉及到对文本内容添加下划线的操作.有时候我们需要根据实际的情况去添加:单实线下划线.虚线下划线.双下划线.波浪线等等下划线条. 许多朋友在对文本添 ...

  7. jackson 驼峰注解_jackson 常用注解,比如忽略某些属性,驼峰和下划线互转

    一般情况下使用JSON只使用了java对象与字符串的转换,但是,开发APP时候,我们经常使用实体类来做转换:这样,就需要用到注解: Jackson默认是针对get方法来生成JSON字符串的,可以使用注 ...

  8. html字体下划线下移,CSS下划线与文字间距距离设置(CSS文字下划线距离设置)

    CSS设置下划线与文字间距距离(CSS文字下划线距离设置) css下划线与文字上下距离设置,文字字体下划线样式技巧篇,如何改变文字与下划线距离间距?这里CSS5为大家介绍通过下边框border-bot ...

  9. 帕斯卡命名法、驼峰命名法、下划线命名法

    帕斯卡命名法.驼峰命名法.下划线命名法.匈牙利命名法 其中前三种用的比较多. 帕斯卡命名法(Pascal) 程序代码示例: ShowMessage(); string PassWord; 单字之间不以 ...

最新文章

  1. Python 之 matplotlib (九)contours等高线
  2. Mysql 知识点总结(持续更新)
  3. Kafka将消息发往内存缓冲区
  4. 直播实录 | AlphaGo Zero是如何实现无师自通的?
  5. 《C4.5: Programs for Machine Learning》chaper4实验结果重现
  6. [转]oracle 11g 忘记 默认用户密码
  7. JS获取url多个参数及解决中文乱码问题
  8. SAP 资产分类的配置方法
  9. java 摄像头_javacv调用摄像头拍照
  10. 一位全减器VHDL语言
  11. 学习笔记--爬虫(11)---js逆向思路和解密思路(初级)
  12. Windows 更新错误 0x80073712
  13. 紫书——Repeating Decimals UVA - 202
  14. 格斗类游戏的键盘处理
  15. ECSHOP模板堂商品最小起订量插件
  16. Windows相关系统性学习
  17. 【单片机毕业设计】【mcuclub-306】万年历电子时钟 | 数字时钟 | 多功能时钟 | 智能闹钟
  18. mysql取去年年初_查询年初,年末,去年年初,明年年初与年末sql语句
  19. Spring boot 集成 Elastic-job 实现定时任务
  20. cx_Oracle.DatabaseError: DPI-1047: Cannot locate a 64-bit Oracle Client library:

热门文章

  1. mysql 4G内存配置表
  2. Windows 下用reg 文件将exe 写入启动项
  3. Java-Reflection反射-获取包括父类在内的所有字段
  4. [摘录]第8章 与非美国人谈判的技巧
  5. ruby on rails错误undefined method `title#39; for nil:NilClass
  6. 反编译华为U8825D“framework-res.apk”出现的错误提示(1)
  7. MySQL表的key怎么设置为yes_MySQL 修改账号密码方法
  8. windows程序设计 c语言,【教程】基于C语言的Windows编程入门
  9. db2dual_DB2常用SQL的写法(持续更新中...)
  10. iphone个系列尺寸_iPhone 12系列、11系列尺寸对比