从零搭建个人知识库: Org 笔记中高效写 LaTeX
前言
在 Org-mode 中获得和 LaTeX 模式 一致 的 LaTeX 代码体验:
- 使用 CDLaTeX
- 语法高亮
- 数学符号
prettify - 括号自动匹配
- 快速公式预览
- LaTeX 导言区 (preamble) 共享
默认设置
- 输入数学公式
- 行内公式:
\(...\),$...$ - 行间公式
\[...\],$$...$$,\begin{XXX}...\end{XXX}
- 行内公式:
- 在行间数学公式中用 C-c ‘ 可进入 LaTeX 编辑模式. (有些版本的
org-mode的 LaTeX 编辑模式是采用latex-mode);; 你自己的 LaTeX 模式设置 (defun my/latex-hook () (turn-on-cdlatex) (turn-on-reftex)) (add-hook 'LaTeX-mode-hook 'my/latex-hook) (add-hook 'latex-mode-hook 'my/latex-hook) - 数学公式预览
- 预览当前位置/当前选中区域 C-c C-x C-l
- 取消预览: C-u + C-c C-x C-l
打开 CDLaTeX 模式
Org-mode 有一个专属的 org-cdlatex-mode, 打开后可以使用 CDLaTeX 模式中定义的所有快捷键命令. 关于 CDLaTeX 可以参考
(add-hook 'org-mode-hook #'org-cdlatex-mode) ;; 在 org-mode 中使用 cdlatex主要区别:
- Tab 要兼容
org-mode中的展开/折叠功能- 环境补全只能用在行首, 如
equ+ Tab =\begin{equation}\end{equation} - 数学环境中 Tab 的功能与 LaTeX 一致, 如
qq+ Tab =\quad - 其余情形 Tab 执行 Org-mode 的展开/折叠
- 环境补全只能用在行首, 如
- 反引号 ` 输入数学符号可以在非数学环境中使用 (但是符号不能被预览, 只能 prettify).
$,(等不再自动匹配.
语法高亮与美化
(setq org-highlight-latex-and-related '(native latex entities)) ;; LaTeX 语法高亮设置
(setq org-pretty-entities t) ;; LaTeX 代码的 prettify
(setq org-pretty-entities-include-sub-superscripts nil) ;; 不隐藏 LaTeX 的上下标更容易编辑org-pretty-entities和 LaTeX 模式中prettify-symbol-mode共享变量tex--prettify-symbols-alist的设置- 设置
tex--prettify-symbols-alist可参考 【Emacs+LaTeX教程】如何优雅地预览数学公式
括号和 $ 匹配问题
其实也可以用 cdlatex-mode 替代 org-cdlatex-mode, 但是确实有一些副作用.
折衷的解决方法: 复写 cdlatex-mode 中的括号和 $ 匹配函数.
;; org-cdlatex-mode 中使用 cdlatex 的自动匹配括号, 并把 $...$ 换成 \( ... \)
(defun my/insert-inline-OCDL ()
(interactive)
(insert "\\(") ;; 把 "\\(" 和 "\\)" 替换成 "$" 就能实现输入成对 "$" 的功能.
(save-excursion (insert "\\)" )))
(defun my/insert-bra-OCDL ()
(interactive)
(insert "(")
(save-excursion (insert ")" )))
(defun my/insert-sq-bra-OCDL ()
(interactive)
(insert "[")
(save-excursion (insert "]" )))
(defun my/insert-curly-bra-OCDL ()
(interactive)
(insert "{")
(save-excursion (insert "}" )))
(define-key org-cdlatex-mode-map (kbd "$") 'my/insert-inline-OCDL)
(define-key org-cdlatex-mode-map (kbd "(") 'my/insert-bra-OCDL)
(define-key org-cdlatex-mode-map (kbd "[") 'my/insert-square-bra-OCDL)
(define-key org-cdlatex-mode-map (kbd "{") 'my/insert-curly-bra-OCDL)这里还做了一个优化: 把 $ 绑定成输入 \(?\), 原因有二:
- 用
$输入行内公式, 要求公式内紧临$的字符不能是空格, 否则不能识别为数学环境. 识别失败又会导致语法高亮、cdlatex-mode不能触发等问题 - 用
$输入行内公式, 后面必须是空格. 这和 LaTeX 模式下输入习惯不同.
用 \(?\) 替代就没有以上所有问题.
公式预览
基本命令
- C-c C-x C-l: 预览/取消预览当前光标所在数学公式, 或预览当前章节所有数学公式
- C-u + C-c C-x C-l: 取消 预览当前 章节 所有数学公式
- C-u C-u + C-c C-x C-l: 预览当前 缓冲区 所有数学公式
- C-u C-u C-u + C-c C-x C-l: 取消 预览当前 缓冲区 所有数学公式.
预览图片大小调整
(setq my/latex-preview-scale 2) ;; 一般来说这里的 scale 约等于 set-face-attribute 中的 :height /100
(setq org-format-latex-options
`(:foreground default :background default :scale ,my/latex-preview-scale :html-foreground "Black" :html-background "Transparent" :html-scale ,my/latex-preview-scale :matchers ("begin" "$1" "$" "$$" "\\(" "\\["))) ;; 增大公式预览的图片大小快速编译 org-preview
org-preview 是一个非正式的包, 极大 提高 了数学公式预览速度 (异步编译, 有望加入未来版本的 Org).
;; 快速编译数学公式
(use-package org-preview
:load-path "lisp/" ; 需要手动从网盘或 https://github.com/karthink/org-preview/ 下载 org-preview.el 文件, 并置于 ~/.emacs.d/lisp/ 文件夹下
;; straight 用户用下一行取代上一行
;; :straight (:host github :repo "karthink/org-preview")
:hook (org-mode . org-preview-mode))自动预览 org-fragtog
- 光标移出公式, 自动编译
- 光标移入公式, 自动展开
(use-package org-fragtog
:hook (org-mode . org-fragtog-mode))LaTeX 导言区共享
Org-mode 如何用上自定义的 LaTeX 宏命令?
方法一: 使用 #+LATEX_HEADER: 关键字
在 Org 文件开头加入 =
#+LATEX_HEADER: \newcommand{\R}{\mathbb{R}}
就可以在整个文件中使用 \mathbb{R}
方法二: 使用 #+SETUPFILE: 关键字
可以创建一个叫 latex-preamble.org 放在 Org-roam 目录下, 然后给所有的笔记文件开头 (可以放在笔记模板里) 加上
#+SETUPFILE: ./latex-preamble.org
然后把所有要用的导言区命令每一行加上 #+LATEX_HEARDER: 放在 latex-preamble.org 文件中.
方法三: 通过 .sty 文件与 LaTeX 文件共享自定义命令
- 把常用的导言区命令放在
~/texmf/tex/latex/目录下的mysymbol.sty文件中 - 添加设置
;; 在 ~/texmf/tex/latex/ 下的 .sty 文件 (setq org-latex-packages-alist '(("" "mysymbol" t)))
原理:
~/texmf是正常情况下$TEXMF的目录. 可以通过命令行kpsewhich --var-value TEXMF确认$TEXMF/tex/latex/目录下的.sty的文件可以被\usepackage引用.- 上述 Emacs 设置相当于 Org 编译 LaTeX 公式时默认加载
\usepackage{mysymbol}命令; 而在 LaTeX 文件中也可以使用同样的命令.
如何导出 Org 笔记
- C-c C-e h o 导出成 HTML 并打开
- C-c C-e l o 导出成 PDF 并打开.
总结
Org-mode 和 CDLaTeX 的强强联合
- Org 笔记的灵活性
- Org-roam 双链笔记工作流程
- CDLaTeX 的流畅数学公式体验
代码汇总
;; 你自己的 LaTeX 模式设置
(defun my/latex-hook ()
(turn-on-cdlatex)
(turn-on-reftex))
(add-hook 'LaTeX-mode-hook 'my/latex-hook)
(add-hook 'latex-mode-hook 'my/latex-hook)
(add-hook 'org-mode-hook #'org-cdlatex-mode) ;; 在 org-mode 中使用 cdlatex
(setq org-highlight-latex-and-related '(native latex entities)) ;; LaTeX 语法高亮设置
(setq org-pretty-entities t) ;; LaTeX 代码的 prettify
(setq org-pretty-entities-include-sub-superscripts nil) ;; 不隐藏 LaTeX 的上下标更容易编辑
;; org-cdlatex-mode 中使用 cdlatex 的自动匹配括号, 并把 $...$ 换成 \( ... \)
(defun my/insert-inline-OCDL ()
(interactive)
(insert "\\(") ;; 把 "\\(" 和 "\\)" 替换成 "$" 就能实现输入成对 "$" 的功能.
(save-excursion (insert "\\)" )))
(defun my/insert-bra-OCDL ()
(interactive)
(insert "(")
(save-excursion (insert ")" )))
(defun my/insert-sq-bra-OCDL ()
(interactive)
(insert "[")
(save-excursion (insert "]" )))
(defun my/insert-curly-bra-OCDL ()
(interactive)
(insert "{")
(save-excursion (insert "}" )))
(define-key org-cdlatex-mode-map (kbd "$") 'my/insert-inline-OCDL)
(define-key org-cdlatex-mode-map (kbd "(") 'my/insert-bra-OCDL)
(define-key org-cdlatex-mode-map (kbd "[") 'my/insert-square-bra-OCDL)
(define-key org-cdlatex-mode-map (kbd "{") 'my/insert-curly-bra-OCDL)
(setq my/latex-preview-scale 2) ;; 一般来说这里的 scale 约等于 set-face-attribute 中的 :height /100
(setq org-format-latex-options
`(:foreground default :background default :scale ,my/latex-preview-scale :html-foreground "Black" :html-background "Transparent" :html-scale ,my/latex-preview-scale :matchers ("begin" "$1" "$" "$$" "\\(" "\\["))) ;; 增大公式预览的图片大小
;; 快速编译数学公式
(use-package org-preview
:load-path "lisp/" ; 需要手动从网盘或 https://github.com/karthink/org-preview/ 下载 org-preview.el 文件, 并置于 ~/.emacs.d/lisp/ 文件夹下
;; straight 用户用下一行取代上一行
;; :straight (:host github :repo "karthink/org-preview")
:hook (org-mode . org-preview-mode))
(use-package org-fragtog
:hook (org-mode . org-fragtog-mode))
;; 在 ~/texmf/tex/latex/ 下的 .sty 文件
(setq org-latex-packages-alist '(("" "mysymbol" t)))