jgm / pandoc

Universal markup converter
https://pandoc.org
Other
34.27k stars 3.36k forks source link

Epub: reliable way to define LaTeX macros #6775

Closed tobiasBora closed 3 years ago

tobiasBora commented 3 years ago

LaTeX macros are used very frequently. Unfortunately, I can't find any better way than doing (in org-mode):

#+TITLE: My First Post
#+LaTeX_HEADER: \def\water{H_2O}
$\def\water{H_2O}$

* My section
$$\water + \water = 2\water$$

The first #+LaTeX_HEADER is added to the .tex header, while the second $\def\water{H_2O}$ is of interest for mathjax, that way both these commands work:

pandoc -t latex test.org -s -o test_pandoc.pdf
pandoc -t html test.org -s -o test_pandoc.html --mathjax

Unfortunately, if I try to create an epub, for example using:

pandoc -t epub2 test.org -s -o test_pandoc.epub --webtex

I get errors two times:

So would it be possible to provide a more unified way of defining that some tex code correspond to macros, and provide this code automatically to webtex?

Thanks!

tarleb commented 3 years ago

Sorry for the late reply, this got lost somehow.

There is no built-in method for this. For non-math, one can use org-mode #+MACRO statements, but those don't work in math contexts.

One possible solution would be to use a Lua filter to replace certain commands in math contexts. E.g.:

function Math (m)
  m.text = m.text:gsub('\\water', '{H_2O}')
  return m
end

With a bit of work, this could be extended to build a full macro system for math.

Please reach out on the pandoc-discuss mailing list for more help to get this working.

tobiasBora commented 3 years ago

Thanks for your answer. Lua filters could be an idea, but they have three issues:

  1. as it they don't handle arguments, and handling such arguments would likely require to write a LaTeX parser... Not sure it is really desirable.
  2. I usually have different macros between different files... and it would not be highly practical to write one lua script per file (and duplicate the definitions between the source and the lua file).
  3. I guess it also requires adaptation to handle macro included as arguments to other macros

But this solution also has some advantages, notably I guess it's more portable than just pasting the macros at the beginning of the html/tex files.

But it's better than nothing, thanks for the trick!

tarleb commented 3 years ago

Well, pandoc already includes a LaTeX parser, and we can use it from within Lua filters. So we could just use that!

Below is a (hacky!) filter which add the definitions from the header to each math element, parses the resulting string as LaTeX, and returns the resulting math.

local latex_headers

function get_latex(metaval)
  return table.concat(
    pandoc.List.map(
      metaval,
      function (v) return v.t == 'RawInline' and v.text or '' end
    ),
    '\n'
  )
end
function Meta (meta)
  latex_headers = meta['header-includes']:map(get_latex)
end
function Math (m)
  local delim = m.mathtype == 'DisplayMath' and '$$' or '$'
  local latex = table.concat(latex_headers, '\n')
    .. '\n' .. delim .. m.text .. delim .. '\n'
  local blocks = pandoc.read(latex, 'latex').blocks
  return pandoc.utils.blocks_to_inlines(blocks)
end

return {{Meta = Meta}, {Math = Math}}

This should give you the desired result. Probably requires some refinement, but should get you started.