【问题标题】:Pandoc lua filter: How to preserve footnotes' formatting?Pandoc lua 过滤器:如何保留脚注的格式?
【发布时间】:2019-01-04 00:57:06
【问题描述】:

我尝试实现CSS Generated Content for Paged Media Module 中定义的脚注。
使用此定义,脚注必须内联spans。 我写了pandoclua 过滤器的初稿。
这是我的第一个 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()函数,但无法得到任何结果。

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

所以,当我对以下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>

代码块丢失。有什么办法可以同时保留脚注的格式和代码块?

【问题讨论】:

  • 这永远不会如你所愿。请参阅p tag 的 HTML 规范。一旦找到任何块级元素的开始标签,p 元素就会关闭。因此,您不能将块级元素放在段落中。 span 也是如此,它是一个 phrasing content 元素,只能包含其他短语内容元素。我猜 Pandoc 的 HTML 渲染器知道这一点,并拒绝在不允许的地方输出块级标签。
  • 您引用的规范仅在脚注示例中显示内联级别的内容。而footnote display property 提供了一种方法来指示内容是应该显示为“内联”还是“块”内容。这是必要的,因为脚注本身实际上不能是包含它的 span 标记内的块内容。换句话说,规范只提供了一个脚注,其中包含不超过一个段落的内容,但只有 content ,而不是 p 本身。
  • 有类似Bigfoot.js(网站当前关闭,请参阅GitHub project)的东西,它们显示脚注以便它们显示为内联,但实际上它们使用Markdown的常见脚注标记(所有脚注在末尾document) 并使用一些 JavaScript 和 CSS 使它们显示为内联。这与 CSS Generated Content for Paged Media Module 规范非常不同,它们实际上是内联的。
  • @Waylan 感谢您的 cmets!按照您的回复顺序:1/让我感到惊讶的是pandoc对Note元素的定义hackage.haskell.org/package/pandoc-types-1.17.5.1/docs/…它是一个由块元素列表组成的内联元素(这对我的大脑来说很奇怪)。但是,我同意你的观点:我只能处理措辞内容。但是,我认为应该可以将一些简单的格式保留为粗体或 emph。
  • @Waylan 2/ 我同意。这就是为什么我尝试使用 &lt;br/&gt;(在 pandoc 中命名为 LineBreak)。 3/ 我更喜欢避免使用 JS 进行任何 DOM 操作(或仅使用非常简单的脚本)。原因是我使用Prince制作pdf(html内容不打算在浏览器中使用)。

标签: html filter lua markdown pandoc


【解决方案1】:

我找到了如何处理Note 元素。

首先,Note 元素是一个内联元素,所以我们可以使用walk_inline。奇怪的是Note 元素可以嵌入像ParaCodeBlock 这样的块元素。

以下过滤器仅处理 ParaCodeBlock 元素。保留格式。

由于Para 元素是内联元素的列表,很明显可以在Span 元素中重用这些元素。
CodeBlock 文本也可以在内联 Code 元素中处理。

local List = require 'pandoc.List'

Note = function (elem)
  local inlineElems = List:new{} -- where we store all Inline elements of the footnote
  -- Note is an inline element, so we have to use walk_inline
  pandoc.walk_inline(elem, {
    -- Para is a list of Inline elements, so we can concatenate to inlineElems
    Para = function(el)
      inlineElems:extend(el.content)
      inlineElems:extend(List:new{pandoc.LineBreak()})
    end,
    -- CodeBlock is a block element. We have to store its text content in an inline Code element
    CodeBlock = function(el)
      inlineElems:extend(List:new{pandoc.Code(el.text, el.attr), pandoc.LineBreak()})
    end
  })
  table.remove(inlineElems) -- remove the extra LineBreak
  return pandoc.Span(inlineElems, pandoc.Attr("", {"footnote"}, {}))
end

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

【讨论】:

  • Pandoc 有一个将块转换为内联的函数,但它没有作为 Lua 函数公开。据我了解,这样的功能将使您的生活变得更加轻松。我可以建议在pandoc issue tracker 上提出这个问题吗?
  • @tarleb 感谢您的信息!我是 pandoc internals 的初学者。是的,我认为这样的功能会是一个很好的帮手。
  • 感谢您的支持!我对 Haskell 有点害怕。我只为一流的开发人员看到这种语言(我只是一个业余开发人员)。 lua 似乎更容易访问。我将首先打开一个问题,看看这些内部结构。
  • 我可以理解。我尝试(但都失败了)三次使用 Haskell,然后我终于从中获得了一些成果。不是很难,只是很不一样。不过现在很有趣;)
  • 谢谢@tarleb!我喜欢 pandoc,现在喜欢 lua 过滤器。感谢您的出色工作!
猜你喜欢
  • 1970-01-01
  • 2019-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多