个性化定制org-mode导出

9

我已经使用org-mode一段时间来记录我的研究笔记。我喜欢它无缝地导出到latex(用于我的论文)和html(用于我的博客)。然而,当我使用 #+LATEX_HEADER 定义新命令时,在HTML导出中根本不会显示这些命令。

目前,我通过将所有这些命令放在顶部并手动从tex文件中删除“(”和“)”来处理此问题。

我希望能够为这些命令保留一个抽屉,并自定义org mode的html和latex导出以适当地处理此抽屉。

例如,我会在org文件中添加以下内容:

:LATEX_MACROS:
\newcommand{\norm}[1]{\lVert{#1}\rVert}
\newcommand{\abs}[1]{\lvert{#1}\rvert}
\newcommand{\half}{\frac{1}{2}}
:END:

导出后,这将在LaTeX文件的页眉部分以逐字方式显示,在HTML文件中则显示为

\(
\newcommand{\norm}[1]{\lVert{#1}\rVert}
\newcommand{\abs}[1]{\lvert{#1}\rvert}
\newcommand{\half}{\frac{1}{2}}
\)
4个回答

6

以下是一种独立的方式,适用于Org、pdflatex和MathJax,确保抽屉(或至少LATEXMACROS抽屉)被导出(这是默认设置),然后在Org文件顶部插入:

#+OPTIONS: toc:nil
#+DRAWERS: LATEXMACROS ...

:LATEXMACROS:
@@html:<div style="display: none">@@
\(
\global\def\mymacro{...}
\global\def\mymacrow2args#1#2{...}
...
\)
@@html:</div>@@
:END:

#+TOC: headlines

这样做是为了解决以下问题:

  • 我们必须使用数学环境(此处为\( ... \)),否则Org会转义TeX语法。

  • 我们不能使用\newcommand,因为LaTeX期望它们在导言部分中,并且MathJaX无法接收它。可以在导言部分之外使用\newcommand,但是然后LaTeX(与MathJax不同)将定义的宏限制为当前数学环境。通常我们想要在文件的任何地方使用它们。

  • 我们不能使用普通的\def,因为它在作用域上的行为类似于\newcommand(对于MathJax是全局的,对于LaTeX是局部的)。我们也不能使用\xdef,因为MathJax不认识它。

  • MathJax不知道\global,但这不会阻止它使用\def,这本质上是全局的。然而,在网页中,它会为每个\global打印一个红色的警告。为了摆脱这些警告,我们将数学环境放在一个未显示的HTML区块中。

  • 对于MathJax,宏不会在默认位置的内容表中及时定义。如果您在标题中使用宏并希望有一个TOC,请使用#+OPTIONS: toc:nil禁用默认值,并在抽屉之后手动添加它:#+TOC:headlines

注意事项:

  • 无法预览使用自定义宏的latex片段,因为Org构建的小型TeX文件不包括我们的环境。

  • \newcommand不同,\def会静默地替换任何东西。而且,它的语法略有不同。

  • 数学环境在pdflatex输出中占据一些垂直空间,因此我们必须将其放在不重要的位置(例如在第一个标题之前)。

  • 这可能真的与版本有关:

    • Org模式可能会在导出LaTeX宏方面变得更好(例如通过在解析#+LATEX_HEADER时更加智能、提供新的导出选项、不转义\newcommand并将其放入正确处理的导言部分来将它们发送到MathJax)。

    • MathJax可能会开始接受\xdef作为\def的别名或忽略\global(因此不再需要HTML部分技巧)。


1
这些限制的有趣后果之一是,您可以将宏定义限制为一个后端或另一个后端:对于LaTeX,请使用#+LATEX_HEADER:\newcommand \m(或\def),对于MathJax,请使用\(\ newcommand \m \)(或\ def)。 我使用它来使用LaTeX中的\ textsc格式化\ tag的小写字母,或者使用https://dev59.com/32bWa4cB1Zd3GeqPVla_#11578420中的宏在MathJax中。 - Blout

3

使用Org的动态块作为替代方案(不是独立的解决方案)。

  • 与原始解决方案相比,它没有任何缺点(因为它生成Org实际期望的LaTeX或HTML)
  • 可以在LaTeX模式下编辑宏(C-c C-'

回调函数

创建一个名为org-dblock-write:block-macro.el的文件,并添加以下内容到Emacs的加载路径中。

(defun org-dblock-write:block-macro (params)
  (let ((block-name (or (plist-get params :from) "macros"))
    (org-buf (current-buffer)))
    (with-temp-buffer
      (let ((tmp-buf (current-buffer)))
    (set-buffer org-buf)
    (save-excursion
      (org-babel-goto-named-src-block block-name)
      (org-babel-mark-block)
      (let ((mblock-begin (region-beginning))
            (mblock-end (region-end)))
        (set-buffer tmp-buf)
        (insert-buffer-substring org-buf mblock-begin mblock-end)))
    (set-buffer org-buf)
    (insert "#+BEGIN_HTML\n\\(\n")
    (insert-buffer-substring tmp-buf)
    (insert "\\)\n#+END_HTML\n")
    (set-buffer tmp-buf)
    (beginning-of-buffer)
    (while (re-search-forward "^" nil t)
      (replace-match "#+LATEX_HEADER: " nil nil))
    (set-buffer org-buf)
    (insert-buffer-substring tmp-buf)))))

Org文件

在文件的某个位置,创建:

  • 一个名为“macros”的LaTeX源代码块,其中包含您的宏
  • 一个空的block-macro动态块

您可以更改源代码块的名称,并在动态块中使用:from <custom-name>头参数。此外,请注意源代码块中的:exports none(通常不希望导出LaTeX源代码)。

#+NAME: macros
#+BEGIN_SRC latex :exports none
  \newcommand\a{a}
  \def\b{b}
  \DeclareMathOperator\c{c}
#+END_SRC
#+BEGIN: block-macro
#+END:

现在在动态块上使用 C-c C-c,它会更新为:

#+BEGIN: block-macro
#+BEGIN_HTML
\(
      \newcommand\a{a}
      \def\b{b}
      \DeclareMathOperator\c{c}
\)
#+END_HTML
#+LATEX_HEADER:       \newcommand\a{a}
#+LATEX_HEADER:       \def\b{b}
#+LATEX_HEADER:       \DeclareMathOperator\c{c}
#+LATEX_HEADER: 
#+END:

每当宏被修改时,请执行此操作。

3

我自己找到了解决方法。请注意,这可能不是最优雅的解决方案,因为它没有把Latex部分放在Latex文件的开头(即\begin{document}之外),但对我来说足够好用。

(setq org-export-blocks
  (cons '(latexmacro org-export-blocks-latexmacro) org-export-blocks))

(defun org-export-blocks-latexmacro (body &rest headers)
  (message "exporting latex macros")
  (cond
   ((eq org-export-current-backend 'html) (concat "\\(" body "\\)"))
   ((eq org-export-current-backend 'latex) body)
   (t nil))
)

1
我通常有一个包含许多自定义定义的文件,我会在很多文档中重复使用它,并且我想在我的org文档中也使用它。
以下是Blout答案的修改版本,请阅读他的答案以获取更多信息。
定义宏
(defun org-dblock-write:insert-latex-macros (params)
  (let ((text)
    (file (plist-get params :file)))
    (with-temp-buffer
      (insert-file file)
      (setq text (split-string (buffer-string) "\n" t)))
    (insert (mapconcat (lambda (str) (concat "#+LATEX_HEADER: " str)) text "\n"))
    (insert "\n#+BEGIN_HTML\n\\(\n")
    (insert (mapconcat 'identity text "\n"))
    (insert "\n\\)\n#+END_HTML")))

使用方法

文件 macros.tex:

\newcommand\a{a}
\def\b{b}
\DeclareMathOperator\c{c}

在org文件中:
#+BEGIN: insert-latex-macros :file "macros.tex"
#+BEGIN_HTML
\(
      \newcommand\a{a}
      \def\b{b}
      \DeclareMathOperator\c{c}
\)
#+END_HTML
#+LATEX_HEADER:       \newcommand\a{a}
#+LATEX_HEADER:       \def\b{b}
#+LATEX_HEADER:       \DeclareMathOperator\c{c}
#+LATEX_HEADER: 
#+END:

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接