如何扩展 Pandoc

How to extend Pandoc

我将 bookdown 用于文档,该文档使用 bookdown::gitbookbookdown::pdf_book 输出。

在我的 Rmd 文件中,我使用 div 环绕注释和警告,并使用 css 文件设置样式。例如:

<div class="note">
This is a note.
</div>

显然,HTML 和 CSS 在生成 PDF 文件时会被忽略。我想知道是否有一种方法可以“注入”一个小脚本来替换 div,例如,一个简单的前缀文本。

或者,是否有另一种方法可以在 HTML 和 PDF 中格式化它,而不会通过每次添加冗长的内容来乱丢我的文件,例如:

if (knitr::is_html_output(excludes='epub')) {
  cat('
<div class="note">
This is a note.
</div>
  ')
} else {
  cat('Note: This is a note.')
}

我也可以按照描述设置块引号的样式 here 但这不是一个选项,因为我仍然需要块引号。

我在 tex.stackexchange.com 上找到了这个 answer,这让我走上了解决问题的正确轨道。


这是我正在做的。

  1. 使用以下函数创建 boxes.lua
function Div(element)
-- function based on https://tex.stackexchange.com/a/526036

    if 
        element.classes[1] == "note" 
        or element.classes[1] == "side-note" 
        or element.classes[1] == "warning" 
        or element.classes[1] == "info" 
        or element.classes[1] == "reading" 
        or element.classes[1] == "exercise" 
    then

        -- get latex environment name from class name
        div = element.classes[1]:gsub("-", " ")
        div = div:gsub("(%l)(%w*)", function(a, b) return string.upper(a)..b end)
        div = "Div"..div:gsub(" ", "")
        
        -- insert element in front
        table.insert(
            element.content, 1,
            pandoc.RawBlock("latex", "\begin{"..div.."}"))

        -- insert element at the back
        table.insert(
            element.content,
            pandoc.RawBlock("latex", "\end{"..div.."}"))

    end
    return element
end
  1. pandoc_args添加到_output.yml:
bookdown::pdf_book:
  includes:
    in_header: latex/preamble.tex
  pandoc_args: 
    - --lua-filter=latex/boxes.lua 
  extra_dependencies: ["float"]
  1. preamble.tex中创建环境(也在_output.yml中配置):
    • 我正在使用 tcolorbox 而不是 mdframed
\usepackage{xcolor}
\usepackage{tcolorbox}

\definecolor{notecolor}{RGB}{253, 196, 0}
\definecolor{warncolor}{RGB}{253, 70, 0}
\definecolor{infocolor}{RGB}{0, 183, 253}
\definecolor{readcolor}{RGB}{106, 50, 253}
\definecolor{taskcolor}{RGB}{128, 252, 219}

\newtcolorbox{DivNote}{colback=notecolor!5!white,colframe=notecolor!75!black}
\newtcolorbox{DivSideNote}{colback=notecolor!5!white,colframe=notecolor!75!black}
\newtcolorbox{DivWarning}{colback=warncolor!5!white,colframe=warncolor!75!black}
\newtcolorbox{DivInfo}{colback=infocolor!5!white,colframe=infocolor!75!black}
\newtcolorbox{DivReading}{colback=readcolor!5!white,colframe=readcolor!75!black}
\newtcolorbox{DivExercise}{colback=taskcolor!5!white,colframe=taskcolor!75!black}
  1. 因为方框内还有图片和表格,所以我 运行 变成了 LaTeX Error: Not in outer par mode.。我能够通过将以下命令添加到我的 Rmd 文件来解决此问题:
```{r, echo = F}
knitr::opts_chunk$set(fig.pos = "H", out.extra = "")
```

执行此操作的适当方法是使用围栏 div,而不是将 HTML 直接插入您的 markdown 并稍后尝试使用 LUA 对其进行解析。 Pandoc 已经允许您插入自定义样式并将它们处理为两种文件类型。换句话说,它将负责为您创建适当的 HTML 和 LaTeX,然后您只需要为它们中的每一个设置样式。 Bookdown 文档引用了这个 here, but it simply points to further documentation here, and here.

此方法将在 html 中创建自定义分类 div 并在 LaTeX 代码中应用相同的样式名称。

因此,对于您的示例,它看起来像这样:

::: {.note data-latex=""}
This is a note.
:::

HTML 中的输出将与您的相同:

<div class="note">
<p>This is a note.</p>
</div>

并且您已经得到 CSS 想要的样式。

LaTeX 代码如下:

\begin{note}
This is a note.
\end{note}

要设置样式,您需要在 preamble.tex 文件中添加一些代码,您也已经弄清楚了。这是一个非常简单的 LaTeX 示例,它可以简单地从左侧和右侧缩进文本:

\newenvironment{note}[0]{\par\leftskip=2em\rightskip=2em}{\par\medskip}