外链论坛

 找回密码
 立即注册
搜索
查看: 41|回复: 1

1700页数学笔记火了!全程敲代码,硬核小哥教你上手LaTeX+Vim

[复制链接]

2956

主题

220

回帖

9909万

积分

论坛元老

Rank: 8Rank: 8

积分
99099298
发表于 2024-8-17 10:18:31 | 显示全部楼层 |阅读模式

晓查 乾明 发自 凹非寺

量子位 报告 | 公众号 QbitAI

显现一位“神仙”本科生!

数学课上,全程键盘手打1700页笔记。

速度紧追老师板书,公式、图形一个不落。

效果?请看下图:

不仅排版媲美教科书,况且还能够批注,检索关键词……

笔记被他Po到网上之后,便引来海量围观。

不到一天,关联推文就已然有2000多赞,Hacker News论坛上盖了200多楼。

乃至有网友评论叫作:“你便是咱们必须的英雄!”

他是怎么做到的呢?奥密武器便是LaTeX+Vim

这位来自欧洲的小哥非常剧烈安利Vim文本编辑器,他说:

用LaTeX写数学公式,我选Vim编辑器。它强大、通用、可扩展性很强。只要是基于文本的任务我都用它,写代码、编辑LaTeX、写markdown都是。

虽然入门周期的学习曲线超级陡峭,但只要把握了基本的操作方式,就会欲罢不可

下面就让咱们看一下他完成这一壮举的详细流程,文中说到的工具下载位置咱们都附在了最后。

快速上手教程

咱们瞧瞧小哥的工作环境配置。

他用Vim编辑LaTeX的场景,就像下面这般

左边是Vim,右边是pdf阅读器Zathura,它有类似Vim的快捷键。

小哥用的操作系统是Ubuntu,运用bspwm做为窗口管理器。在Vim中,运用的LaTex插件是vimtex,它有语法高亮表示、目录视图、同步对象等功能。

而后运用vim-plug做如下配置:

Plug lervag/vimtex let g:tex_flavor=latex let g:vimtex_view_method=zathura let g:vimtex_quickfix_mode=0 set conceallevel=1 let g:tex_conceal=abdmg

最后两行掌控的是“隐匿”功能。开启了这个功能,除了你光标所在的那一行之外,文本里夹杂的LaTeX代码就都会隐匿替换成其他符号。

例如说在下面动图里,隐匿了[,],$之后,了它们的干扰,全部文档就更易读。这个功能还会用∩替代\bigcap,∈替代\in等等。

设置完成,接下来就到了全部教程的精华所在:

用LaTeX记笔记,怎么才可像老师写板书同样快?

便是片段(snippets)发挥功效地区了。

片段

片段是什么?

片段是一小段可复用的文本,由其他文本触发。

例如,输入sign,再按下Tab键,这个单词就会自动扩展为一段签名:

片段能够是动态的:输入today并按下Tab键,它就会变成当前的日期。

而输入box按Tab,就会显现一个框,还会随着输入文字自动变大。

片段,乃至能够嵌套在另一个片段里用:

怎么创建片段?运用UltiSnips

管理片段的插件UltiSnips,小哥是这般配置的:

关于sign片段的代码如下:

snippet sign "Signature" Yours sincerely, Gilles Castel endsnippet

针对动态的片段,你能够将代码放在``之间, 在片段扩展的时候,就会运行。下面的例子,便是用 bash 格式化当前日期:date+%f。

snippet today "Date" `date +%F` endsnippet

能够在!p ...代码块里运用Python,例如上面box片段的代码便是这般的:

snippet box "Box" `!p snip.rv = ┌ + ─ * (len(t[1]) + 2) + ┐` │ $1 │ `!p snip.rv = └ + ─ * (len(t[1]) + 2) + ┘` $0 endsnippet

这些 Python 代码块将被变量 snip.rv 的值替换。在这些代码块中,你能够拜访代码段的当前状态,例如t[1]包括第1个制表位,fn是当前文件名等等。

LaTex片段

运用片段编写LaTeX,要比纯手工编写快得多。尤其有些非常繁杂的片段能帮你大大节约时间,有效防止抓狂。

下面是有些非常有用且容易上手的片段:

环境

插进一个环境,只必须在一行的开头输入beg。而后键入环境的名叫作,这个名叫作在\end{}命令中同样。按下Tab键,就能够将光标安置在新创建的环境中。

这个片段的代码如下:

snippet beg "begin{} / end{}" bA \begin{$1} $0 \end{$1} endsnippet

其中,b暗示这个片段只会在代码行的开头展开,A表率自动展开,便是不消按Tab键了。制表位(Tab stop)——便是能够经过按Tab 和Shift+Tab到的位置——用$1、 $2、......来暗示,最后一个用$0。

行内和数学表示

在记数学笔记的过程中,最常用的两个片段是mk和dm。

它们负责起步数学模式。第1个片段用于“行内数学”,第二个用于“表示数学”。

代码行内的数学片段是“智能的”:它晓得什么时候在$符号后面直接输入一个单词,它会自动加个空格。但倘若输入一个非单词的字符,它就不会添加空格了,例如在““$p$-value”状况下,是这般的:

这个片段的代码如下:

snippet mk "Math" wA $${1}$`!p if t[2] and t[2][0] not in [,, ., ?, -, ]: snip.rv = else: snip.rv = `$2 endsnippet

第1行末尾的w,寓意着这个片段会在单词边界处扩展,例如,hellomk不会扩展,然则hello mk会。

用于表示数学的片段更简单,更加方便;有了它,你可能再不会忘记用句号结束方程了。

代码:

snippet dm "Math" wA \[ $1 .\] $0 endsnippet

小写和上标

另一个特别有用的片段便是下标。能够把a1改为a1,把a_12改为a{12}。

这个片段的触发器是运用正则表达式。有两种状况会扩展片段。一是你键入一个字符,后面跟着一个数字,例如[A-Za-z]\d;另一种是,一个字符后面有并跟着两个数字,例如[A-Za-z]\d\d。

当你运用括号将正则表达式的一部分装在一个组中时,例如(\d\d),你能够在 Python中经过match.group (i)来运用它们扩展片段。

至于上标,能够运用td,它就会变成^{}。然而,针对平方、立方和其他有些平常的片段,能够运用专门的代码片段,如 sr、cb等等。

效果图:

代码:

snippet sr "^2" iA ^2 endsnippet snippet cb "^3" iA ^3 endsnippet snippet compl "complement" iA ^{c} endsnippet snippet td "superscript" iA ^{$1}$0 endsnippet

分数

分数是一个用起来最方便的一个片段,扩展的形式如下:

/ / → frac {}{} 3 / → frac {3}{} 4 pi ^ 2 / → frac {4 pi ^ 2}{} (1 + 2 + 3) / → frac {1 + 2 + 3}{} (1 + (2 + 3) /)→(1 + frac {2 + 3}{}) (1 + (2 + 3)) / → frac {1 + (2 + 3)}{

第1个片段的代码很简单:

snippet // "Fraction" iA \\frac{$1}{$2}$0 endsnippet

第二个和第三个示例,能够运用正则表达式来匹配3/、4ac/、6pi^2/、a2/等表达式。

snippet ((\d+)|(\d*)(\\)?([A-Za-z]+)((\^|_)(\{\d+\}|\d))*)/ "Fraction" wrA \\frac{`!p snip.rv = match.group(1)`}{$1}$0 endsnippet

看了上边这些,你可能觉得正则表达式太难了。不碍事,下面有一个解释得非常直观的图表:

在第四和第五种示例下,要换一种办法运用UltiSnips的正则表达式引擎处理不了的,Python能够

这儿最后要分享的关于分数的片段,能按照你的选取,来生成一个分数。

能够选取有些文本,而后按Tab键,继续输入、而后再按Tab键。

代码中,运用${VISUAL}变量来暗示所选的内容。

snippet / "Fraction" iA \\frac{${VISUAL}}{$1}$0 endsnippet

Sympy和Mathematica

还有一个很酷但用得不多的片段,是运用Sympy来计算数学表达式。例如,输入sympy,而后按下Tab,能够扩展为sympy | sympy,输入sympy 1 + 1 sympy,按下Tab,能够扩展为2。

片段代码:

nippet sympy "sympy block " w sympy $1 sympy$0 endsnippet priority 10000 snippet sympy(.*)sympy "evaluate sympy" wr `!p from sympy import * x, y, z, t = symbols(x y z t) k, m, n = symbols(k m n, integer=True) f, g, h = symbols(f g h, cls=Function) init_printing() snip.rv = eval(latex( + match.group(1).replace(\\, ) \ .replace(^, **) \ .replace({, () \ .replace(}, )) + )) ` endsnippet

用Mathematica,能够做类似的事情:

片段代码:

priority 1000 snippet math "mathematica block" w math $1 math$0 endsnippet priority 10000 snippet math(.*)math "evaluate mathematica" wr `!p import subprocess code = ToString[ + match.group(1) + , TeXForm] snip.rv = subprocess.check_output([wolframscript, -code, code]) ` endsnippet

后缀片段

除了上边这些之外,后缀片段很值得分享。例如phat→hat{p}和zbar→overline{z}。还有类似的后缀向量,例如v,.→vec{v}和v.,→vec{v}。.和,的次序不碍事因此能够同期按下它们两个。

这些片段真的能够节省时间,能够根据和老师写板书同样次序来记。

重视,bar和hat前缀依然能够用,只要以较低的优先级添加它们就行。

这些片段的代码是:

priority 10 snippet "bar" "bar" riA \overline{$1}$0 endsnippet priority 100 snippet "([a-zA-Z])bar" "bar" riA \overline{`!p snip.rv=match.group(1)`} endsnippet priority 10 snippet "hat" "hat" riA \hat{$1}$0 endsnippet priority 100 snippet "([a-zA-Z])hat" "hat" riA \hat{`!p snip.rv=match.group(1)`} endsnippet snippet "(\\?\w+)(,\.|\.,)" "Vector postfix" riA \vec{`!p snip.rv=match.group(1)`} endsnippet

其他片段

另外,小哥还有大约100个常用的片段(下载位置附着文末),大都数都很简单。例如,输入!>变成\mapsto,输入->变成\to等等。

fun变成f: \R \to \R :,!>变成\mapsto,->变成\to,cc变成\subset。

lim变成\lim{n \to \infty},sum变成\sum{n = 1}^{\infty},ooo变成\infty。

特定课程的片段

除了有些常用的片段,能够针对特定的课程设定片段。例如,在量子力学这门课中,能够设定有些关于bra/ket符号的片段。

<a|→\bra{a} <ψ|→\bra{\psi}="" a="">→\ket{a}

|ψ>→\ket{\psi}

→\braket{a}{b}

代码:

snippet "\<(.*?)\|" "bra" riA \bra{`!p snip.rv = match.group(1).replace(q, f\psi).replace(f, f\phi)`} endsnippet snippet "\|(.*?)\>" "ket" riA \ket{`!p snip.rv = match.group(1).replace(q, f\psi).replace(f, f\phi)`} endsnippet snippet "(.*)\\bra{(.*?)}([^\|]*?)\>" "braket" riA `!p snip.rv = match.group(1)`\braket{`!p snip.rv = match.group(2)`}{`!p snip.rv = match.group(3).replace(q, f\psi).replace(f, f\phi)`} endsnippet

上下文

在编写这些片段时必须思虑的一件事是,“这些片段会与长与常用的文本冲突吗?”

例如,在英语中大大概72个单词包括sr,这寓意着当输入disregard这个词时,sr会扩展到^2,显现一个di^2egard。

这个问题的处理方法是,为代码片段添加上下文。

经过运用 Vim 的语法明显表示能够确定UltiSnips是不是应该扩展片段,这取决于你运用的是数学还是文本。

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()”添加到只期盼在数学上下文中展开的片段中。

context "math()" snippet sr "^2" iA ^2 endsnippet

重视,“数学上下文”是一个微妙的东西。 有时你能够运用\text{…}在数学环境中添加有些文本。在这种状况下,你不必须扩展片段。然则,在以下状况下: \[ \text{$...$} \],它们能够扩展。 这便是为何math上下文的代码有点繁杂。下面的动图说明了这些微妙之处。

除了以上有些片段,你能够按照自己的必须,来自己添加有些插件片段,来加强自己的效率。

用笔还是用电脑?

纯手打记下1700页数学笔记,awesome都不足形容了这位小哥了,堪叫作理工科学生中的“英雄”。

并非所有人都赞同小哥的做法,强大的高科技工具在传统面前常常会被质疑。

有部分网友认为手写比电脑打字印象深刻,况且要达到这位小哥的熟悉程度,恐怕LaTeX和Vim得练习好几年。

既然用笔更方便,为何还要用电脑来记笔记呢?原由很简单:字太丑!

倘若记下来的内容连自己看的欲望都,怎么复习课堂笔记呢?最少用电脑记下来的排版工整,让人赏心悦目。

虽然国外网友争论不休,但在国内只要一个要求能够彻底否决这个方法:不让带电脑进课堂。

对此,你怎么看?

工具传送门:

Linux和Mac系统自带Vim。

Windows用户安装Vim:

https://ftp.nluug.nl/pub/vim/pc/gvim81.exe

Vim插件管理:

https://github.com/junegunn/vim-plug

Vim上的LaTeX插件:

https://github.com/lervag/vimtex

窗口平铺管理器:

https://github.com/baskerville/bspwm

管理Vim片段工具:

https://github.com/SirVer/ultisnips

倘若你用不惯Vim,还有Emacs、Atom、VS Code、Sublime,它们都有LaTeX插件,总有一款文本编辑器适合你。

LaTeX平常数学符号输入办法

https://en.wikibooks.org/wiki/LaTeX/Mathematics

想要熟练更加多的LaTeX运用办法,就必须系统地学习,平时多加练习必不可少。

博文链接:

https://castel.dev/post/lecture-notes-1/

回复

使用道具 举报

0

主题

1万

回帖

1

积分

新手上路

Rank: 1

积分
1
发表于 2024-8-25 15:02:54 | 显示全部楼层
你的言辞如同繁星闪烁,点亮了我心中的夜空。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

站点统计|Archiver|手机版|小黑屋|外链论坛 ( 非经营性网站 )|网站地图

GMT+8, 2024-11-9 04:54 , Processed in 0.075766 second(s), 20 queries .

Powered by Discuz! X3.4

Copyright © 2001-2023, Tencent Cloud.