Vim有什么奇技巧?
作者:卡卷网发布时间:2025-01-08 18:42浏览数量:79次评论数量:0次
有人用vim纯手打1700页数学笔记。
速度紧追老师板书,公式、图形一个不落。效果?请看下图:
不仅排版媲美教科书,而且还能够批注,检索……
笔记被他Po到网上之后,便引来大量围观。
不到一天,相关推文就已经有2000多赞,HackerNews论坛上盖了200多楼。
甚至有网友评论称:“你就是我们需要的英雄!”
他是怎么做到的呢?秘密武器就是:<>LaTeX>+<>Vim>!
下面就让我们看一下他完成这一壮举的具体流程,文中提到的工具下载,我们都附在了最后。
<>快速上手教程>
我们先看看小哥的工作环境配置。
他用Vim编辑LaTeX的场景,就像下面这样:
左边是Vim,右边是pdf阅读器Zatha,它也有类似Vim的快捷键。
小哥用的作是Uuntu,使用spwm作为窗口器。在Vim中,使用的LaTex插件是vimtex,它有语法高亮显示、目录视图、同步对象等功能。
然后,使用vim-plug做如下配置:
Plug'lervag/vimtex'
letg:tex_flor='latex'
letg:vimtex_view_method='zatha'
letg:vimtex_quickfix_mode=0
setconceallevel=1
letg:tex_conceal='admg'
最后两行控制的是“隐”功能。开启了这个功能,除了你光标所在的那一行之外,文本里夹杂的LaTeX代码就都会隐或者替换成符号。
如说在下面动图里,隐了[,],$之后,没有了它们的干扰,整个文档就更易读。这个功能还会用∩替代\igcap,∈替代\in等等。
设置完成,接下来就到了整个教程的精华所在:
<>用LaTeX记笔记,怎么才能像老师写板书一样快?>
这就是片段(snippets)发挥作用地方了。
<>片段>
<>片段是什么?>
片段是一小段可复用的文本,由文本触发。
例如,输入sign,再按下Ta键,这个单词就会自动扩展为一段签名:
片段也可以是动态的:输入today并按下Ta键,它就会变成当前的期。
而输入ox按Ta,就会出现一个框,还会随着输入文字自动变大。
片段,甚至可以嵌套在另一个片段里用:
<>怎么创建片段?使用UltiSnips>
片段的插件UltiSnips,小哥是这样配置的:
Plug'sirver/ultisnips'
letg:UltiSnipsExpandTrigger='<ta>'
letg:UltiSnipsJumpForwardTrigger='<ta>'
letg:UltiSnipsJumpackwardTrigger='<s-ta>'
关于sign片段的代码如下:
snippetsign"Signate"
Yossincerely,
GillesCas
endsnippet
对于动态的片段,你可以将代码放在``之间,在片段扩展的时候,就会运行。下面的例子,就是用ash格式化当前期:date+%f。
snippettoday"Date"
`date+%F`
endsnippet
你也可以在!p...代码块里使用Python,如上面ox片段的代码就是这样的:
snippetox"ox"
`!psnip.rv='┌'+'─'*(len(t[1])+2)+'┐'`
│$1│
`!psnip.rv='└'+'─'*(len(t[1])+2)+'┘'`
$0
endsnippet
snippeteg"egin{}/end{}"A
\egin{$1}
$0
\end{$1}
endsnippet其中,表示这个片段只会在代码行的开头展开,A代表自动展开,也就是说不用按Ta键了。制表位(Tastop)——也就是你可以通过按Ta和Shift+Ta跳转到的位置——用$1、$2、......来表示,最后一个用$0。
<>行内和数学显示>
在记数学笔记的过程中,最常用的两个片段是mk和dm。
它们负责启动数学模式。第一个片段用于“行内数学”,第二个用于“显示数学”。
代码行内的数学片段是“智能的”:它知道什么时候在$符号后面直接输入一个单词,它会自动加个空格。但如果输入一个非单词的字符,它就不会添加空格了,如在““$p$-value”情况下,是这样的:
这个片段的代码如下:
snippetmk"Math"wA
$${1}$`!p
ift[2]andt[2][0]notin[',','.','?','-','']:
snip.rv=''
else:
snip.rv=''
`$2
endsnippet第一行末尾的w,意味着这个片段会在单词边界处扩展,例如,hellomk不会扩展,但是hellomk会。
用于显示数学的片段更简单,也更加方便;有了它,你可能再也不会忘记用句号结束方程了。
代码:
snippetdm"Math"wA
\[
$1
.\]$0
endsnippet<>小写和上标>
另一个很有用的片段就是下标。能够把a1改为a1,把a_12改为a{12}。
这个片段的触发器是使用正则表达式。有两种情况会扩展片段。一是你键入一个字符,后面跟着一个数字,如[A-Za-z]\d;另一种是,一个字符后面有并跟着两个数字,如[A-Za-z]\d\d。
snippet'([A-Za-z])(\d)'"autosuscript"wrA
`!psnip.rv=match.group(1)`_`!psnip.rv=match.group(2)`
endsnippet
snippet'([A-Za-z])_(\d\d)'"autosuscript2"wrA
`!psnip.rv=match.group(1)`_{`!psnip.rv=match.group(2)`}
endsnippet
当你使用括号将正则表达式的一部分装在一个组中时,例如(\d\d),你可以在Python中通过match.group(i)来使用它们扩展片段。
至于上标,可以使用td,它就会变成^{}。然而,对于平方、立方和一些常见的片段,可以使用专门的代码片段,如sr、c等等。
效果图:
代码:
snippetsr"^2"iA
^2
endsnippet
snippetc"^3"iA
^3
endsnippet
snippetcompl"complement"iA
^{c}
endsnippet
snippettd"superscript"iA
^{$1}$0
endsnippet<>分数>
分数是一个用起来最方便的一个片段,扩展的形式如下:
//→frac{}{}3/→frac{3}{}4pi^2/→frac{4pi^2}{}(1+2+3)/→frac{1+2+3}{}(1+(2+3)/)→(1+frac{2+3}{})(1+(2+3))/→frac{1+(2+3)}{
第一个片段的代码很简单:
snippet//"Fraction"iA
\\frac{$1}{$2}$0
endsnippet第二个和第三个示例,可以使用正则表达式来匹配3/、4ac/、6pi^2/、a2/等表达式。
snippet'((\d+)|(\d*)(\\)?([A-Za-z]+)((\^|_)(\{\d+\}|\d))*)/'"Fraction"wrA
\\frac{`!psnip.rv=match.group(1)`}{$1}$0
endsnippet
看了上边这些,你可能觉得正则表达式太难了。没关系,下面有一个解释得非常直观的图表:
在第四和第五种示例下,要换一种方法。使用UltiSnips的正则表达式引擎解决不了的,Python可以:
priority1000
snippet'^.*\)/'"()Fraction"wrA
`!p
stripped=match.string[:-1]
depth=0
i=len(stripped)-1
whileTrue:
ifstripped[i]==')':depth+=1
ifstripped[i]=='(':depth-=1
ifdepth==0:reak;
i-=1
snip.rv=stripped[0:i]+"\\frac{"+stripped[i+1:-1]+"}"
`{$1}$0
endsnippet这里最后要分享的关于分数的片段,能根据你的选择,来生成一个分数。
你可以先选择一些文本,然后按Ta键,继续输入、然后再按Ta键。
代码中,使用${VUAL}变量来表示所选的内容。
snippet/"Fraction"iA
\\frac{${VUAL}}{$1}$0
endsnippet
<>Sympy和Mathematica>
还有一个很酷但用得不多的片段,是使用Sympy来计算数学表达式。例如,输入sympy,然后按下Ta,可以扩展为sympy|sympy,输入sympy1+1sympy,按下Ta,可以扩展为2。
片段代码:
snippetsympy"sympylock"w
sympy$1sympy$0
endsnippet
priority10000
snippet'sympy(.*)sympy'"evaluatesympy"wr
`!p
fromsympyimport*
x,y,z,t=symols('xyzt')
k,m,n=symols('kmn',integer=True)
f,g,h=symols('fgh',cls=Function)
init_printing()
snip.rv=eval('latex('+match.group(1).replace('\\','')\
.replace('^','**')\
.replace('{','(')\
.replace('}',')')+')')
`
endsnippet用Mathematica,也可以做类似的事情:
片段代码:
priority1000
snippetmath"mathematicalock"w
math$1math$0
endsnippet
priority10000
snippet'math(.*)math'"evaluatemathematica"wr
`!p
importsuprocess
code='ToString['+match.group(1)+',TeXForm]'
snip.rv=suprocess.check_output(['wolframscript','-code',code])
`
endsnippet<>后缀片段>
除了上边这些之外,后缀片段也很值得分享。例如phat→hat{p}和zar→overline{z}。还有类似的后缀向量,例如v,.→vec{v}和v.,→vec{v}。.和,的顺序没关系,所以可以同时按下它们两个。
这些片段的可以节省时间,可以按照和老师写板书一样的顺序来记。
注意,ar和hat前缀也依然可以用,只要以较低的优先级添加它们就行。
这些片段的代码是:
priority10
snippet"ar""ar"riA
\overline{$1}$0
endsnippet
priority100
snippet"([a-zA-Z])ar""ar"riA
\overline{`!psnip.rv=match.group(1)`}
endsnippet
priority10
snippet"hat""hat"riA
\hat{$1}$0
endsnippet
priority100
snippet"([a-zA-Z])hat""hat"riA
\hat{`!psnip.rv=match.group(1)`}
endsnippet
snippet"(\\?\w+)(,\.|\.,)""Vectorpostfix"riA
\vec{`!psnip.rv=match.group(1)`}
endsnippet<>片段>
此外,小哥还有大约100个常用的片段(下载附于文末),大多数都很简单。如,输入!>变成\mapsto,输入->变成\to等等。
fun变成f:\R\to\R:,!>变成\mapsto,->变成\to,cc变成\suset。
lim变成\lim{n\to\infty},sum变成\sum{n=1}^{\infty},ooo变成\infty。
<>特定课程的片段>
除了一些常用的片段,也可以针对特定的课程设定片段。例如,在量子力学这门课中,可以设定一些关于ra/ket符号的片段。
<a|→\ra{a}<ψ|→\ra{\psi}=""a="">→\ket{a}|ψ>→\ket{\psi}→\raket{a}{}
代码:
snippet"\<(.*?)\|""ra"riA
\ra{`!psnip.rv=match.group(1).replace('q',f'\psi').replace('f',f'\phi')`}
endsnippet
snippet"\|(.*?)\>""ket"riA
\ket{`!psnip.rv=match.group(1).replace('q',f'\psi').replace('f',f'\phi')`}
endsnippet
snippet"(.*)\\ra{(.*?)}([^\|]*?)\>""raket"riA
`!psnip.rv=match.group(1)`\raket{`!psnip.rv=match.group(2)`}{`!psnip.rv=match.group(3).replace('q',f'\psi').replace('f',f'\phi')`}
endsnippet<>上下文>
在编写这些片段时需要考虑的一件事是,“这些片段会与长与常用的文本冲突吗?”
例如,在英语中大约有72个单词包含sr,这意味着当输入disregard这个词时,sr会扩展到^2,出现一个di^2egard。
这个问题的解决方案是,为代码片段添加上下文。
通过使用Vim的语法突出显示,可以确定UltiSnips是否应该扩展片段,这取决于你使用的是数学还是文本。
gloal!p
texMathZones=['texMathZone'+xforxin['A','AS','','S','C',
'','D','DS','E','ES','F','FS','G','GS','H','HS','I','',
'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]
defmath():
synstackids=vim.eval("synstack(line('.'),col('.')-(col('.')>=2?1:0))")
try:
first=next(
iforiinreversed(synstackids)
ifiintexIgnoreMathZoneIdsoriintexMathZoneIds
)
retnfirst!=ignore
exceptStopIteration:
retnFalse
endgloal现在,你可以将context“math()”添加到只希望在数学上下文中展开的片段中。
context"math()"
snippetsr"^2"iA
^2
endsnippet请注意,“数学上下文”是一个微妙的东西。有时你可以使用\text{…}在数学环境中添加一些文本。在这种情况下,你不需要扩展片段。但是,在以下情况下:\[\text{$...$}\],它们可以扩展。这就是为什么math上下文的代码有点复杂。下面的动图说明了这些微妙之处。
除了上述一些片段,你也可以根据自己的需要,来自己添加一些插件或者片段,来提高自己的效率。
<>用笔还是用电脑?>
纯手打记下1700页数学笔记,awesome都不够形容了这位小哥了,堪称理工科学生中的“英雄”。
并非所有人都赞同小哥的做法,强大的高科技工具在传面前常常会被质疑。
有部分网友认为手写电脑打字印象深刻,而且要达到这位小哥的熟练程度,恐怕LaTeX和Vim得练习好几年。
既然用笔更方便,为什么还要用电脑来记笔记呢?原因很简单:字太丑!
如果记下来的内容连自己看的都没有,怎么复习课堂笔记呢?至少用电脑记下来的排版工整,让人赏心悦目。
虽然国外网友争论不休,但在国内只要一个条件就可以彻底否决这个方法:不让带电脑进课堂。
对此,你怎么看?
<>工具传送门:>
Linux和Mac自带Vim。
Windows用户安装Vim:s://ftp.nluug.nl/pu/vim/pc/gvim81.exe
Vim插件:s://githu/junegunn/vim-plug
Vim上的LaTeX插件:s://githu/lervag/vimtex
窗口平铺器:s://githu/askerville/spwm
Vim片段工具:s://githu/SirVer/ultisnips
LaTeX常见数学符号输入方法:s://en.wikiooks.org/wiki/LaTeX/Mathemati
想要熟悉更多的LaTeX使用方法,就需要地学习,平时多加练习也必不可少。
博文链接:
s://cas.dev/post/lecte-notes-1/—<>完>—
量子位·QitAIվ'ᴗ'ի追踪AI技术和产品新动态
量子位欢迎大家关注我们,以及订阅我们的知乎专栏
END
免责声明:本文由卡卷网编辑并发布,但不代表本站的观点和立场,只提供分享给大家。
请记住:卡卷网 Www.Kajuan.Net
广告位

你 发表评论:
欢迎