![动机](https://linux22.com/image/320557/%E5%8A%A8%E6%9C%BA.png)
抱歉,标题太长(问题也更长),但这是一个相当复杂的主题,需要稍微详细说明一下。
目标:我想定义一对乳胶宏,我可以在源代码中编写它们来界定文本区域,使其“出现在下一页,景观化,在此页填满之后”。这些宏不能是一种新的环境(但可以基于一种环境)
动机
我有一份用 markdown 编写的文档,需要pandoc
将其转换为 LaTeX。每个 markdown 表都转换为longtable
。一切都自动进行,并且运行正常。
但是,有些表格对于页面宽度来说太宽了(自动生成的表格longtables
没有p
-type 列,我无法控制这一点)。所以我想把这些表格放在一边。现在问题来了。我会告诉你迄今为止的(失败的)尝试。
第一次尝试。使用pdflscape
我可以编辑 pandoc 使用的 latex 模板,并将包和我自己的命令添加到序言中。所以我添加了\usepackage{pdflscape}
。此外,如果 latex 宏出现在 markdown 源中,pandoc 会将它们不加改变地传递给生成的 latex 文件,因此我尝试在我的 markdown 文档中写入以下内容:
\begin{landscape}
... markdown code for the long table
...
\end{landscape}
生成的 latex 编译没有问题,但结果并不如我所料。不仅宏没有\begin/\end
改变就传递了,而且它们之间的所有内部 markdown 代码也没有改变。即:markdown 表没有被翻译成合适的 latex 表,而是“逐字”传递了。
在阅读 pandoc 文档后,我发现这是预期的行为。当 pandoc 检测到一对\begin{something}
/\end{something}
时,会假定该 latex 环境的内容也是 latex,因此这种方法不起作用。
第二次尝试。伪造landscape
环境
由于问题在于 pandoc 对特殊语法进行了硬编码\begin{}/\end{}
,因此我尝试避免使用该语法。
我在 Latex 模板的前言中定义了以下宏:
\usepackage{pdflscape}
\def\startlandscape{\begin{landscape}}
\def\stoplandscape{\end{landscape}}
并在markdown源中写入以下内容:
\startlandscape
... markdown code for the long table
...
\stoplandscape
这有效!这些宏“按原样”传递给 latex 文档,编译时没有问题。宽表现在以横向排版。
问题是这longtable
不是一个浮动环境,因此当出现那个长表格时,当前页面被中止(填充白色),表格被放入下一页,横向显示。所以我的文本中有很大空白。
为了变得更聪明,我做了以下事情:
第三次尝试。通过以下方式推迟 longtable 的输出:afterpage
afterpage
软件包提供了命令\afterpage{}
,它将收到的文本作为参数保存起来,并仅在当前页面写满后输出。这将在下一页排版表格之前用更多文本填充当前页面。
现在的问题是:如何将完整的landscape
环境传递给\afterpage
?
简单的方法:
\newenvironment{postponelandscape}{%
\afterpage{\begin{landscape}
}{%
\end{landscape}}
}
显然是错误的,因为 的两个参数中的括号不平衡\newenvironment
。
第四次尝试。使用environ
包
此包能够创建“捕获”内容并将其存储在名为 的宏中的环境\BODY
,该宏稍后可以作为参数传递给任何其他命令(\afterpage
在我的情况下)。因此,我在序言中添加了以下几行:
\usepackage{pdflscape}
\usepackage{afterpage}
\usepackage{environ}
\NewEnviron{postponelandscape}{%
\afterpage{\begin{landscape}\BODY\end{landscape}}
}
这定义了新的环境postponelandscape
。我在纯 latex 源代码中测试了这个环境,例如:
Text before the table
\begin{postponelandscape}
\begin{longtable}{...}
...
\end{longtable}
\end{postponelandscape}
More text after the table
效果非常好。整个长表格以横向显示在下一页中,当前页面则显示“表格后面有更多文本”,而不是空白。
因此,只需像我之前所做的那样,将此环境“伪造”为一对\start/\stop
命令即可欺骗 pandoc。我在序言中添加了以下内容:
\def\startlandscape{\begin{postponelandscape}}
\def\stoplandscape{\end{postponelandscape}}
所以我尝试了:
\startlandscape
\begin{longtable}{...}
...
\end{longtable}
\stoplandscape
但此操作失败并出现错误:
! LaTeX Error: \begin{postponelandscape} on input line XX ended by \end{document}.
所以,(最后!)我的问题是:
为什么会发生这种情况?为什么这个
\start/\stop
技巧对landscape
env 有效(第二次尝试),但对postponedlandscape
env 无效(第四次尝试)?有什么办法可以解决我的问题吗?欢迎使用任何其他方法。
让我重申一下目标:我想定义一对乳胶宏,我可以在源代码中写入它们来界定一个文本区域,如“在这一页写满之后,出现在下一页,以景观形式显示”。
答案1
使用
\afterpage{\clearpage\input{mytable}}
mytable 的位置
\begin{landscape}
\begin{longtable}
...
\end{longtable}
\end[landscape}
这很可能会在 Latex 中做正确的事情,并且大概可以做相当于
\input{mytable}
在任何 pandoc 转换为其他格式时。
答案2
仅供将来参考,我报告现在 pandoc 还可以识别以和开头的命令\start
作为\stop
LaTeX 代码块,因此我将其重命名\startlandscape
为\blandscape
和\stoplandscape
为\elandscape
,现在横向页面开始和结束命令之间的 markdown 代码可以编译为 LaTeX。
我在 LaTeX 模板头中声明了它们,如下所示:
\usepackage{pdflscape}
\newcommand{\blscape}{\begin{landscape}}
\newcommand{\elscape}{\end{landscape}}
现在这段 markdown + LaTeX 代码
\blandscape
![Image.](assets/image.svg){#fig:image}
\elandscape
正确编译为
\begin{landscape}
\begin{figure}
\hypertarget{fig:image}{%
\centering
\includegraphics{assets/image.svg}
\caption{Image.}\label{fig:image}
}
\end{figure}