省时省力写 LaTeX
- 引子: 五分钟说服你用 Emacs 写 LaTeX (视频)
- 第 1 节: Emacs 快速配置与插件管理 (视频)
- 第 2 节: cdlatex 中快速输入数学符号和字体与自定义设置 (视频)
- 第 3 节: Tab 补全快速插入LaTeX代码 (视频)
- 附录 1: Emacs最强内置pdf阅读器 pdf-tools 简介 (视频)
- 附录 2: 如何优雅地预览公式 (视频)
本小节将介绍如何快速配置一个用于 LaTeX 写作的 Emacs, 包括软件安装和插件管理, 以及 Emacs 的一些必要的入门知识. 最后将推荐两组非常实用的插件: 第一组插件 Which-key + Keycast + Helpful 将帮助我们快速熟悉 Emacs 的操作和概念, 第二组插件 Vertico + Marginalia + Orderless 将有效提升我们在小缓冲区的补全体验, 并附上 AucTeX 和 CDLaTeX 的基本设置.
Emacs 可以运行在 Windows, Linux, MacOS 上, 也可以通过 termux 运行在 Android 手机或平板上. 这里我们只介绍电脑系统上的 Emacs 安装.
在本文撰写时 (2023.4), Emacs 的最新正式版本为 28.2, 最近的测试版本为 29.090. 下面介绍的安装方法针对的是正式版. (更新: 2023.8 已经可以下载 Emacs 29 正式版.)
在多数平台上, 我们是利用合适的开源软件管理器来安装 Emacs. 在 Linux 中这是自带的, 在 Windows 和 MacOS 中大家需要自行安装. 我们下面详细说明.
Linux 系统中可以用自带的软件管理器安装 Emacs. 例如, 在 Ubuntu 中使用 apt 安装 Emacs, 只需要在命令行中输入
sudo apt install emacsMacOS 中需要先安装 Homebrew. 方法是在命令行中输入
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"当 Homebrew 安装成功后会有提示, 然后就可以使用 Homebrew 安装 Emacs 了: 在命令行中输入
brew install emacsWindows 下安装 Emacs 有两种常见方法. 第一种是安装 MSYS2 (下载链接). 安装后打开 C:/msys64/mingw64.exe (C:/msys64/ 是 MSYS2 的默认安装目录, 根据实际情况调整). 在命令行中输入
pacman -S mingw-w64-x86_64-emacs通过 MSYS2 安装的一个好处是我们可以通过 Pacman 管理 Emacs 的更新. 另一个好处是在上面还可以很方便安装其它开源软件, 例如 Git, Epdfinfo 等. Epdfinfo 是在 Windows 下使用 Emacs 的 PDF-tools 插件的必需软件 (BV1pg4y1s7Z9).
另一种安装方法是直接从官网上下载安装包. Emacs 28 的安装包已经优化了不少, 会自动把程序安装至 C:/Program Files/emacs 目录下, 并附带卸载程序. 通过安装包安装的 Emacs 需要我们手动更新.
安装完 Emacs 之后, 我 强烈建议 大家交换 Caps Lock 与 Left Ctrl. Emacs 常常使用以 Ctrl 开始的快捷键, 因此把 Ctrl 与不常用的大写锁定 Caps Lock 交换是每个 Emacs 使用者对电脑 做的第一件事. Ctrl 键的广泛使用是因为在 Emacs 诞生之初, 当时通用的键盘 Ctrl 确实在当今的 Caps Lock 位置上. 再啰嗦一句: 交换 Caps lock 与 Ctrl 绝不是一件可有可无的事情, 它在我们日常使用 Emacs 中真的非常重要! 大家千万不要怕麻烦.
交换 Ctrl 与 Caps Lock 的方法在不同系统上也不一样.
Windows 中更改键位可以通过注册表或者最新的 PowerToys 软件.
注册表方法 (适用于 Win 10 以前)
方法如下:
regedit 打开注册表[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout]Scancode 文件, 把内容修改为 00 00 00 00 00 00 00 00
03 00 00 00 1d 00 3a 00
3a 00 1d 00 00 00 00 00Scancode 文件并重启电脑PowerToys (适用于 Win 10, Win 11)
PowerToys 并安装在 Ubuntu 下, 可以安装 Gnome-tweaks:
sudo apt install gnome-tweaks然后打开 Gnome-tweaks 的键盘设置, 在高级选项里有关于 Ctrl 键的设置. 你不仅仅可以交换它与 Caps Lock, 也可以进行许多别的设置.
又或者, 在很多 Linux 系统的命令行下输入
setxkbmap -option ctrl:swapcaps也可以交换 Ctrl 与 Caps Lock .
在 MacOS 中, 大家可以在 system -> keyboard -> functional keys 中调整所有功能键的键位.
剩下两个设置只有 Windows 用户需要进行.
第一是把 Emacs 的家目录, 即 Emacs 中通过 ~ 访问的目录, 改成 C:/Users/<用户名>/. 默认的家目录是 C:/Users/<用户名>/AppData/Roaming/. 从这个目录出发不方便我们访问像 “我的文档” 这种常用文件夹, 所以我们需要手动修改家目录为 C:/Users/<用户名>/, 与 Linux 和 MacOS 的使用习惯保持一致.
修改家目录的方法是在环境变量的设置中 (可以在 Windows 搜索栏中搜索 Edit system variables 打开), 增加一个用户的环境变量 HOME, 把它设置为 C:/Users/<用户名>/.
第二是保证你的 Emacs 安装目录在系统变量 PATH 上. 如果不在, 还是在同一个界面, 把包含你 emacs.exe 的文件夹路径手动添加到 PATH 变量中.
作为 Emacs 新手, 大家需要理解的一个核心概念就是命令. 在 Emacs 中所有的操作, 无论简单复杂都是命令. Emacs 这个单词就来自于 macro, 即宏命令. 比如说我们想执行打开一个文件的操作, 有 3 种方式等价的操作方式:
file -> visit new file, 然后和普通的软件一样选择你要打开的文件.open-file 命令. 方法是按下 M-x (M = Alt), 然后在最下面的小缓冲区输入 open-file, 然后输入文件名.Emacs 中有许多有用的命令. 你未来也可以自己通过 Elisp 语言编写自己命令. Emacs 把其中最常用的命令都绑定了快捷键, 用户自己也可以设置自己的快捷键. 当我们用熟了之后, 很多快捷键就会像打字一样形成肌肉记忆. 作为新手, 我们有很多键盘的快捷操作可以用鼠标代替, 因此你不必急于一下子掌握全部 Emacs 的快捷键.
但是, 仍有一些快捷键是大家最好尽快熟悉的. 下面这张表我给大家总结了新手必知的几个快捷键. 在表中, C 表示 Ctrl, M 表示 Alt. 这也是 Emacs 快捷键通用写法. 最右边一列是快捷键对应的命令名, 也就是第一列所有的快捷键都等价于 M-x 加上第三列.
| 快捷键 | 操作 | 命令名 |
|---|---|---|
| C-g | 中止当前一!切!命!令! | keyboard-quit |
| C-/ | 撤销命令 | undo |
| 文件操作 | ||
| C-x C-f | 打开文件 | find-file |
| C-x C-s | 保存文件 | save-buffer |
| C-x b | 切换文件 (缓冲区) | switch-to-buffer |
| C-x 1 | 关闭其它窗口 | delete-other-window |
| C-h f/v/k | 查询命令/变量/快捷键 | describe-function/variable/key |
| 文本处理 | ||
| M-x | 复制 | kill-ring-save |
| C-w | 剪切 | kill-region |
| C-y | 粘贴 | yank |
在 Emacs 中发生误操作时, 你需要知道如何中止与撤销命令. 当你的快捷键输入一半想反悔时 (是的, Emacs 的快捷键可以很长!), 可以使用 C-g 重新来输入, 又或者 Emacs 在执行命令时卡住了, 你可以通过 C-g 来让它恢复正常.
如果你需要撤回上一条命令, 则需要使用 C-/. 但值得注意的是, 撤回撤回命令的命令也是同一个键; 这偶尔会让人抓狂.
下面我们介绍 Emacs 中最基础的几个管理界面的快捷键.
首先是打开文件, C-x C-f, 命令名是 find-file. 这里的 find 隐含 Emacs 会根据不同情况执行不同操作: 若文件存在, 则是普通的打开文件; 若文件不存在, 则是打开一个新文件.
第二个是保存文件, C-x C-s, 对应 save-buffer, 即把当前缓冲区 (更新后) 的内容写进文件里.
大多数情况将缓冲区 (buffer) 等同于文件不会影响你的 Emacs 使用. 这里简单讲讲它们的不同. 文件存在于电脑硬盘上, 而 Emacs 的缓冲区只显示文件内容. 当你把文件内容读入缓冲区以后, 又在 Emacs 外修改了文件的内容, 缓冲区中的内容并不会改变, 除非你明确指示 Emacs 重新读取. 而在 Windows 中, 一个文件同时只能被一个 Windows 程序打开. Emacs 的缓冲区也不一定对应着文件, 在模式栏大家可以看到当前缓冲区的名字. 名字被两个 * 号包含的一般是非文件的缓冲区, 例如 *Message* 用于显示 Emacs 给用户的信息, 编译 LaTeX 时 *Output* 会存放编译输出结果等.
第三个命令是切换缓冲区/文件, C-x b, 对应 switch-to-buffer. 执行后在最下方的小缓冲区会提示输入你想要切换的缓冲区名字, 默认是上一个显示的缓冲区, 直接回车就行.
在 Emacs 中同时显示多个缓冲区的方法是打开多个窗口 (window), 然后在每个窗口中显示一个缓冲区. 有时 Emacs 自动创建新的窗口, 例如展示帮助信息时. 新手最常用的操作是保留当前光标所在窗口, 而关掉其它所有窗口. 这可以通过, C-x 1, 即 delete-other-window 实现. 我们可以用鼠标辅助我们在不同窗口间切换.
Emacs 中查询帮助信息的快捷键是 C-h <字母>. 常用的有 C-h f, 查询命令, C-h v, 查询变量, 以及 C-h k, 查询快捷键. 通常 C-h 命令会自动创建新的窗口显示帮助信息. 我们可以先把光标移到我们工作的缓冲区, 然后用 C-x 1 关闭掉帮助信息窗口. 注意此时帮助信息的缓冲区并没有关闭, 重新显示可以通过 C-x b 并查找以 *help* 命名的缓冲区.
Emacs 有自己一套复制/剪切/粘贴的快捷键: M-w / C-w / C-y. 这和一般程序的 C-c / C-x / C-v 不同, 需要大家习惯. 所有复制或剪切的内容都会进入一个叫 kill-ring 的地方, 它相当于一个剪粘版的历史记录. 粘贴快捷键 C-y 会粘贴最近一条记录, 如果你想访问之前的记录, 可以紧跟着 C-y 再按下一次或多次 M-y.
接下来我们介绍如何更好地管理 Emacs 插件. Emacs 插件也叫 Emacs 包 (package). 插件可以给我们带来更多的功能, 是 Emacs 使用中不可缺少的一环. 插件的安装和设置与其它的 Emacs 设置一样, 都放在 Emacs 的启动文件 ~/.emacs.d/init.el 中. 关于插件安装与设置, 我推荐大家使用现在常用的 use-package 语法, 它的语法更简洁, 还可以很方便地自动安装插件.
Emacs 中下载新的插件可以通过不同的方式 (这也是由某些插件提供的). 常用的有两种, 一种是用内置的 package.el, 这个插件名字就叫 package.el, .el 后缀来自于 Emacs 的编程语言 Elisp.
第二种是用 Straight. package.el 会从官方的插件库 (ELPA, MELPA) 或镜像网站上下载新插件, 而 Straight 用下载插件的源代码并编译, 一般是利用 Git 从 Github 上下载. 为了使用 Straight, 你需要系统上已经安装了 Git 程序, 并且能正常地访问 github.com. 以下我们介绍两种安装方式如何设置.
我们在 package.el 和 Straight 的设置示例中都手动检查并安装了 use-package. Emacs 29 后 use-package 已经是内置插件, 相关代码可以省去.
package.el 设置示例以下我们提供了 package.el 的一个设置示例. 大家需要把如下代码放入设置文件 ./.emacs.d/init.el 中.
;; -*- lexical-binding: t; -*-
;; 静态作用域声明必须放在首行
;; 把 Emacs 自动添加的代码放到 custom.el 中
(setq custom-file (expand-file-name "custom.el" user-emacs-directory))
;;========================================
;; 使用 package.el 设置 Emacs 插件管理
;;========================================
(require 'package) ; 加载 package.el
(setq package-check-signature nil) ; 如果检查签名有问题可以加入这一行
;; 添加仓库位置
(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/") t)
(add-to-list 'package-archives '("melpa-stable" . "http://stable.melpa.org/packages/") t)
;; 国内用户也可以使用清华的镜像网站. 用下面的代码代替上面两行
;; (setq package-archives
;; '(("gnu" . "http://mirrors.tuna.tsinghua.edu.cn/elpa/gnu/")
;; ("nongnu" . "http://mirrors.tuna.tsinghua.edu.cn/elpa/nongnu/")
;; ("melpa-stable" . "http://mirrors.tuna.tsinghua.edu.cn/elpa/stable-melpa/")
;; ("melpa" . "http://mirrors.tuna.tsinghua.edu.cn/elpa/melpa/")))
;; 刷新插件列表
(unless package-archive-contents
(package-refresh-contents))
;; 自动安装 use-package. 在Emacs 29中已内置故可省略
(unless (package-installed-p 'use-package)
(package-install 'use-package))
;; 自动安装所有使用 use-package 声明的插件
(require 'use-package-ensure)
(setq use-package-always-ensure t)
;;========================================
;; Emacs 插件管理设置完毕
;;========================================
;;========================================
;; 这段代码放在最后, 加载 Emacs 自动设置的变量
(if (file-exists-p custom-file) (load-file custom-file))
;;========================================这段代码的第一部分启用了 package.el, 然后通过 package-archives 变量设置了下载插件的网址. 在国内也可以使用清华的软件源. 接下来 package-refresh-contents 刷新了插件列表. 然后我们自动检测 use-package 是否安装, 如果没有安装则自动下载安装. 最后, 我们设置了 use-package-always-ensure 变量为 t, 这样以后我们所有用 use-package 声明的插件都会自动安装.
straight.el 设置示例straight 需要用 git 从 github 等网站上下载源码. 请再三确认 git 在系统路径上 (尤其是用 msys2 安装的 Windows 用户).
因为 straight.el 与 package.el 难以共存, 所以我们必须早早手动禁用内置的 package.el. 这必须修改一个我们平时很少用的文件 .emacs.d/early-init.el. 我们需要在 early-init.el 中加入
;; 在执行 init.el 前禁用 package.el
(setq package-enable-at-startup nil)接下来, 我们需要在 init.el 中加入以下代码:
;; -*- lexical-binding: t; -*-
;;========================================
;; 把 Emacs 自动添加的代码放到 custom.el 中
(setq custom-file (expand-file-name "custom.el" user-emacs-directory))
;; 使用 straight.el 设置 Emacs 插件管理
;;========================================
(defvar bootstrap-version)
;; 修复 Emacs 29 修改了 native-compile 相关变量导致的 bug
(unless (version<= emacs-version "28.2")
(setq straight-repository-branch "develop"))
;; 以下代码从 straight.el 主页 https://github.com/radian-software/straight.el 上复制
(let ((bootstrap-file
(expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
(bootstrap-version 6))
(unless (file-exists-p bootstrap-file)
(with-current-buffer
(url-retrieve-synchronously
"https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el"
'silent 'inhibit-cookies)
(goto-char (point-max))
(eval-print-last-sexp)))
(load bootstrap-file nil 'nomessage))
(straight-use-package 'use-package) ; 用 straight.el 安装 use-package 声明的插件
(setq straight-use-package-by-default t) ; 自动安装所有插件, 相当于加入 :straight t
;;========================================
;; Emacs 插件管理设置完毕
;;========================================
;;========================================
;; 这段代码放在最后, 加载 Emacs 自动设置的变量
(if (file-exists-p custom-file) (load-file custom-file))
;;========================================这里大部分的代码是 straight.el 的 Github主页上提供的下载与安装 straight 的代码, 然后再用 straight 安装 use-package. 最后我用把 straight-use-package-by-default 变量设为 t, 这是在使用 straight 时进行插件自动安装的设置.
下面我给大家推荐两组非常实用的插件. 在进行好 package.el 或者 straight.el 的设置后 (注意: 不能同时使用), 安装与设置插件只需要把相关的 use-package 代码块复制到 init.el 即可. 而且在两个体系下的代码块基本是通用的.
我们之前也都设置了自动安装插件. 当你第一次执行 init.el 时 (通常是第一次重启 Emacs 的时候), Emacs 会自动检测你在 init.el 中声明的插件是否已经安装, 若没有则通过指定的方法 (package.el 或 straight.el) 自动下载安装. 如果大家在一台新的机器上使用 Emacs, 把 init.el 文件复制到新机器上就可以直接获得一模一样的使用体验!
你也可以在修改完 init.el 后, 执行 M-x eval-buffer 命令手动加载新加的 use-package 代码块.
在复制代码块中最常见的问题是某个地方在复制的过程中漏了括号. 大家已经发现 elisp 语言中括号是必须配对的. 我们可以在修改 init.el 后手动的用 M-x match-paren 检查括号是否匹配. 如果有不匹配的括号, 那么光标就会跳过没有匹配成功的括号上, 否则这个命令不会用任何效果.
我们首先介绍 Which-key + Keycast + Helpful. 安装代码如下
(use-package which-key
:custom (which-key-idle-delay 0.5) ; 延迟时间, 以秒为单位
:config (which-key-mode)) ; 启用 which-key 模式
(use-package keycast
:config (keycast-header-line-mode 1)) ; 在标题显示
(use-package helpful
:bind
;; 重新定向 C-h 开始的命令
(([remap describe-function] . #'helpful-callable)
([remap describe-variable] . #'helpful-variable)
([remap describe-key] . #'helpful-key)
([remap describe-command] . #'helpful-command)
([remap describe-symbol] . #'helpful-symbol)
("C-h C-d" . #'helpful-at-point)
("C-h F" . #'helpful-function)))which-key 可以在按下快捷键的时候自动提示你接下来可能的快捷键. 比如按下 C-h, 就会提示接下来你按 v, f, k 等可以查看哪种类型的帮助. 如果把鼠标悬停在选项上也会在浮窗中显示对应命令的帮助.
keycast 则会显示当前你使用的快捷键及对应的命令名. 它有 4 种显示的位置. 代码中我们选择在 headrer-line , 也就是 Emacs 窗口的最上方显示. 如果大家想在别的地方显示, 比如模式栏, 可以把 (keycast-header-line-mode 1) 改成 (keycast-mode-line-mode 1).
这两个插件可以帮助新手快速熟悉 Emacs 的快捷键和命令. 对于老用户来说, 也可以帮你快速熟悉新安装的插件. 我自己平时也是常开的.
helpful 则优化了帮助界面的信息显示, 包括更多有用的信息和高亮.
在 Emacs 中输入命令或打开文件, 切换缓冲区等等都会用到小缓冲区补全. 第二组插件 Vertico + Marginalia + Orderless 是针对小缓冲区补全的. 代码如下
(use-package vertico ; 竖式展开小缓冲区
:custom (verticle-cycle t)
:config (vertico-mode))
(use-package marginalia ; 更多信息
:config (marginalia-mode))
(use-package orderless ; 乱序补全
:custom
(completion-styles '(orderless basic))
(completion-category-defaults nil)
(completion-category-overrides '((file (styles partial-completion)))))vertico 把每个补全选项放在单独的一行, 配合 marginalia 会在每个选项的右边加入更多相关信息.
在小缓冲区中输入时, 我们可以按 Tab 补全当前的输入. 加入 vertico 之后, 我们可以用 C-n 和 C-p 或者上下移动键来选择不同的补全选项. C-n 和 C-p 也是 Emacs 中上下移动光标的快捷键.
最后的 orderless 允许我们在小缓冲区补全时忽略单词的顺序. 例如, 如果我们输入 M-x, 想要匹配 find-file 命令, 在默认情况下必须先输入 find, 再输入 file 才能找到 find-file. 如果你用了 orderless, 则可以通过 file find 找到, 或者部分的单词 fil fin + Tab= 找到.
CDLaTeX + AucTeX 设置最后我们提供一个简单可用的 CDLaTeX 和 AucTeX 设置. 大家只要把这段代码复制进 init.el 就可以实现视频五分钟说服你用Emacs写LaTeX中的大部分功能.
(defun my/latex-hook ()
(turn-on-cdlatex)
(turn-on-reftex))
(use-package cdlatex
:load-path "lisp/" ; 需要手动从网盘或 https://github.com/cdominik/cdlatex/blob/master/cdlatex.el 下载 cdlatex.el 文件, 并置于 ~/.emacs.d/lisp/ 文件夹下
;; 若使用 straight, 注释前一行, 并取消下一行注释:
;; :straight (:host github :repo "cdominik/cdlatex" )
)
(use-package tex
:ensure auctex
;; 若使用 straight, 注释前一行, 并取消下一行注释:
;; :straight auctex
:custom
(TeX-parse-self t) ; 自动解析 tex 文件
(TeX-PDF-mode t)
(TeX-DVI-via-PDFTeX t)
:config
(setq-default TeX-master t) ; 默认询问主文件
(add-hook 'LaTeX-mode-hook 'my-latex-hook)) ; 加载LaTeX模式设置这个基本设置不一定能实现 PDF 正向或反向搜索, 因为这取决于操作系统与 PDF 阅读器. 如果你想在不同平台上使用 Emacs 并获得统一的 PDF 体验, 可以考虑使用 PDF-tools (见视频 BV1pg4y1s7Z9).
关于 CDLaTeX 的安装, 要注意的是, 它并不在任何的软件源时. 如果使用 package.el, 你需要手动下载这个文件 (Github链接 或者我网盘里的备份), 并用 :load-path 关键字指定文件的目录. 如果是 Straight, 则需要我们指定 Github 仓库的地址 cdominik/cdlatex.
AucTeX 是通过 (use-package tex) 激活的. 因为包名不统一的问题, 我们要额外加入 :ensure auctex 或 :straight auctex. 其实 Emacs 已经内置了 AucTeX, 但不一定是最新版本, 我们这里的 use-package 则会把它更新到最新版.
大家好, 我是小米, 欢迎大家来到我的省时省力写 LaTeX 系列. 本期我们开始介绍 Emacs 的 CDLaTeX 插件. 这次讲解如何使用 CDLaTeX 快速插入数学字母, 符号和字体的功能, 以及如何自定义新的快捷键.
Emacs 中的 LaTeX 编辑主要是依赖 AucTeX 和 CDLaTeX 这两个插件. AucTeX 提供了编辑 LaTeX 的基本功能, 而 CDLaTeX 主要提供了大量简化和易设置的输入方式. 为了安装并在 LaTeX 编辑时启用这两个插件, 我们需要在 init.el 中加入代码:
(defun my/latex-hook ()
(turn-on-cdlatex)
(turn-on-reftex))
(use-package tex
:ensure auctex
;; 若使用 straight, 注释前一行, 并取消下一行注释:
;; :straight auctex
:custom
(TeX-parse-self t) ; 自动解析 tex 文件
(TeX-PDF-mode t)
(TeX-DVI-via-PDFTeX t)
:config
(setq-default TeX-master t) ; 默认询问主文件
(add-hook 'LaTeX-mode-hook 'my/latex-hook)) ; 加载LaTeX模式钩子
(use-package cdlatex
:after tex ; 保证 cdlatex 在 auctex 之后加载
:load-path "lisp/" ; 需要手动从网盘或 https://github.com/cdominik/cdlatex/blob/master/cdlatex.el 下载 cdlatex.el 文件, 并置于 ~/.emacs.d/lisp/ 文件夹下
;; 若使用 straight, 注释前一行, 并取消下一行注释:
;; :straight (:host github :repo "cdominik/cdlatex" )
)使用 straight.el 的用户需要根据注释内容适当调整. 在 (use-package cdlatex ...) 中我们指定了 :after tex, 是为了保证 cdlateX 在 auctex 之后加载. 把 cdlatex 的 use-package 代码块置于 auctex 之后也实现了相同效果; 而加了这一行后, 代码块次序可以随意调整.
LaTeX-mode-hook 是我们打开 LaTeX 文件时需要加载的设置, 这里我们定义了一个新的函数 my/latex-hook (名字可随意), 这样方便我们日后加入更多的功能. 函数的第一行 (turn-on-cdlatex) 就是打开 tex 文件时加载 cdlatex-mode 的命令.
成功设置后, 当我们打开 tex 文件时, 大家应当可以看到模式栏中的 LaTeX/P 和 CDL, 就表示加载了 aucteX 和 cdlatex. 通过 C-h m (m 表示 mode) 可以查看当前加载的所有主要模式和次要模式.
这里的数学符号也包括各种非拉丁字母如 \alpha, \aleph 等. 输入方法是用反引号 (Tab 上方) 加另一个键组成的快捷键输入.
希腊字母可以用 ` + 对应拉丁字母插入, 包括大小写. 例如
\alpha\beta\gamma\Gamma\Sigma如果你不熟悉希腊字母对应的拉丁字母, 没有关系, 只要在按下 ` 后稍稍停顿, 就会弹出一个提示界面. 大家刚开始使用时可以多查看这个提示界面.
大家在提示界面可以看到, 除了希腊字母以外, 我们还可以用同样的方法快速插入数学符号. CDLaTeX 预置了很多好记的默认设置. 例如, ` + 8 插入 \infty, 因为数字 8 放平就是无穷, 又如, ` + * 插入 \times 乘号, ` + + 插入 \cup (并集), ` + > 插入 \rightarrow (右箭头) 等.
CDLaTeX 中连续按下两次反引号 ` 可以打开第二层目录. 第二层通常用于希腊字母的变体, 如
\epsilon, ``e 插入 \varepsilon\rho, ``r 插入 \varrho又或者是一些类似的符号, 如
\rightarrow, ``> 插入 \longrightarrow或者是多个符号最直观的快捷键相同, 但是频率最高的放在第一层, 频率低的放在第二层, 如
\delta, ``d 插入 \partial (求偏导符号)这个目录还有第 3 层, 这里绑定的快捷键就更少了. 默认的是一些数学函数的符号, 如 \sin, \exp 等
``反引号在 LaTeX 中写作几乎不会用到, 除了用于左双引号 `` (laTeX 的右双引号是 '' ). 这很好解决: 在 AucTeX 默认设置下, 第一个输入的双引号 " 会自动转换成为 `` 插入, 第二个输入的双引号 " 会转换为 '' . 例如, “word” 将插入 ``word''.
当然, 你也可以把反引号修改成其它的键, 但是既然无须担心双引号输入的问题, 我觉得改的意义不大. 反引号已经是很好的选择.
Emacs 的最大优势就是我们可以自由地设置. 前面反引号 ` 触发的快捷输入, 我们也可以添加自己需要的符号或调整已有的设置.
这里的所有设置保存在一个叫 cdlatex-math-symbol-alist 的变量中. 我们接下来讲解在 Emacs 如何设置一个变量, 保存设置以及加载设置. 这对其它的变量也是一样.
虽然所有的变量设置都可以通过 init.el 里面的 (setq ...) 语句完成, 对于 cdlatex-math-symbol-alist 这种结构非常复杂的变量, 新手还是建议用 Emacs 自带的设置界面.
打开一个变量的设置界面主要有两种方式 (以 cdlatex-math-symbol-alist 为例)
customize-variable 命令:
M-x customize-variable RET M-x cdlatex-math-symbol-alistcdlatex-math-symbol-alist 并点击 customize我们想调换 `e 和 ``e 原本的快捷键设置, 即实现如下效果: `e 插入 \varepsilon, ``e 插入 \epsilon. (这么做的原因是 \varepsilon 更常用).
cdlatex-math-symbol-alist 的设置界面character 后输入 eRepeat 后按 INS, 新插入的一行输入 \varepsilonRepeat 后按 INS, 新插入的一行输入 \epsilon这就完成了基本设置. 如果大家想绑定 ```e 和 ````e 等, 只需要再加入新的行以及你需要的 LaTeX 宏命令即可.
这里因为 `e 已经在 CDLaTeX 的默认设置中, 所以我们是覆盖了原有设置. 你可以在一开始的按下 ` 的提示界面中看到默认设置, 或者通过查看变量 cdlatex-math-symbol-alist-default.
设置完毕我们会点击 Apply and Save.
Apply: 改变了当前 cdlatex-math-symbol-alist 的値, 重启 Emacs 后失效Save: 保存设置, 重启后仍生效.但是已经打开的 tex 文件是看不到更新的设置的. 想要重新加载 CDLaTeX 的设置. 这有 3 种方法:
tex 文件.tex 文件缓冲区, 按下 C-c C-n.第三种方法可以刷新 LaTeX 模式设置, 也适用于其它与 cdlatex 的设置. 此时, 大家按下反引号 ` 就可以看到更新后的列表了.
原则上这个机制可以插入任意的数学表达式, 如 \stackrel{\mathrm{a.s.}}{=}=, 但是建议只绑定原子化的数学符号. 复杂的表达式更适合用 CDLaTeX 的命令补全功能. (参考 Tab 补全快速插入LaTeX代码)
快捷键要易记, 直观, 凭你的第一感觉就能找到. 否则不能提高输入速度. 大家也可以查看默认的设置寻找灵感. 反例就是把左箭头 \leftarrow 绑到 `> 上.
如果一个键上绑定了多层快捷键, 要考虑不同命令使用的频率, 把最常用的放在第一层, 次常用的放在第二层, 依此类推. 像上面的 \epsilon 和 \varepsilon 的例子.
你也可以绑定自己定义的宏命令. 例如, 我的 `e 绑定的是 \eps, 而在我的 LaTeX 文档引言区中会定义 \newcommand{\eps}{\varepsilon}. 这样的好处可以提高代码的可读性, 方便交流. 毕竟你的导师, 你的合作者未必用 Emacs, 长长的 \varepsilon 会让人眼花. 但是我输入时想到的是希腊字母 epsilon 就应该用 `e 输入.
这里有很大的发挥空间, 因为第二层和第三层基本都是空的, 每个键还分大小写, 可以自由设置 100 多个快捷键. 所以尽情发挥吧.
CDLaTeX 还可以快速插入不同的数学字体, 像 \mathrm{}, \mathbf{} 等等.
例如, 我们常常用粗体 R 表示实数域, 也就是 \mathbf{R}. 我们可以按 3 个键完成输入: R + ' + b
\mathbf{}按单引号 ' 默认会改变前一个字母的字体, 也包括希腊字母, 但只是前面一个字母. 例:
\mathbf{\alpha}a\mathbf{b}.如果需要改变多个字母的字体可以先选择字体, 再输入文本. 这就是第二种方法. 但是输入单引号时前面要是空格或者 $, { 这种功能性字符. 例:
可以用于改变多个字符的字体.
这种插入方式也可以推广到一切 LaTeX 宏命令 + 一对花括号内一段文本的结构. 除了像 \mathbf{}, \mathrm{} 这种数学字体, 还可以输入
数学公式中对字母的其它修饰, 如
\vec{}\hat{}\bar{}这里默认的快捷捷非常直观, 大家也可以按下单引号 ' 稍等以查看提示界面.
非数学公式中的文本字体, 如
\textbf{}\textit{}这里同样的 'b, 用在数学公式内就是 \mathbf{}, 用在文本中就是 \textbf{}. CDLaTeX 会自动检测当前环境是否为数学环境.
触发字体修饰的第三种方法是选先高亮选中一段文本, 再选择修饰. 例如, 选中数学环境外的 blabla, 然后按 ‘b, 则 blabla 会变成 \textbf{blabla}. 如果 blabla 在数学环境内, 则变成 \mathbf{blabla}
第一种方法只能修饰一个字母, 所以嵌套修饰只能使用第二种或第三种方法. 例:
\bar{\mathbf{R}}.\mathbf{R}, 然后高亮选中按下 '-, 变成 \bar{\mathbf{R}}这里需要设置的变量是 cdlatex-math-modify-alist. 打开设置界面的方法和前面一样, 输入
M-x customize-variable RET cdlatex-math-modify-alist
现在我们举一个例子. 假设我们想用 't 在数学公式中插入空心粗体 \mathbb{}. 操作如下
cdlatex-math-modify-alist 设置界面character 输入 t\mathbb\text, 这是 CDLaTeX 的默认设置.Type 改成 command. 两种方式几乎等价但是 command 现在更常用.我们修改完之后, 按 Apply and Save 保存, 然后在 tex 文件缓冲区中用 C-c C-n 刷新设置, 这样我们在数学环境中按下 ' 就能插入空心粗体 \mathbb{} 了.
customize-variable 设置保存位置我们的 init.el 设置里面有这样两行:
(setq custom-file (expand-file-name "custom.el" user-emacs-directory))
;; .....
;; .....
(if (file-exists-p custom-file) (load-file custom-file))这样 Emacs 会把通过 customize-variable 设置的变量保存在我们自定义的 custom.el 的文件中. 内容大概像这样:
(custom-set-variables
;; custom-set-variables was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(cdlatex-math-modify-alist '((116 "\\mathbb" "" t nil nil)))
'(cdlatex-math-symbol-alist '((101 ("\\varepsilon" "\\epsilon")))))
;; ......这里包含了我们前面对 cdlatex-math-modify-alist 和 cdlatex-math-symbol-alist 的设置.
如果没有特别的设置, customize-variable 设置的变量默认会由 Emacs 保存到 init.el 文件的最后. 我们的设置可以区分自己的设置和 Emacs 保存的设置.
当然, 你也可以手动把 custom-set-variables 中的内容用 (setq ...) 语句写在你的 init.el 当中, 尤其可以放在相应插件的 use-package 代码块中. 这样的好处是方便单独管理每个插件的设置, 并且利用 use-package 的延迟加载功能加快打开 Emacs 的时间. 当我们的 CDLaTeX 设置很长的时候, 这样做可以把 Emacs 的启动时间从 10 多秒减少到 1 秒以下. 大家可以在熟悉了 Emacs 的设置后再做尝试, 新手不推荐这么做.
Emacs 中的 CDLaTeX 插件利用反引号 ` 和单引号 ' 开始的快捷键可以快速插入数学字母, 符号和字体. 我们可以通过设置 cdlatex-math-symbol-alist 和 cdlatex-math-modify-alist 这两个变量修改和增加自己喜欢的快捷键.
在下期视频中我们将介绍 CDLaTeX 中 Tab 的命令/模板补全功能. 它可以帮助我们输入一些更复杂的宏命令, 或者插入环境模板等等.
大家好, 我是小米. 本期我们将介绍如何在 CDLaTeX 中用 Tab 补全命令快速地输入复杂的宏命令和环境模板.
补全原理很简单, 用几个字母组合加 Tab 生成一些复杂的命令. 例如, fr + Tab 就会生成 \frac{}{}, 这里光标会停留在第一个括号内; 在第一个括号内完成输入后, 按 Tab 光标就会跳到下一个括号中. 因此, 输入一个常见的分数 \frac{1}{2} 只需要输入 f + r + Tab + 1 + Tab + 2.
CDLaTeX 内置了一些可补全的命令, 可以在 cdlatex-command-alist-default 变量中查看 (C-h v). 我们举一些例子 (以下 ? 所在位置表示补全后光标停留的位置.)
fr + Tab = \frac{?}{}, 根号 sq + Tab = \sqrt{?}qq + Tab = \quad, 大空格 qqq + Tab = \qquadlr( + Tab = \left(?\right), lr[ = \left[?\right]sn + Tab = \section{?}, ss + Tab = \subsection{?}, sss + Tab = \subsubsubsection{?}te + Tab = \text{}se + Tab = \{ \} (set)st + Tab = \stackover{}{}hl + Tab = \hline, hhl + Tab = \\ \hline (表格中常用)big( + Tab = \big(?\big), Big( + Tab = \Big(?\Big), bigg( + Tab = \bigg(?\bigg) (\big, \Big, \bigg 等是 amsmath 中调整括号大小的命令)lr< + Tab = \langle?\rangle, 一对尖括号 \(\langle \rangle\).显然, 这里的关键字选择都是用命令中最开始的两到三个字母, 这样非常好记, 也很容易使用.
大家可以看到这里的 Tab 补全其实就是一个替换字符串的过程. 当然字符串中也可以包括换行, 因此同样的机制也可以输入形如 \begin{XXX} ... \end{XXX} 的环境.
equation 环境equ + Tab 插入如下模板:
其中, \label{eq:XXX} 是 CDLaTeX 调用 reftex 自动生成的数字标签.
类似的数学公式环境还有如
ali + Tab 插入 align 环境 (自动生成标签), ali* + Tab 插入 align* 环境 (无标签)gat + Tab 插入 gather 环境 (自动生成标签), gat* + Tab 插入 gather* 环境 (无标签)enu + Tab 插入
此时, 在 enumerate 环境中:
it + Tab = \item\item这里, enu + Tab 等同于用 cdlatex-environment (C-c { ) 插入 enumerate 环境
类似的还有
ite + Tab 插入 itemize 环境fg + Tab 插入 figure 环境现在我们介绍如何自定义你自己需要的补全命令. 默认的补全命令都在 cdlatex-command-alist-default 中, 而现有的所有命令, 包括内置的和自定义的, 都可以通过 C-c ? 查看.
在用 C-c ? 查看时, 我们会在最右一列看到 TEXT 和 MATH 关键字:
MATH 关键字表示补全可以在 数学环境 中触发TEXT 关键字表示补全可以在 文本环境 中触发加入自定义新的补全命令通过修改变量 cdlatex-command-alist. 方法是调用 M-x customize-variable =, 然后输入变量名 =cdlatex-command-alist.
例子: te + Tab 输入 \text{?} (光标停在括号内). 我们需要填入如下参数
teinsert \text{}\text{?} (? 表示光标停留的位置)cdlatex-position-cursor (如果需要指定光标则必填!)nil (这是上面 hook 的参数)nil, Math mode: t保存设置 (Apply and Save) 之后, 在已经打开的 tex 文件中用 C-c C-n 可以刷新设置, 就可以开始使用了.
例子: big{ + Tab 插入 \big\{? \big\}
big{insert \big\{? \big\}\big\{? \big\cdlatex-position-cursornilnil, Math mode: t这里有两个细节. 第一是我们在 ? 后面手动多加了一个空格, 这里因为在 LaTeX 编辑模式下, 按 Tab 会自动跳到一个空格位置, 因此我们尽量用空格把代码分隔开来, 便于以后的修改; 既然如此, 我们干脆在模板中加入这个空格.
第二个细节时我们的替换字符串最后少了一个 }. 这是因为 CDLaTeX 中默认会自动匹配输入一对括号 {}. 因此我们只需要补全除了右花括号 } 以外的部分就可以.
CDLaTeX 中自动匹配的括号可以通过 cdlatex-paired-parens 设置, 只针对 $([{<| 6 个字符. 我一般会自动匹配
$([{ . 这里大家只需要注意你在 cdlatex-command-alist 中的设置与 cdlatex-paired-parens 保持一致就可以了.
例子: case + Tab 插入
caseinsert \begin{cases} \end{cases}cdlatex-position-cursornilnil, Math mode: t插入环境除了直接在 cdlatex-command-alist 的 Replacement 中写入环境模板以外, 还可以通过调用函数 cdlatex-environment 的方式实现.
在 LaTeX 编辑模式中, 有两种用环境名插入环境的方法
LaTeX-environment (C-c C-e) + description: 这会调用 AucTeX 的环境模板cdlatex-environment (C-c { ) + description: 这会调用 CDLaTeX 的环境模板.两种模板略有不同. 这第二种插入环境的方法就是用 Tab 补全触发第二个命令.
例子: des + Tab 插入 description 环境
desinsert \begin{description} \end{description}nilcdlatex-environment("description")t, Math mode: nil这里需要注意的是我们用了一个不同的 hook! 所插入的模板是由 cdlatex-env-alist, cdlatex-env-alist-default 控制的.
使用这种方式插入环境的好处:
AUTOLABEL 关键字 (equ + Tab 生成带标签的环境的实现方式)item 模板 (C-<enter> 触发)不过, 在一般情况下, 第一种方法直接把环境模板写进 cdlatex-command-alist 也能实现大部分的功能了.
我的 cdlatex-command-alist 变量, 仅做抛砖引玉之用.
(setq cdlatex-command-alist
'(("eq" "insert pairs of \\[ \\]" "\\[ ? \\]" cdlatex-position-cursor nil t t)
("Big(" "insert Big ()" "\\Big( ? \\Big" cdlatex-position-cursor nil nil t)
("Big[" "insert Big[" "\\Big[ ? \\Big" cdlatex-position-cursor nil nil t)
("Big\\|" "insert Big \\|" "\\Big\\| ? \\Big\\|" cdlatex-position-cursor nil nil t)
("Big{" "insert Big{}" "\\Big\\{ ? \\Big\\" cdlatex-position-cursor nil nil t)
("Big|" "insert Big|" "\\Big| ? \\Big|" cdlatex-position-cursor nil nil t)
("aali" "insert equation" "\\left\\{\\begin{aligned}\n? \n\\end{aligned}\\right." cdlatex-position-cursor nil nil t)
("alb" "Insert beamer alert block with overlay" "\\begin{alertblock}<+->{ ? } \n\n\\end{alertblock}" cdlatex-position-cursor nil t nil)
("alb*" "Insert beamer alert block without overlay" "\\begin{alertblock}{ ? } \n\n\\end{alertblock}" cdlatex-position-cursor nil t nil)
("big(" "insert big ()" "\\big( ? \\big" cdlatex-position-cursor nil nil t)
("big[" "insert big []" "\\big[ ? \\big" cdlatex-position-cursor nil nil t)
("big\\|" "insert big \\|" "\\big\\| ? \\big\\|" cdlatex-position-cursor nil nil t)
("bigg(" "insert bigg()" "\\bigg( ? \\bigg" cdlatex-position-cursor nil nil t)
("bigg[" "insert bigg[" "\\bigg[ ? \\bigg" cdlatex-position-cursor nil nil t)
("bigg\\|" "insert bigg\\|" "\\bigg\\| ? \\bigg\\|" cdlatex-position-cursor nil nil t)
("bigg{" "insert bigg{}" "\\bigg\\{ ? \\bigg\\" cdlatex-position-cursor nil nil t)
("bigg|" "insert bigg|" "\\bigg| ? \\bigg|" cdlatex-position-cursor nil nil t)
("big{" "insert big {}" "\\big\\{ ? \\big\\" cdlatex-position-cursor nil nil t)
("big|" "insert big|" "\\big| ? \\big|" cdlatex-position-cursor nil nil t)
("blo" "Insert beamer block with overlay" "\\begin{block}<+->{ ? } \n\n\\end{block}" cdlatex-position-cursor nil t nil)
("blo*" "Insert beamer block WITHOUT overlay" "\\begin{block}{ ? } \n\n\\end{block}" cdlatex-position-cursor nil t nil)
("bn" "binomial" "\\binom{?}{}" cdlatex-position-cursor nil nil t)
("capl" "insert \\bigcap\\limits_{}^{}" "\\bigcap\\limits_{?}^{}" cdlatex-position-cursor nil nil t)
("case" "insert cases" "\\begin{cases}\n? & \\\\\n &\n\\end{cases}" cdlatex-position-cursor nil nil t)
("cd" "insert cdots" "\\cdots" nil nil t t)
("cupl" "insert \\bigcup\\limits_{}^{}" "\\bigcup\\limits_{?}^{}" cdlatex-position-cursor nil nil t)
("dd" "insert ddots" "\\ddots" nil nil t t)
("def" "insert definition env" "" cdlatex-environment ("definition") t nil)
("des" "insert description" "" cdlatex-environment ("description") t nil)
("enu*" "insert enu" "\\begin{enumerate}\n\\item ?\n\\end{enumerate}" cdlatex-position-cursor nil t nil)
("equ*" "insert unlabel equation" "" cdlatex-environment ("equation*") t nil)
("exb" "Insert beamer example block with overlay" "\\begin{exampleblock}<+->{ ? } \n\n\\end{exampleblock}" cdlatex-position-cursor nil t nil)
("exb*" "Insert beamer example block without overlay" "\\begin{exampleblock}{ ? } \n\n\\end{exampleblock}" cdlatex-position-cursor nil t nil)
("exe" "Insert exercise" "\\begin{exercise}\n? \n\\end{exercise}" cdlatex-position-cursor nil t nil)
("fra" "insert frame (for beamer)" "" cdlatex-environment ("frame") t nil)
("hhl" "insert \\ \\hline" "\\\\ \\hline" ignore nil t nil)
("hl" "insert \\hline" "\\hline" ignore nil t nil)
("ipenu" "insert in paragraph enumerate" "" cdlatex-environment ("inparaenum") t nil)
("ipite" "insert in paragraph itemize" "" cdlatex-environment ("inparaitem") t nil)
("it" "insert \\item" "\\item?" cdlatex-position-cursor nil t nil)
("ld" "insert ldots" "\\ldots" nil nil t t)
("lem" "insert lemma env" "" cdlatex-environment ("lemma") t nil)
("liml" "insert \\lim\\limits_{}" "\\lim\\limits_{?}" cdlatex-position-cursor nil nil t)
("lr<" "insert bra-ket" "\\langle ? \\rangle" cdlatex-position-cursor nil nil t)
("myenu" "insert in my enumerate for beamer" "" cdlatex-environment ("myenumerate") t nil)
("myite" "insert in my itemize for beamer" "" cdlatex-environment ("myitemize") t nil)
("ons" "" "\\onslide<?>{ }" cdlatex-position-cursor nil t t)
("pa" "insert pause" "\\pause" ignore nil t nil)
("pro" "insert proof env" "" cdlatex-environment ("proof") t nil)
("prodl" "insert \\prod\\limits_{}^{}" " \\prod\\limits_{?}^{}" cdlatex-position-cursor nil nil t)
("prop" "insert proposition" "" cdlatex-environment ("proposition") t nil)
("se" "insert \\{\\}" "\\{ ? \\}" cdlatex-position-cursor nil nil t)
("spl" "insert split" "" cdlatex-environment ("split") nil t)
("st" "stackrel" "\\stackrel{?}{}" cdlatex-position-cursor nil nil t)
("te" "insert text" "\\text{?}" cdlatex-position-cursor nil nil t)
("thm" "insert theorem env" "" cdlatex-environment ("theorem") t nil)
("vd" "insert vdots" "\\vdots" nil nil t t)))你是否遇到过以下困扰:
RefTeX 让你轻松创建、引用和管理标签,随心所欲,毫无压力。
用 M-x + reftex-label, 或者 lbl + Tab (CDLaTeX 的命令补全) 均可以生成形如 \label{type:XXXX} 的标签.
标签的内容根据标签的类型, 有以下的方式决定.
\label{eq:NNN} 或者列表环境 \label{it:NNN}, 这里 NNN 表示自动生成的数字. 它是 RefTeX 在当前文档中找到的可以使用的最小数字.\section{First Second Third} 自动生成 \label{sec:first-second-third}用 M-x + reftex-reference, C-c [ 或者 ref + Tab (CDLaTeX 命令补全) 均可以触发引用交叉标签.
\ref, \pageref 等e: 公式标签 (eq:), 包括 equation, 以及 align, gather 等 amsmath 定义的数学公式环境i: 列表标签 (it:), 列表环境 item 的标签s: 章节标签 (sec:), f: 图片标签 (fig:), 等等\ref{} 命令中包含在我们一开始的 AucTeX 配置代码中:
(defun my/latex-hook ()
(turn-on-cdlatex)
(turn-on-reftex))
(add-hook 'LaTeX-mode-hook 'my/latex-hook)默认使用 \ref{} 格式, ref + Tab 直接进入标签选择
(setq reftex-ref-macro-prompt nil)在标签选择界面, 可以用 v 和 V 去改变引用格式.
reftex-reference 会识别光标前的文字自动选择标签类型. 例如, equation 后插入标签会默认类型为 e
可以由变量 reftex-guess-label-type 控制
(setq reftex-guess-label-type t) ; 默认值可以通过 M-x customize-variable 界面修改 reftex-label-alist
t, 绑定 theorem 环境, 标签以 thm: 开头\macro: theoremtthm:Theorem, 定理当我们选择某个标签类型如 t 时
reftex-trust-label-prefix 为 nil, 只会用环境名 theorem 来决定标签类型reftex-trust-label-prefix 为 t, 也会用 thm: 来识别标签类型.(setq reftex-trust-label-prefix t)e 类型加入更多的 magic worde公式可以通过 M-x customize-variable 界面修改 reftex-insert-label-flag
t 加进去.如果一个类型没有在两个列表中出现, 则使用数字作为标签.
(setq reftex-label-menu-flags '(t t nil nil t nil t nil)) ; 在标签选择界面;; 为 LaTeX 模式加载 RefTeX
(defun my/latex-hook ()
(turn-on-cdlatex)
(turn-on-reftex))
(add-hook 'LaTeX-mode-hook 'my/latex-hook)
(setq reftex-ref-macro-prompt nil)
(setq reftex-guess-label-type t) ; 默认值
(setq reftex-trust-label-prefix t)
(setq reftex-label-menu-flags '(t t nil nil t nil t nil)) ; 标签选择界面跟随界面
;; 以及通过 customize-variable 对 reftex-label-alist 和 reftex-insert-label-flag 的设置pdf-tools 的理由在用 Emacs 编写 LaTeX 文档的过程中, 你是否…
又或者, 你想用 Emacs 做读书笔记, 需要同时:
pdf-tools 可以完美实现这些目标.
pdf-tools 的优点与 DocView (Emacs 中内置的 pdf 阅读器) 比较
DocView: 不清晰, 阅读效果差, 读取速度慢pdf-tools:auctex 配合使用, 支持对编译后 pdf 进行正向/反向搜索latex 文档org-noter 在 pdf 上做读书笔记分为两部分
melpa-stable 在 Emacs 包的列表中
可以通过查看 package-archives 变量进行确认 (require 'package) ;; Emacs 包管理器
(setq package-check-signature nil) ;; 如果有签名验证问题, 可以设置不检查签名
(setq package-archives '(("elpa" . "http://tromey.com/elpa/")
("melpa-stable" . "https://stable.melpa.org/packages/") ;; 下载 pdf-tools 只需要这个
("melpa" . "https://melpa.org/packages/")
("gnu" . "http://elpa.gnu.org/packages/")))pdf-toolsmelpa-stable 版本 (2023.3: melpa 版本仍有 bug)epdfinfo.exe 的安装epdfinfo.exe 及其它一些依赖文件 (例如 libpopper-<version>.dll) 可以帮助 Emacs 读取 pdf 文件
两种方法
msys2msys2 安装 epdfinfomsys2?可以将许多开源程序本地化编译为 Windows 程序的平台
优点
Git, Emacs, texlive, gcc, python …msys2 官网上 https://www.msys2.org/ 下载安装程序 msys2-x86_x64-<date>.exe. 默认安装目录为 C:/msys64/.C:/msys64/ 下 mingw64.exe. 会弹出一个命令行终端 pacman -S mingw-w64-x86_64-emacs-pdf-tools-serverC:\msys64\mingw64\bin 中找到 epdfinfo.exe.C:\msys64\mingw64\bin 加入环境变量 PATHpdf-tools在 init.el 文件中加入
(pdf-tools-install)如果想延迟启动 (如打开 pdf 文件后再启动, 节省 Emacs 启动时间), 可以用下面的代码替换
(pdf-loader-install)AucTeX 使用的配置保持不变的设置
(setq TeX-PDF-mode t)
(setq TeX-source-correlate-mode t) ;; 编译后开启正反向搜索
(setq TeX-source-correlate-method 'synctex) ;; 正反向搜索的执行方式
(setq TeX-source-correlate-start-server t) ;; 不再询问是否开启服务器以执行反向搜索使用 Sumatra PDF 的配置
(setq TeX-view-program-list
'(("Sumatra PDF" ("\"C:/Program Files/SumatraPDF/SumatraPDF.exe\" -reuse-instance" (mode-io-correlate " -forward-search %b %n ") " %o"))))
(assq-delete-all (quote output-pdf) TeX-view-program-selection)
(add-to-list 'TeX-view-program-selection '(output-pdf "Sumatra PDF")pdf-tools 的配置
(setq TeX-view-program-selection '((output-pdf "PDF Tools"))) ;; 用pdf-tools 打开 pdf
(add-hook 'TeX-after-compilation-finished-functions
#'TeX-revert-document-buffer) ;; 在完成编译后刷新 pdf 文件我的设置: 尽量把移动绑定在左手 (awsd), 空出右手进行鼠标操作.
(define-key pdf-view-mode-map
"d" 'pdf-view-next-page-command) ;; 向后翻页
(define-key pdf-view-mode-map
"a" 'pdf-view-previous-page-command) ;; 向前翻页
(define-key pdf-view-mode-map
"s" 'pdf-view-scroll-up-or-next-page) ;; 向下滑动
(define-key pdf-view-mode-map
"w" 'pdf-view-scroll-down-or-previous-page) ;; 向上滑动我的设置:
(require 'pdf-annot)
(define-key pdf-annot-minor-mode-map (kbd "C-a a") 'pdf-annot-add-highlight-markup-annotation) ;; 高亮
(define-key pdf-annot-minor-mode-map (kbd "C-a s") 'pdf-annot-add-squiggly-markup-annotation) ;; 波浪线
(define-key pdf-annot-minor-mode-map (kbd "C-a u") 'pdf-annot-add-underline-markup-annotation) ;; 下划线
(define-key pdf-annot-minor-mode-map (kbd "C-a d") 'pdf-annot-delete) ;; 删除这里重新绑定常用的返回功能 (小知识: 在 Sumatra PDF 里对应 Alt-<right>)
(require 'pdf-history)
(define-key pdf-history-minor-mode-map "b" 'pdf-history-backward)打开 pdf 文件时自动放缩
(add-hook 'pdf-view-mode-hook 'pdf-view-fit-width-to-window) ;; 自动放大到页宽这可能是安装了 2023 年后 pdf-tools 的版本导致的. 可以从 M-x package-list-package 界面中确认是从 melpa-stable 中安装的
(invalid-function pdf-view-current-page) 的错误信息这是因为在 28.x 以后的 Emacs 版本中会开启本地化编译 (native compilation), 而 pdf-tools 中有一些语法过时了, 在本地化编译时会报错. 如果这个 bug 不解决的话, 不影响 pdf-tools 的使用, 但是会稍微降低 pdf 渲染的速度.
用 C-h v <enter> system-configuration-options <enter> 查询, 如果变量包含字段 --with-native-compilation, 则说明当前版本支持本地化编译
本地化编译后的文件会放在 .emacs.d/eln-cache/ 中, 以 .elc 结尾.
如果在上面的目录下已经产生了 pdf-*.elc 文件, 请先删除.
(setq no-native-compile t)pdf-tools 的本地化编译 (setq native-comp-deferred-compilation-deny-list '(".*pdf.*")) (pdf-tools-install)
(setq native-comp-deferred-compilation-deny-list '(".*pdf.*"))
(setq TeX-view-program-selection '((output-pdf "PDF Tools"))) ;; 用pdf-tools 打开 pdf
(add-hook 'TeX-after-compilation-finished-functions
#'TeX-revert-document-buffer) ;; 在完成编译后刷新 pdf 文件
(define-key pdf-view-mode-map "d" 'pdf-view-next-page-command) ;; 向后翻页
(define-key pdf-view-mode-map "a" 'pdf-view-previous-page-command) ;; 向前翻页
(define-key pdf-view-mode-map "s" 'pdf-view-scroll-up-or-next-page) ;; 向下滑动
(define-key pdf-view-mode-map "w" 'pdf-view-scroll-down-or-previous-page) ;; 向上滑动
(require 'pdf-annot)
(define-key pdf-annot-minor-mode-map (kbd "C-a a") 'pdf-annot-add-highlight-markup-annotation) ;; 高亮
(define-key pdf-annot-minor-mode-map (kbd "C-a s") 'pdf-annot-add-squiggly-markup-annotation) ;; 波浪线
(define-key pdf-annot-minor-mode-map (kbd "C-a u") 'pdf-annot-add-underline-markup-annotation) ;; 下划线
(define-key pdf-annot-minor-mode-map (kbd "C-a d") 'pdf-annot-delete) ;; 删除
(require 'pdf-history)
(define-key pdf-history-minor-mode-map "b" 'pdf-history-backward)
(add-hook 'pdf-view-mode-hook 'pdf-view-fit-width-to-window) ;; 自动放大到页宽pdf-tools 的 Github 仓库: https://github.com/vedang/pdf-toolsmsys2 官网 https://www.msys2.org/epdfinfo.exe 可用版本: https://www.jianguoyun.com/p/DTiBwxMQ856tCxiflP0EIAApdf-tools 的理由在用 Emacs 编写 LaTeX 文档的过程中, 你是否…
又或者, 你想用 Emacs 做读书笔记, 需要同时:
pdf-tools 可以完美实现这些目标.
pdf-tools 的优点与 DocView (Emacs 中内置的 pdf 阅读器) 比较
DocView: 不清晰, 阅读效果差, 读取速度慢pdf-tools:auctex 配合使用, 支持对编译后 pdf 进行正向/反向搜索latex 文档org-noter 在 pdf 上做读书笔记分为两部分
melpa-stable 在 Emacs 包的列表中
可以通过查看 package-archives 变量进行确认 (require 'package) ;; Emacs 包管理器
(setq package-check-signature nil) ;; 如果有签名验证问题, 可以设置不检查签名
(setq package-archives '(("elpa" . "http://tromey.com/elpa/")
("melpa-stable" . "https://stable.melpa.org/packages/") ;; 下载 pdf-tools 只需要这个
("melpa" . "https://melpa.org/packages/")
("gnu" . "http://elpa.gnu.org/packages/")))pdf-toolsmelpa-stable 版本 (2023.3: melpa 版本仍有 bug)epdfinfo.exe 的安装epdfinfo.exe 及其它一些依赖文件 (例如 libpopper-<version>.dll) 可以帮助 Emacs 读取 pdf 文件
两种方法
msys2msys2 安装 epdfinfomsys2?可以将许多开源程序本地化编译为 Windows 程序的平台
优点
Git, Emacs, texlive, gcc, python …msys2 官网上 https://www.msys2.org/ 下载安装程序 msys2-x86_x64-<date>.exe. 默认安装目录为 C:/msys64/.C:/msys64/ 下 mingw64.exe. 会弹出一个命令行终端 pacman -S mingw-w64-x86_64-emacs-pdf-tools-serverC:\msys64\mingw64\bin 中找到 epdfinfo.exe.C:\msys64\mingw64\bin 加入环境变量 PATHpdf-tools在 init.el 文件中加入
(pdf-tools-install)如果想延迟启动 (如打开 pdf 文件后再启动, 节省 Emacs 启动时间), 可以用下面的代码替换
(pdf-loader-install)AucTeX 使用的配置保持不变的设置
(setq TeX-PDF-mode t)
(setq TeX-source-correlate-mode t) ;; 编译后开启正反向搜索
(setq TeX-source-correlate-method 'synctex) ;; 正反向搜索的执行方式
(setq TeX-source-correlate-start-server t) ;; 不再询问是否开启服务器以执行反向搜索使用 Sumatra PDF 的配置
(setq TeX-view-program-list
'(("Sumatra PDF" ("\"C:/Program Files/SumatraPDF/SumatraPDF.exe\" -reuse-instance" (mode-io-correlate " -forward-search %b %n ") " %o"))))
(assq-delete-all (quote output-pdf) TeX-view-program-selection)
(add-to-list 'TeX-view-program-selection '(output-pdf "Sumatra PDF")pdf-tools 的配置
(setq TeX-view-program-selection '((output-pdf "PDF Tools"))) ;; 用pdf-tools 打开 pdf
(add-hook 'TeX-after-compilation-finished-functions
#'TeX-revert-document-buffer) ;; 在完成编译后刷新 pdf 文件我的设置: 尽量把移动绑定在左手 (awsd), 空出右手进行鼠标操作.
(define-key pdf-view-mode-map
"d" 'pdf-view-next-page-command) ;; 向后翻页
(define-key pdf-view-mode-map
"a" 'pdf-view-previous-page-command) ;; 向前翻页
(define-key pdf-view-mode-map
"s" 'pdf-view-scroll-up-or-next-page) ;; 向下滑动
(define-key pdf-view-mode-map
"w" 'pdf-view-scroll-down-or-previous-page) ;; 向上滑动我的设置:
(require 'pdf-annot)
(define-key pdf-annot-minor-mode-map (kbd "C-a a") 'pdf-annot-add-highlight-markup-annotation) ;; 高亮
(define-key pdf-annot-minor-mode-map (kbd "C-a s") 'pdf-annot-add-squiggly-markup-annotation) ;; 波浪线
(define-key pdf-annot-minor-mode-map (kbd "C-a u") 'pdf-annot-add-underline-markup-annotation) ;; 下划线
(define-key pdf-annot-minor-mode-map (kbd "C-a d") 'pdf-annot-delete) ;; 删除这里重新绑定常用的返回功能 (小知识: 在 Sumatra PDF 里对应 Alt-<right>)
(require 'pdf-history)
(define-key pdf-history-minor-mode-map "b" 'pdf-history-backward)打开 pdf 文件时自动放缩
(add-hook 'pdf-view-mode-hook 'pdf-view-fit-width-to-window) ;; 自动放大到页宽这可能是安装了 2023 年后 pdf-tools 的版本导致的. 可以从 M-x package-list-package 界面中确认是从 melpa-stable 中安装的
(invalid-function pdf-view-current-page) 的错误信息这是因为在 28.x 以后的 Emacs 版本中会开启本地化编译 (native compilation), 而 pdf-tools 中有一些语法过时了, 在本地化编译时会报错. 如果这个 bug 不解决的话, 不影响 pdf-tools 的使用, 但是会稍微降低 pdf 渲染的速度.
用 C-h v <enter> system-configuration-options <enter> 查询, 如果变量包含字段 --with-native-compilation, 则说明当前版本支持本地化编译
本地化编译后的文件会放在 .emacs.d/eln-cache/ 中, 以 .elc 结尾.
如果在上面的目录下已经产生了 pdf-*.elc 文件, 请先删除.
(setq no-native-compile t)pdf-tools 的本地化编译 (setq native-comp-deferred-compilation-deny-list '(".*pdf.*")) (pdf-tools-install)
(setq native-comp-deferred-compilation-deny-list '(".*pdf.*"))
(setq TeX-view-program-selection '((output-pdf "PDF Tools"))) ;; 用pdf-tools 打开 pdf
(add-hook 'TeX-after-compilation-finished-functions
#'TeX-revert-document-buffer) ;; 在完成编译后刷新 pdf 文件
(define-key pdf-view-mode-map "d" 'pdf-view-next-page-command) ;; 向后翻页
(define-key pdf-view-mode-map "a" 'pdf-view-previous-page-command) ;; 向前翻页
(define-key pdf-view-mode-map "s" 'pdf-view-scroll-up-or-next-page) ;; 向下滑动
(define-key pdf-view-mode-map "w" 'pdf-view-scroll-down-or-previous-page) ;; 向上滑动
(require 'pdf-annot)
(define-key pdf-annot-minor-mode-map (kbd "C-a a") 'pdf-annot-add-highlight-markup-annotation) ;; 高亮
(define-key pdf-annot-minor-mode-map (kbd "C-a s") 'pdf-annot-add-squiggly-markup-annotation) ;; 波浪线
(define-key pdf-annot-minor-mode-map (kbd "C-a u") 'pdf-annot-add-underline-markup-annotation) ;; 下划线
(define-key pdf-annot-minor-mode-map (kbd "C-a d") 'pdf-annot-delete) ;; 删除
(require 'pdf-history)
(define-key pdf-history-minor-mode-map "b" 'pdf-history-backward)
(add-hook 'pdf-view-mode-hook 'pdf-view-fit-width-to-window) ;; 自动放大到页宽pdf-tools 的 Github 仓库: https://github.com/vedang/pdf-toolsmsys2 官网 https://www.msys2.org/epdfinfo.exe 可用版本: https://www.jianguoyun.com/p/DTiBwxMQ856tCxiflP0EIAA文本编辑中的两个要素
【Emacs+LaTeX教程】Emacs最强内置pdf阅读功能pdf-tools简介 缺点
preview-latex【教程】LaTeX+Emacs从零开始2-6节:所见即所得之Preview-latex 缺点
prettify-symbols-mode优点
版本要求
auctex 查看)M-x prettify-symbols-mode
init.el 文件设置 (defun my-latex-hook ()
(prettify-symbols-mode t))
(add-hook 'LaTeX-mode-hook 'my-latex-hook)保证 Unicode 数学符号可以正确显示
(set-fontset-font "fontset-default" 'mathematical "Cambria Math")设置自动展开光标附近的宏命令.
(setq prettify-symbols-unprettify-at-point t)tips: 如果只想删除刚输入的一个宏命令, 最快的方法是用 C-/ 撤消, 而不是一个个字符删除.
(require 'tex-mode)
(defun my/more-prettified-symbols ()
(mapc (lambda (pair) (cl-pushnew pair tex--prettify-symbols-alist))
'(("\\Z" . 8484) ;; 大多数人在latex中会用 \Z, \Q, \N, \R 表示数域
("\\Q" . 8474)
("\\N" . 8469)
("\\R" . 8477)
("\\eps" . 949)
("\\ONE" . #x1D7D9)
("\\mathbb{S}" . #x1D54A)
("\\PP" . #x2119) ;; 个人需要, 经常要使用P和E的数学字体
("\\P" . #x1D5AF )
("\\Pp" . #x1D40F)
("\\E" . #x1D5A4)
("\\Ee" . #x1D404)
("\\EE" . #x1D53C )
("\\Fc" . #x2131)
("\\Nc" . #x1D4A9))))
(my/more-prettified-symbols)将 ("<latex 宏命令>" . <unicode 编码>) 加入列表中
\\” 开头, 表示一个普通的 “\”.#x” 表示是 16 进制数字, 否则就是 10 进制个人加入编码的原则
\N , \Z 等大多数人使用的宏命令, 这样可以减少与他人合作的障碍E, P. ;; 以下为LaTeX mode相关设置
(setq-default TeX-master nil) ;; 编译时问询主文件名称
(setq TeX-parse-selt t) ;; 对新文件自动解析(usepackage, bibliograph, newtheorem等信息)
;; PDF正向搜索相关设置
(setq TeX-PDF-mode t)
(setq TeX-source-correlate-mode t)
(setq TeX-source-correlate-method 'synctex)
(setq TeX-view-program-selection '((output-pdf "PDF Tools"))) ;; 用pdf-tools 打开 pdf
(add-hook 'TeX-after-compilation-finished-functions
#'TeX-revert-document-buffer) ;; 在完成编译后刷新 pdf 文件
;; 打开TeX文件时应该加载的mode/执行的命令
(defun my-latex-hook ()
(turn-on-cdlatex) ;; 加载cdlatex
(outline-minor-mode) ;; 加载outline mode
(prettify-symbols-mode t)
(turn-on-reftex) ;; 加载reftex
(outline-hide-body)) ;; 打开文件时只显示章节标题
(add-hook 'LaTeX-mode-hook 'my-latex-hook)
(setq prettify-symbols-unprettify-at-point t)
(set-fontset-font "fontset-default" 'mathematical "Cambria Math")
(require 'tex-mode)
(defun my/more-prettified-symbols ()
(mapc (lambda (pair) (cl-pushnew pair tex--prettify-symbols-alist))
'(("\\Z" . 8484) ;; 大多数人在latex中会用 \Z, \Q, \N, \R 表示数域
("\\Q" . 8474)
("\\N" . 8469)
("\\R" . 8477)
("\\eps" . 949)
("\\ONE" . #x1D7D9)
("\\mathbb{S}" . #x1D54A)
("\\PP" . #x2119) ;; 个人需要, 经常要使用P和E的数学字体
("\\P" . #x1D5AF )
("\\Pp" . #x1D40F)
("\\E" . #x1D5A4)
("\\Ee" . #x1D404)
("\\EE" . #x1D53C )
("\\Fc" . #x2131)
("\\Nc" . #x1D4A9))))
(my/more-prettified-symbols)