介绍

介绍

我想使用 markdown 分隔的 div 呈现一个两列的 pdf 文档。最简单的例子如下:

:::::::::::::: {.columns data-latex=""}
::: {.column width="40%" data-latex="[t]{0.4\textwidth}"}
contents...
:::
::: {.column width="60%" data-latex="[t]{0.6\textwidth}"}
contents...
:::
::::::::::::::

在 html 中渲染没问题,但显然有人认为 latex 中的多列渲染仅适用于 beamer,因此它不适用于纯 latex,也不适用于 pdf。我无法切换到 pandoc 的 html pdf 引擎,因为我的最终文档需要 latex 模板。

minipage latex 环境似乎非常方便实现我想要的功能。经过大量调查,我找到了这个 lua 过滤器:

local pandocList = require 'pandoc.List'

Div = function (div)
  local options = div.attributes['data-latex']
  if options == nil then return nil end

  -- if the output format is not latex, the object is left unchanged
  if FORMAT ~= 'latex' and FORMAT ~= 'beamer' then
    div.attributes['data-latex'] = nil
    return div
  end

  local env = div.classes[1]
  -- if the div has no class, the object is left unchanged
  if not env then return nil end

  local returnedList
  
  -- build the returned list of blocks
  if env == 'column' then
    local beginEnv = pandocList:new{pandoc.RawBlock('tex', '\\begin' .. '{' .. 'minipage' .. '}' .. options)}
    local endEnv = pandocList:new{pandoc.RawBlock('tex', '\\end{' .. 'minipage' .. '}')}
    returnedList = beginEnv .. div.content .. endEnv
  end
  return returnedList
end

不幸的是,生成的乳胶文档(pandoc --lua-filter ./latex-div.lua -o test.latex test.md)如下,由于第一个小页面的结尾和第二个小页面的开头之间有空行,因此无法按预期呈现:

\begin{document}

\begin{minipage}[t]{0.4\textwidth}

contents\ldots{}

\end{minipage}

\begin{minipage}[t]{0.6\textwidth}

contents\ldots{}

\end{minipage}

\end{document}

我快到了。如何在不重新处理 latex 文件的情况下删除这个不需要的空白行?

答案1

经过进一步的调查和尝试,我终于能够回答我自己的问题了(希望它对某些人有用)。

由于嵌套的 div 在父 div 之前进行处理,因此可以重新处理它们以关闭小页面环境并在同一个 pandoc.RawBlock 中打开下一个环境(显然可以摆脱不需要的空白行)。

这是新的 lua 过滤器代码:

local pandocList = require 'pandoc.List'

Div = function (div)
  local options = div.attributes['data-latex']
  if options == nil then return nil end

  -- if the output format is not latex, the object is left unchanged
  if FORMAT ~= 'latex' and FORMAT ~= 'beamer' then
    div.attributes['data-latex'] = nil
    return div
  end

  local env = div.classes[1]
  -- if the div has no class, the object is left unchanged
  if not env then return nil end

  local returnedList
  
  -- build the returned list of blocks
  if env == 'column' then
    local beginEnv = pandocList:new{pandoc.RawBlock('tex', '\\begin' .. '{' .. 'minipage' .. '}' .. options)}
    local endEnv = pandocList:new{pandoc.RawBlock('tex', '\\end{' .. 'minipage' .. '}')}
    returnedList = beginEnv .. div.content .. endEnv

  elseif env == 'columns' then
    -- merge two consecutives RawBlocks (\end... and \begin...)
    -- to get rid of the extra blank line
    local blocks = div.content
    local rbtxt = ''

    for i = #blocks-1, 1, -1 do
      if i > 1 and blocks[i].tag == 'RawBlock' and blocks[i].text:match 'end' 
      and blocks[i+1].tag == 'RawBlock' and blocks[i+1].text:match 'begin' then
        rbtxt = blocks[i].text .. blocks[i+1].text
        blocks:remove(i+1)
        blocks[i].text = rbtxt
      end
    end
    returnedList=blocks
  end
  return returnedList
end

生成的乳胶文档现在是正确的:

\begin{document}

\begin{minipage}[t]{0.4\textwidth}

contents\ldots{}

\end{minipage}\begin{minipage}[t]{0.6\textwidth}

contents\ldots{}

\end{minipage}

\end{document}

答案2

事实证明,有一个更简单的解决方案,即使用 Tex 来\mbox使两个小页面粘在一起,尽管有空白行。

local pandocList = require 'pandoc.List'

Div = function (div)
  local options = div.attributes['data-latex']
  if options == nil then return nil end

  -- if the output format is not latex, the object is left unchanged
  if FORMAT ~= 'latex' and FORMAT ~= 'beamer' then
    div.attributes['data-latex'] = nil
    return div
  end

  local env = div.classes[1]
  -- if the div has no class, the object is left unchanged
  if not env then return nil end

  local returnedList
  
  -- build the returned list of blocks
  if env == 'column' then
    local beginEnv = pandocList:new{pandoc.RawBlock('tex', '\\begin' .. '{' .. 'minipage' .. '}' .. options)}
    local endEnv = pandocList:new{pandoc.RawBlock('tex', '\\end{' .. 'minipage' .. '}')}
    returnedList = beginEnv .. div.content .. endEnv

  elseif env == 'columns' then
    -- it turns-out that a simple Tex \mbox do the job
    begin_env = List:new{pandoc.RawBlock('tex', '\\mbox{')}
    end_env = List:new{pandoc.RawBlock('tex', '}')}
    returned_list = begin_env .. div.content .. end_env
  end
  return returnedList
end

得到的乳胶代码是:

\begin{document}

\mbox{

\begin{minipage}[t]{0.4\textwidth}

contents\ldots{}

\end{minipage}\begin{minipage}[t]{0.6\textwidth}

contents\ldots{}

\end{minipage}

}

\end{document}

从那时起,我发布了一个更全面的过滤器git 存储库以及其他可能有用的过滤器。

答案3

介绍

根据我的评论,经过一番努力,我相信我成功地增加了一些整洁克里斯·阿加对他自己的问题的解决方案。

笔记:这个解决方案没有什么价值。它只是对作者最初努力的一次编辑,我仍然认为这是 ChrisAga 的杰作。

Lua 脚本

local pandocList = require 'pandoc.List'

Div = function (div)
  local width = div.attributes['width']
  local options = ""
  if width ~= nil then 
    w = tonumber(width)
    if w == nil then 
      width = string.gsub(width, '%%', '')
      w = tonumber(width)
    end
    if w ~= nil then
      if w >= 1 then w = w / 100 end
      options = "[t]{" .. w .. "\\textwidth}"
    end
  end

  if options == nil then return nil end

  -- if the output format is not latex, the object is left unchanged
  if FORMAT ~= 'latex' and FORMAT ~= 'beamer' then
    div.attributes['data-latex'] = nil
    return div
  end

  local env = div.classes[1]
  -- if the div has no class, the object is left unchanged
  if not env then return nil end

  local returnedList
  
  -- build the returned list of blocks
  if env == 'column' then
    local beginEnv = pandocList:new{pandoc.RawBlock('tex', '\\begin' .. '{' .. 'minipage' .. '}' .. options)}
    local endEnv = pandocList:new{pandoc.RawBlock('tex', '\\end{' .. 'minipage' .. '}')}
    returnedList = beginEnv .. div.content .. endEnv

  elseif env == 'columns' then
    -- merge two consecutives RawBlocks (\end... and \begin...)
    -- to get rid of the extra blank line
    local blocks = div.content
    local rbtxt = ''

    for i = #blocks-1, 1, -1 do
      if i > 1 and blocks[i].tag == 'RawBlock' and blocks[i].text:match 'end' 
      and blocks[i+1].tag == 'RawBlock' and blocks[i+1].text:match 'begin' then
        rbtxt = blocks[i].text .. blocks[i+1].text
        blocks:remove(i+1)
        blocks[i].text = rbtxt
      end
    end
    returnedList=blocks
  end
  return returnedList
end

Markdown

有了这个脚本,Markdown现在可以简化成如下形式:

:::::::::::::: {.columns}
::: {.column width="40%"}
contents...
:::
::: {.column width="60%"}
contents...
:::
::::::::::::::

方法

我的目标是消除以下重复:

::: {.column width="40%" data-latex="[t]{0.4\textwidth}"}

其中我们说40%0.4。这不仅复杂,而且还容易导致不一致。

options我在这里所做的是从参数构建变量width,而不是从参数中获取变量data-latex

width参数也可以用百分比、[1, 100] 比例或 [0, 1[ 比例来表示。该值1毫无疑问地被视为[1, 100]比例的一部分,因为否则它将相当于100%宽度,这完全排除了对柱状环境的需求。

相关内容