推荐一个快速输入 latex 数学公式的包 latex-auto-activating-snippets,不用按 tab 键自动展开 snippet

应用背景

我在 org-mode 中输入数学公式的时候,为了尽量加快对具有重复性的符号的输入(例如用粗斜体表示矢量 \bm{a}),会使用 yasnippet 实现存一些代码片段,需要的时候输入关键子加 tab 展开代码片段(也就是将输入内容替换为代码片段)。

为了更省时间,我希望能够不用输入 tab ,只输入关键字就能展开片段。这就是自动展开功能。

举几个例子:

用户输入 被替换成的文本
a,. \vec{a}
abar \overline{a}
beg \begin{}

latex-auto-activating-snippet 不仅可用于 org-mode,也可用于 tex-mode 等等,只要设置激活条件。

已知解决方案

Vim UltiSnips 自动展开功能

Gilles Castel怎么用vim做数学笔记一文中使用 Vim 插件 UltiSnips 中的自动展开功能实现了如下图的片段展开:

对应于

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

UltiSnips 是通过对一行的内容使用正则表达式匹配实现的,这是 auto-activating-snippets 作者说的

VSCode LaTeX-Utilities

tecosaur 做了一个 VSCode 插件 LaTeX-Utilities,用于 latex 文档中的数学公式输入。其中有一个 Live Snippets 的功能,通过正则表达式(可以自定义)匹配和替换实现了自动展开的功能。

这里使用了 xx -> \times(a \times b)/ -> \frac{a \times b}{}

Emacs yasnippet

yasnippet 也是可以实现这个功能的。在一篇 issue 中有人提出定义一个函数

  (defun my-yas-try-expanding-auto-snippets ()
    (when (and (boundp 'yas-minor-mode) yas-minor-mode)
      (let ((yas-buffer-local-condition ''(require-snippet-condition . auto)))
        (yas-expand))))
  (add-hook 'post-command-hook #'my-yas-try-expanding-auto-snippets)

然后在 snippet 定义的 condition 中加上:

# -*- mode: snippet -*-
# name: parentheses
# key: ()
# condition: (and (texmathp) 'auto)
# --
\left($1\right)$0

也可以实现类似的功能。

Emacs latex-auto-activating-snippets

这就是我要推荐的 emacs 包。 tecosaur 也对这个包做了贡献。它分了两层:

  1. 用于自动展开的引擎 auto-activating-snippets
  2. 各种 latex 代码片段定义 latex-auto-activating-snippets

它的实现方式是,追踪用户最后打的字,如果连续几个字构成的序列(key-sequence)能匹配到某个片段,就展开。 这类似于一个很长前缀的命令,只不过那些前缀会直接进到 buffer 中,直到匹配到后,运行某种函数将函数的输出替换序列。

This package implements an engine for auto-expanding snippets. It is done by tracking your inputted chars along a tree until you complete a registered key sequence.

Its like running a long prefix command, but the keys you type are not ‘consumed’ and appear in the buffer until you complete the whole command - and then the snippet is triggered!

据作者所说,这种实现方式相较于 UltiSnips 的实现方式的优势是,可以在 snippet 很多的时候也不卡,就和有很多 keymaps 的时候也不卡是一个道理。

相较于 yasnippet 的优势是,yasnippet 在每次展开的时候都会检查所有 snippet 的 condition,所以会比较慢。

laas(简称)的配置和使用

我的部分配置

(use-package! laas
  :hook (org-mode . laas-mode)
  :config
  ;; 不自动插入空格
  (setq laas-enable-auto-space nil)
  (aas-set-snippets 'laas-mode
                    ;; 只在 org latex 片段中展开
                    :cond #'org-inside-LaTeX-fragment-p
                    "tan" "\\tan"
                    ;; 内积
                    "i*" (lambda () (interactive)
                           (yas-expand-snippet "\\langle $1\\rangle$0"))
                    "sr" "^2"
                    ;; 还可以绑定函数,和 yasnippet 联动
                    "Sum" (lambda () (interactive)
                            (yas-expand-snippet "\\sum_{$1}^{$2} $0"))
                    ;; 这是 laas 中定义的用于包裹式 latex 代码的函数,实现 \bm{a}
                    :cond #'laas-object-on-left-condition
                    ",." (lambda () (interactive) (laas-wrap-previous-object "bm"))
                    ".," (lambda () (interactive) (laas-wrap-previous-object "bm"))))

效果是这样的:

Peek 2021-07-08 15-43

这里使用了:

用户输入 被替换成的文本
a,. \bm{a}
** \cdot
\bm{c}/ \frac{\bm{c}}{}
18 个赞

这个很棒啊,感觉一定要试试

挺好的,不过vimtex的功能已经很完善了,还能动态显示矩阵的所有元素,这个功能挺牛的,不知道emacs能不能实现,希望大神试试

太棒了,稍微试了一下,确实比cdlatex流畅

可以看看这个:https://karthinks.com/software/latex-input-for-impatient-scholars/

:grinning:

2 个赞