Pandoc lua过滤器可强制使用紧凑列表

时间:2019-09-15 03:05:52

标签: lua pandoc

我想编写一个lua过滤器,以强制Pandoc在从Markdown转换为PDF时使用紧凑列表。我注意到带有嵌套表/文本/ div的列表将不使用\tightlist选项,因为Pandoc AST对每个列表项都使用Para而不是Plain。我试图修改示例here以强制将所有BulletListOrderedList项都置为Plain,但是当某项包含嵌套内容时,我无法使其正常工作。 pandoc mwe.txt -f markdown -t native --lua-filter the-filter.lua返回第一个列表项的Para

[BulletList
 [[Plain [Str "list",Space,Str "1"]]
 ,[Plain [Str "list",Space,Str "1"]]
 ,[Plain [Str "list",Space,Str "1"]]]
,Para [Str "Some",Space,Str "paragraph"]
,BulletList
 [[Para [Str "list",Space,Str "2"]
  ,Div ("",["class"],[])
   [Para [Str "Nested",Space,Str "div"]]]
 ,[Plain [Str "list",Space,Str "2"]]
 ,[Plain [Str "list",Space,Str "2"]]]]

我无所适从:

  • 我应该使用walk_block并将每个列表项更改为Plain吗?
  • 如何处理#blocks> 1的情况?如何将Para更改为Plain,然后包含任何嵌套的内容(例如我有两个嵌套的div)?

mwe.txt

- list 1
- list 1
- list 1

Some paragraph

- list 2

  ::: {.class}
  Nested div
  :::

- list 2
- list 2

the-filter.lua

local List = require 'pandoc.List'

function compactifyItem2 (blocks)
  if (#blocks == 1) then
    if (blocks[1].t == 'Para') then
      return {pandoc.Plain(blocks[1].content)}
    else
      return blocks
    end
  elseif (#blocks == 2) then -- I assume I have to change the Para and nest the child content
    if (blocks[1].t == 'Para') then
      blocks.content = pandoc.Plain(blocks[1].content) .. blocks[2].content
      return {blocks.content}
    end
  else
    return blocks
  end
end

function compactifyList (l)
  l.content = List.map(l.content, compactifyItem2)
  return l
end

return {{
    BulletList = compactifyList,
    OrderedList = compactifyList
}}

2 个答案:

答案 0 :(得分:1)

您已经很接近了。我认为以下情况适用于一般情况:

--- Iterate over all blocks in an item, converting 'top-level'
-- Para into Plain blocks.
function compactifyItem (blocks)
  -- step through the list of blocks step-by-step, keeping track of the
  -- element's index in the list in variable `i`, and assign the current
  -- block to `blk`.
  -- 
  for i, blk in ipairs(blocks) do
    if blk.t == 'Para' then
      -- update in item's block list.
      blocks[i] = pandoc.Plain(blk.content)
    end
  end
  return blocks
end

function compactifyList (l)
  -- l.content is an instance of pandoc.List, so the following is equivalent
  -- to pandoc.List.map(l.content, compactifyItem)
  l.content = l.content:map(compactifyItem)
  return l
end

return {{
    BulletList = compactifyList,
    OrderedList = compactifyList
}}

在链接的帖子中省略了多块商品的情况。但是,关于何时应该精简列表,可能有不同的意见。以上应该压缩所有列表。

使用walk_blocks会产生意想不到的副作用,因为它会影响所有块,包括嵌套在Div下方的 Para 块。

答案 1 :(得分:0)

上面的原始答案不适用于Pandoc 2.11和从Google Docs导出的docx文件。有关详情,请参见this issue。这是我对原始答案的修改版本。

-- Source: https://stackoverflow.com/a/57943159/7361270
-- Modified by makeworld

-- Iterate over all blocks in an item, converting 'top-level'
-- Para into Plain blocks.
function compactifyItem (blocks)
  -- step through the list of blocks step-by-step, keeping track of the
  -- element's index in the list in variable `i`, and assign the current
  -- block to `blk`.
  -- 
  for i, blk in ipairs(blocks) do
    if blk.t == 'Para' then
      -- update in item's block list.
      blocks[i] = pandoc.Plain(blk.content)
    elseif blk.t == 'BlockQuote' then
      -- It's a Google Doc thing, where each bullet is in a blockquote
      -- https://github.com/jgm/pandoc/issues/6824
      blocks[i] = pandoc.Plain(blk.content[1].content)
    end
  end
  return blocks
end

function compactifyList (l)
  -- l.content is an instance of pandoc.List, so the following is equivalent
  -- to pandoc.List.map(l.content, compactifyItem)
  l.content = l.content:map(compactifyItem)
  return l
end

return {{
    BulletList = compactifyList,
    OrderedList = compactifyList
}}