9
votes

So, I have been using org-mode for taking my research notes for some time now. I love how I can seamlessly export to both latex (for my papers) and html (for my blog). However, whenever I define macros with \newcommand with #+LATEX_HEADER, these do not show up in the HTML export at all.

I currently handle this by putting the all these commands as (\newcommand \newcommand etc. etc.) at the top and then manually removing the "(" and ")" from the tex file.

What I wish I could do was to keep a drawer for these commands and customize html and latex export of org mode to handle this drawer appropriately.

For example, I would add the following in the org file:

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

And after export, this shows up in the latex file verbatim in header section and in the html file as

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

4 Answers

6
votes

Here's a standalone way that works with Org, pdflatex and MathJax at the time of this writing. Make sure the drawers (or at least the LATEXMACROS drawer) are exported (this is the default), then insert near the top of the Org file:

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

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

#+TOC: headlines

This works around the following problems:

  • We have to use a math environment (here \( ... \)), otherwise Org escapes the TeX syntax.

  • We cannot use \newcommand, because LaTeX expects them to be in the preamble and MathJaX does not receive it. \newcommand can be used outside of the preamble, but then LaTeX (unlike MathJax) restricts the defined macros to the current math environment. We usually want to use them anywhere in the file.

  • We cannot use a plain \def because it behaves like \newcommand in terms of scoping (global for MathJax, local for LaTeX). We cannot use \xdef either because MathJax does not know it.

  • MathJax does not know \global but that won't prevent it from using \def which is global anyway. However, it will print a red warning for each \global in the web page. To get rid of them, we put the math environment inside an undisplayed HTML section.

  • For MathJax, the macros won't be defined in time for the table of content in its default location. If you use macros in headlines and want a TOC, disable the default with #+OPTIONS: toc:nil and manually add it after the drawer with #+TOC: headlines.

Caveats:

  • It's not possible to preview latex fragments which use custom macros, because the small TeX file Org build won't include our environment.

  • Unlike \newcommand, \def silently replaces anything. Also, its syntax is slightly different.

  • The math environment takes up some vertical space in the output of pdflatex, so we have to put it where that doesn't matter (e.g. before the first headline).

  • This is probably really version dependent:

    • Org mode may get better at exporting LaTeX macros (e.g. sending them to MathJax by being smarter when parsing #+LATEX_HEADER, providing a new export option, not escaping \newcommand and putting those into a correctly handled preamble).

    • MathJax may start accepting \xdef as an alias of \def or ignoring \global (so that the HTML section trick is not needed anymore).

3
votes

I figured out how to do it myself. Note that this is perhaps not the most elegant solution since it does not place the latex part in the beginning of the latex file (i.e. outside \begin{document}), but it works well enough for me.

(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))
)
3
votes

Alternative solution (not stand-alone), using Org's dynamic blocks.

  • It has none of the caveats of my original solution (because it generates what Org actually expects for LaTeX or HTML)
  • It's possible to edit the macros in LaTeX mode (C-c C-')

Callback

Create a file named org-dblock-write:block-macro.el with the following content and add it to Emacs' load path.

(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 file

Somewhere in the file, create:

  • A LaTeX source block named "macros" containing your macros
  • An empty block-macro dynamic block

You can change the name of the source block, and use a :from <custom-name> header argument in the dynamic block. Also, note the :exports none in the source block (usually you don't want to export the LaTeX source).

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

Now use C-c C-c with the point on the dynamic block, and it will update to:

#+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:

Do this whenever the macros are modified.

1
votes

I usually have a file with many custom definitions which I reuse for many documents and I want to use it also in my org documents.

The following is a modification of Blout's answer, so please read his answer for more info.

Define macro

(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")))

Usage

File macros.tex:

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

In org file:

#+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: