注意: 我已经把这个做成了一个包,放在 github 上: GitHub - et2010/org-edit-latex: Edit LaTeX fragments like editing src blocks 便于维护。这里的不再更新。另外,最新版本已经支持行内 latex 的编辑。
已经提交到 MELPA,可以用 package-list-packages 查看并下载,欢迎使用!
在 Org mode 中使用 LaTeX 的正确姿势不是 LaTeX src block,或 export block,而是 LaTeX fragment。因为 latex fragment
- 可以预览
- 可以预览
- 可以预览
预览 LaTex 是 Org 的一个很 cool 的 feature,preview 可以实现整个 Org 文档中不出现 LaTeX 代码,增强可读性。对于用 Org-mode 做科学笔记,写科技论文的人来说非常重要。
但是 latex fragment 在编辑时有一个劣势,就是无法打开一个专门的 buffer 用 auctex 编辑,也就没有代码高亮和自动缩进这些功能。下面的代码解决了这一问题。
使用很简单,把光标移动到 fragment 内部(这里限定了只能编辑 display math,不支持 inline math,因为我个人认为行内公式有 cdlatex 和 yasnippet 一般就足够了)。然后用 org-edit-special 命令开始编辑就行了(我用的 spacemacs,默认是绑定到 , ',编辑完了也是和 src block 一样退出。
这里感谢论坛里各位同学的帮忙,特别是 @xuchunyang @twlz0ne 帮忙解答 advice 方面的问题,还要感谢 @CuriousBull 和我聊天启发我想出了这个方法。欢迎大家试用并提出宝贵的意见。首发 Emacs-China。
最好配合下列配置使用:
(setq org-src-preserve-indentation t)
另外,需要把 latex 添加到 org-babel-load-langauges
中去(确保你可以 C-c C-c 运行 latex 代码块)。
Update
Ver 1.2
- 修复了当 latex fragment 位于 buffer 末尾处时,wrapper 不能正常工作的问题。 Ver 1.1
- 优化了 LaTeX 环境的判断 Ver 1.0
- 重写了跳过空行那部份的代码。现在不会再出现搜索不到导致的死循环了
- 增加了对 $$ $$ 形式 display math 的支持
Known Issue
- latex fragment 不能位于文件的末尾(也就是文件末尾至少要有一个空行),不然会进入死循环,可以用 C-g 退出。欢迎提出解决方案。
如果出现了不 work 的情况,一般是正则表达式不匹配造成的死循环,请将你的不工作的例子贴在下面,方便我进行 debug,谢谢!
(defun org-wrap-latex-fragment ()
"Wrap latex fragment in a latex src block"
(interactive)
(let* ((ele (org-element-context))
(beg (org-element-property :begin ele))
(end (org-element-property :end ele))
(nb (org-element-property :post-blank ele))
(env-p (save-excursion
(goto-char beg)
(looking-at-p "^[ \t]*\\\\begin"))))
(when (memq (org-element-type ele)
'(latex-fragment latex-environment))
(save-excursion
(cond
(env-p
(goto-char end)
(when (not (and (eobp)
(equal 0 nb)
(save-excursion
(beginning-of-line)
(looking-at-p "[ \t]*\\\\end{"))))
(forward-line (- (1+ nb)))
(end-of-line))
(insert "\n#+END_SRC")
(goto-char beg)
(insert "#+BEGIN_SRC latex\n"))
(t
(goto-char end)
(insert "\n#+END_SRC")
(goto-char beg)
(beginning-of-line)
(insert "#+BEGIN_SRC latex\n")))))))
(defun org-unwrap-latex-fragment (&rest args)
"Unwrap latex fragment"
(interactive)
(let* ((ele (org-element-context))
(lang (org-element-property :language ele))
(beg (org-element-property :begin ele))
(end (org-element-property :end ele))
(nb (org-element-property :post-blank ele)))
(when (and (eq 'src-block
(org-element-type ele))
(string= "latex" lang))
(save-excursion
(goto-char end)
(if (and (eobp)
(equal 0 nb)
(save-excursion
(beginning-of-line)
(looking-at-p "#\\+end_src")))
(delete-region (point-at-bol) (point-at-eol))
(forward-line (- (1+ nb)))
(delete-region (point-at-bol) (1+ (point-at-eol))))
(goto-char beg)
(delete-region (point-at-bol) (1+ (point-at-eol)))))))
(defun org-wrap-latex-fragment-maybe (&rest args)
"Wrap a latex fragment with \"begin_src latex\" and \"end_src\" so that we could edit it like a latex src block. This only works on display math."
(when (save-excursion
(goto-char (org-element-property :begin (org-element-context)))
;; display math :
(looking-at-p "[ \t]*\\$\\$\\|[ \t]*\\\\\\[\\|[ \t]*\\\\begin"))
(org-wrap-latex-fragment)))
(advice-add #'org-edit-special :before #'org-wrap-latex-fragment-maybe)
(advice-add #'org-edit-src-exit :after #'org-unwrap-latex-fragment '((depth . 100)))