Pandoc lua 过滤器:如何保留脚注的格式?

我尝试按照CSS Generated Content for Paged Media Module的定义实现脚注。

按照这个定义,脚注必须是内联的 span。 我写了一个 pandoc lua 过滤器的初稿。

这是我的第一个 pandoc 过滤器(也是我第一次编写 lua 代码)。

以下是过滤器:

Note = function (elem)
  local textContent = {}
  local content = elem.content
  for i = 1, #content do
    textContent[2*i-1] = pandoc.Str(pandoc.utils.stringify(content[i]))
    if i < #content
    then
      textContent[2*i] = pandoc.LineBreak()
    end
  end
  return pandoc.Span(textContent, pandoc.Attr("", {"footnote"}, {}))
end

对于未格式化的文本脚注(由于使用 stringify() 函数而失去了格式),它能够很好地工作:简单的脚注和多个块的脚注都能被很好地渲染。

为了保留格式,我尝试在 Note 元素的 content 上使用 walk_block() 函数,但是我无法得到任何结果。

我遇到了第二个问题:对于 CodeBlock 元素 stringify() 函数返回一个空的字符字符串。

因此,当我在以下的 markdown 文本上使用这个过滤器时:

Here is a footnote reference,[^1] and another.[^longnote]

[^1]: Here is the footnote.

[^longnote]: Here's one with multiple blocks.

    Subsequent paragraphs are indented to show that they
belong to the previous footnote.

        { some.code }

    The whole paragraph can be indented, or just the first
    line.  In this way, multi-paragraph footnotes work like
    multi-paragraph list items.

This paragraph won't be part of the note, because it
isn't indented.

我得到了以下的 HTML 片段:

<p>
  Here is a footnote reference,
  <span class="footnote">Here is the footnote.</span>
  and another.
  <span class="footnote">Here’s one with multiple blocks.
    <br />
    Subsequent paragraphs are indented to show that they belong to the previous footnote.
    <br />
    <br />
    The whole paragraph can be indented, or just the first line. In this way, multi-paragraph footnotes work like multi-paragraph list items.
  </span>
</p>
<p>This paragraph won’t be part of the note, because it isn’t indented.</p>

代码块被忽略了。有没有什么方法可以同时保留脚注的格式和代码块?

点赞
用户6500804
用户6500804

我发现了如何处理 “Note” 元素。

首先,“Note” 元素是一个内联元素,所以我们可以使用 walk_inline 函数。奇怪的是,“Note” 元素可以嵌入像 “Para” 或 “CodeBlock” 这样的块元素。

以下过滤器仅处理 “Para” 和 “CodeBlock” 元素。格式保持不变。

由于 “Para” 元素是一个内联元素的列表,在 “Span” 元素中重复使用这些元素是显而易见的。

CodeBlock 文本也可以在内联 Code 元素中处理。

local List = require 'pandoc.List'

Note = function (elem)
  local inlineElems = List:new{} -- 用于存储注释中所有内联元素的位置
  -- Note 是一个内联元素,所以我们必须使用 walk_inline
  pandoc.walk_inline(elem, {
    -- Para 是内联元素的列表,所以我们可以将其与 inlineElems 连接起来
    Para = function(el)
      inlineElems:extend(el.content)
      inlineElems:extend(List:new{pandoc.LineBreak()})
    end,
    -- CodeBlock 是一个块元素。我们必须将其文本内容存储在内联 Code 元素中
    CodeBlock = function(el)
      inlineElems:extend(List:new{pandoc.Code(el.text, el.attr), pandoc.LineBreak()})
    end
  })
  table.remove(inlineElems) -- 移除额外的 LineBreak
  return pandoc.Span(inlineElems, pandoc.Attr("", {"footnote"}, {}))
end

如果 “Note” 元素嵌入其他类型的块元素(如 “BulletList” 或 “Table”),则必须为 walk_inline 函数开发特定的过滤器。

2018-07-27 10:03:54