简体   繁体   English

Pandoc lua 过滤器强制紧凑列表

[英]Pandoc lua filter to force compact lists

I want to write a lua filter that forces Pandoc to use compact lists when converting from markdown to PDF.我想编写一个 lua 过滤器,强制 Pandoc 在从 Markdown 转换为 PDF 时使用紧凑列表。 I noticed that lists with nested tables/text/divs will not use the \\tightlist option, as the Pandoc AST uses Para instead of Plain for each list item.我注意到带有嵌套表/文本/div 的列表不会使用\\tightlist选项,因为 Pandoc AST 对每个列表项使用Para而不是Plain I tried to modify the example here to force all BulletList and OrderedList items to Plain , but I could not get it to work when an item contains nested content.我尝试修改此处的示例以强制所有BulletListOrderedList项目为Plain ,但是当项目包含嵌套内容时我无法使其工作。 pandoc mwe.txt -f markdown -t native --lua-filter the-filter.lua returns a Para for the first list item: pandoc mwe.txt -f markdown -t native --lua-filter the-filter.lua返回Para一个列表项的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"]]]]

I'm at a loss how to approach this:我不知道如何解决这个问题:

  • should I use walk_block and change each list item to Plain ?我应该使用walk_block并将每个列表项更改为Plain吗?
  • how do I manage for cases where #blocks > 1?我如何管理#blocks > 1 的情况? How do I change Para to Plain and then include any nested content (say I have two nested divs)?如何将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过滤器.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
}}

You are really close already.你已经很接近了。 I believe the following should work for the general case:我相信以下应该适用于一般情况:

--- 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
}}

The case of multi-block items is an omission in the linked post.多块项目的情况是链接帖子中的遗漏。 However there probably are different opinions on when a list should be made compact.但是,对于何时应该使列表紧凑,可能存在不同的意见。 The above should compactify all lists.以上应该压缩所有列表。

Using walk_blocks would have unintended side-effects, as it would affect all blocks, including the Para block nested below the Div.使用walk_blocks会产生意想不到的副作用,因为它会影响所有块,包括嵌套在 Div 下的Para块。

The original answer above doesn't work with Pandoc 2.11 and a docx file exported from Google Docs.上面的原始答案不适用于 Pandoc 2.11 和从 Google Docs 导出的 docx 文件。 See this issue for details.有关详细信息,请参阅此问题 Here is my modified version of the original answer.这是我对原始答案的修改版本。

-- 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
}}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM