测试对环境的连续调用

测试对环境的连续调用

我使用 beamer 为我的统计课制作幻灯片,现在有一个非常好的设置,可以生成类似于 powerpoint 的输出(参见问题:使用 Beamer 每页放置 3 张幻灯片,并在旁边添加注释(类似 powerpoint))。

要使该系统正常工作,我需要为每张幻灯片定义与幻灯片相关的注释,否则注释将与幻灯片不同步。可能有更好的方法来为幻灯片定义“默认”注释定义,以便它们永远不会不同步,但这远远超出了我在 latex 中的能力,而且环境非常复杂,因此发布 MWE 对我来说很难。

相反,我希望至少能捕捉到幻灯片中未定义注释的错误。我能想到的最简单的方法是简化为如下所示的 MWE:

\documentclass[10pt]{article}

\newcounter{mypagecount}
\setcounter{mypagecount}{1}

\newcommand\incpagecount{
  \stepcounter{mypagecount}
}
\newcommand\getpagecount{
  \themypagecount
}

\newenvironment{mypage}[1]{%
Parameter: #1 Expected: \getpagecount Body :}{ \incpagecount \\ }

\begin{document}

\begin{mypage}{1} foo \end{mypage}
\begin{mypage}{2} foo \end{mypage}
\begin{mypage}{4} foo \end{mypage}
\begin{mypage}{5} foo \end{mypage}

\end{document}

问题:当检测到没有调用 mypage {3} 时,如何让 latex 抛出错误?对于 c 程序员来说,展示如何使用 c 风格的断言参数不等于预期值会很棒!

谢谢大家。

答案1

没有断言。甚至没有!=。还有\if,,,,,,等等。请参阅 TeXbook (Knuth) 和 source2e.pdf (CTAN \ifdim) \ifx\ifcase\@ifundefined\@ifl@aded

注意,局部定义在环境之外不可用。幸运的是,计数器操作使用全局版本。 \global\let\xdef可以使用,但\setlength\renewcommand不能。

\documentclass[10pt]{article}

\newcounter{mypagecount}
\setcounter{mypagecount}{1}

\newcommand\incpagecount{%
  \stepcounter{mypagecount}%
}
\newcommand\getpagecount{% redundant
  \themypagecount
}

\newenvironment{mypage}[1]{%
\ifnum\value{mypagecount}=#1\relax
\else
  \errmessage{Parameter: #1 Expected: \getpagecount}%
  \setcounter{mypagecount}{#1}%
\fi
\noindent Body :}%
{ \incpagecount \\ }

\begin{document}

\begin{mypage}{1} foo \end{mypage}
\begin{mypage}{2} foo \end{mypage}
\begin{mypage}{4} foo \end{mypage}
\begin{mypage}{5} foo \end{mypage}

\end{document}

答案2

我建议采用不同的解决方案。目前这只是一个概念验证。具体来说,如果您将任何选项传递labelframe环境以外的选项,它都会失败。我认为这可以修复,但这会使事情变得复杂。

这个想法是以不同的方式将幻灯片纳入讲义。这利用了 Beamer 的beamerarticle软件包、环境label选项frame\includeslide宏。它还使用了(因为我对s 之类的xcoffins东西感到太沮丧了)和。minipageenviron

工作流程:

  • 3 个文件,其中 2 个是输入第三个的极其简单的包装器。

  • 第三个文件不包含\documentclass,但包含幻灯片和笔记。假设这是<main file name>.tex

  • frame幻灯片照常进入环境。这些幻灯片使用label选项进行标记。

  • 注释放在annot环境中。这些注释需要一个参数来给出相应幻灯片的标签。(如果您通常引用幻灯片,这就是您要给出的参数\ref{}。)可以使用可选参数来覆盖包含幻灯片时使用的设置。

  • 第一个包装器被编译以生成幻灯片。我将其命名为<main file name>-beamer.tex。该文件的内容应该是

    \pdfminorversion=7% comment this out if not using pdftex
    \documentclass[ignorenonframetext]{beamer}
    \input{<main file name>}% substitute appropriately here
    

    这应该被编译第一的

  • 第二个包装器被编译以生成讲义。我之所以调用它,<main file name>-article.tex是因为我使用了article类和 Beamer 的article模式。该文件的内容应该是

    \pdfminorversion=7% comment this out if not using pdftex
    \documentclass{article}% adjust if you prefer a different class
    \usepackage{beamerarticle,graphicx}
    \setjobnamebeamerversion{<main file name>-beamer}% substitute appropriately here
    \input{<main file name>}% substitute appropriately here
    

    这应该被编译第二

然后在 中<main file name>.tex放入其余的序言和正文document。我将大部分自定义内容放在这里的序言中,将其限制在 Beamerarticle模式中,但如果您愿意,可以将其移动到讲义包装器中。

% \jobname.tex = <main file name>.tex
\mode<article>
{

这将仅在模式下执行article

  \usepackage{xcoffins,environ,geometry,calc,pgf}

xcoffins、、environpgfcalc必需的。geometry刚刚摆脱了坏盒子。

首先,我们稍后需要一些新的长度。

  \newlength\annotsep
  \setlength\annotsep{.5em}% set the horizontal separation of frames and annotations
  \newlength\frmwd
  \AtBeginDocument{%
    \setlength\frmwd{.5\linewidth-.5\annotsep-2\fboxsep-2\fboxrule}%
  }

还有几口棺材。

  \NewCoffin\AnnotCoffin
  \NewCoffin\FrameCoffin

现在我们定义annot环境,但是我们使用\NewEnviron而不是\newenvironment因为我们想将整个内容放入棺材中,这看起来最简单。(我试图expl3在这里避免使用语法。)

  \NewEnviron{annot}[2][]{%
    \edef\tempa{\extractedref}\edef\tempb{#2}%
    \ifx\tempa\tempb\relax
    \else\outputempty\fi\xdef\extractedref{}%

这会检查除了此注释的帧之外,是否有任何我们未放入幻灯片的帧。如果有与frame此组注释不对应的标签,我们假设该帧没有注释,并在其右侧输出空白。

现在我们设置了我们的第一个棺材,\FrameCoffin并用相关幻灯片的框架副本(即我们使用annot环境的强制参数引用的幻灯片)来设置。

    \SetVerticalCoffin\FrameCoffin{.5\linewidth-.5\annotsep}{%
      \fbox{\includeslide[width=\frmwd,#1]{#2}}% depending on theme, remove frame if not required
    }%

现在我们设置第二个棺材,\AnnotCoffin用于存放笔记。

    \SetVerticalCoffin\AnnotCoffin{.5\linewidth-.5\annotsep}{%
      \BODY
    }%

我们将棺材从顶部连接起来,将节点稍微向外向下推。

    \JoinCoffins\FrameCoffin[t,r]\AnnotCoffin[t,l](\annotsep,-.5\baselineskip)

排版我们的棺材并留下一些灵活的垂直空间,以便我们的幻灯片在页面上均匀分布。

    \TypesetCoffin\FrameCoffin
    \medskip\vfill\par
  }
  \usepackage{kantlipsum}

此包仅用于示例。除非您正在排版康德的相关摘录,并且不介意可能过时的翻译,否则请不要将其加载到您的实际文档中。

一些新命令。

  \newcommand\extractref{}
  \newcommand\extractedref{}

定义其中一个作为辅助宏。

  \def\extractref label=#1\null{#1}

frame这改变了模式下的定义article。通常,Beamer 会frame在所有模式下排版内容。但是,我们在这里不希望这样。我们将其定义为接受单个可选参数。其他所有内容都会消失。但是,如果有一个可选的第一个参数并且它不为空,我们将假定它是,label=<key for label>并且我们将提取此引用。

  \RenewEnviron{frame}[1][]{%
    \edef\tempa{#1}\edef\tempb{}%
    \ifx\tempa\tempb\relax
    \else
      \outputempty

如果保持跟踪的宏\extractedref不为空,则说明存在一张没有相应注释的幻灯片,因此我们假设该幻灯片没有注释,并在右侧输出带有一组空白注释的幻灯片。

      \xdef\extractedref{\extractref #1\null}%

对于当前的frame,我们不排版任何内容。我们只是提取并存储 中的引用\extractedref

    \fi
  }

现在来看看输出不带注释的 s 的宏。这由重新定义和环境frame使用。frameannot

  \newcommand\outputempty{%
    \edef\tempb{}%
    \edef\tempa{\extractedref}%
    \ifx\tempa\tempb\relax
    \else

这里不需要棺材,但是我们使用默认配置输出幻灯片并放入相同的垂直空间,以使幻灯片均匀分布在页面上。

      \fbox{\includeslide[width=\frmwd]{\extractedref}}%
      \medskip\vfill\par
    \fi
  }
}

我猜你不想在这里缩进段落。你可以考虑使用包parskip,但这可能并不重要,这取决于你的笔记的内容。

  \setlength\parindent{0pt}

如果最后一个frame标签没有标注,我们需要确保它进入讲义。再加一个\outputempty就行了。

  \AtEndDocument{\outputempty}

配置就是这样。现在来看看文档。

\begin{document}

这是一个框架,标记为frame-a

\begin{frame}[label=frame-a]{A Frame}%
  \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{example-image-a}
\end{frame}

以下为 的注释frame-a

\begin{annot}{frame-a}
  Not much to say about image A.
\end{annot}

类似地,对于frame-bframe-c

\begin{frame}[label=frame-b]{B Frame}%
  \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{example-image-b}
\end{frame}
\begin{annot}{frame-b}
  Not much to say about image b.
\end{annot}

\begin{frame}[label=frame-c]{C Frame}%
  \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{example-image-c}
\end{frame}
\begin{annot}{frame-c}
  Not much to say about image C.
\end{annot}

geometry这将生成具有默认布局的页面。

这是frame-another。这个没有注释,所以没有annot后续内容。

\begin{frame}[label=frame-another]{Another Frame}%
  \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{example-image}
\end{frame}

article模式下,下一帧将导致frame-another输出,因为我们假设不存在该帧的注释frame。我用完了 MWE 的图像,并且厌倦了,所以这里有一个咆哮的替代方案。

\begin{frame}[label=frame-tiger]{Tiger Frame}%
  \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{tiger}
\end{frame}
\begin{annot}{frame-tiger}
  This frame shows a large, wild cat.
  Well, what it actually shows is a small picture of a wild cat, but you are meant to infer that it represents a larger reality.
\end{annot}

下一篇的frame注释很长,所以会单独写一页。这里的吼声没那么大,但人数越多越安全,也许吧。

\begin{frame}[label=frame-cats]{Cats Frame}%
  \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{cathod}
\end{frame}
\begin{annot}{frame-cats}
  \kant[1-2]
\end{annot}

\begin{frame}[label=frame-which]{Which Frame?}%
 \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{cauldron}
\end{frame}
\begin{annot}{frame-which}
  This frame includes a pun, a cauldron and a question.
  More accurately, it includes a pun, a depiction of a cauldron and a question mark.
\end{annot}

最后,值得注意的是frame,要确保最后的结果\outputempty能够奏效。

\begin{frame}[label=frame-gadael]
  \includegraphics[width=\textwidth]{cath-gadael-chartref}
\end{frame}

\end{document}

幻灯片:

幻灯片

讲义/笔记:

带注释的讲义

完整代码(需要在指定位置替换文件名):

\begin{filecontents}{\jobname-beamer.tex}
\documentclass[ignorenonframetext]{beamer}
\input{<main file name>}% substitute \jobname or whatever here
\end{filecontents}
\begin{filecontents}{\jobname-article.tex}
\documentclass{article}
\usepackage{beamerarticle,graphicx}
\setjobnamebeamerversion{<main file name>-beamer}% substitute \jobname or whatever here
\input{<main file name>}% substitute \jobname or whatever here
\end{filecontents}

% \jobname.tex = <main file name>.tex
\mode<article>
{
  \usepackage{xcoffins,environ,geometry,calc,pgf}
  \newlength\annotsep
  \setlength\annotsep{.5em}% set the horizontal separation of frames and annotations
  \newlength\frmwd
  \AtBeginDocument{%
    \setlength\frmwd{.5\linewidth-.5\annotsep-2\fboxsep-2\fboxrule}%
  }
  \NewCoffin\AnnotCoffin
  \NewCoffin\FrameCoffin
  \NewEnviron{annot}[2][]{%
    \edef\tempa{\extractedref}\edef\tempb{#2}%
    \ifx\tempa\tempb\relax
    \else\outputempty\fi\xdef\extractedref{}%
    \SetVerticalCoffin\FrameCoffin{.5\linewidth-.5\annotsep}{%
      \fbox{\includeslide[width=\frmwd,#1]{#2}}% depending on theme, remove frame if not required
    }%
    \SetVerticalCoffin\AnnotCoffin{.5\linewidth-.5\annotsep}{%
      \BODY
    }%
    \JoinCoffins\FrameCoffin[t,r]\AnnotCoffin[t,l](\annotsep,-.5\baselineskip)
    \TypesetCoffin\FrameCoffin
    \medskip\vfill\par
  }
  \usepackage{kantlipsum}
  \newcommand\extractref{}
  \newcommand\extractedref{}
  \def\extractref label=#1\null{#1}
  \RenewEnviron{frame}[1][]{%
    \edef\tempa{#1}\edef\tempb{}%
    \ifx\tempa\tempb\relax
    \else
      \outputempty
      \xdef\extractedref{\extractref #1\null}%
    \fi
  }
  \newcommand\outputempty{%
    \edef\tempb{}%
    \edef\tempa{\extractedref}%
    \ifx\tempa\tempb\relax
    \else
      \fbox{\includeslide[width=\frmwd]{\extractedref}}%
      \medskip\vfill\par
    \fi
  }
  \setlength\parindent{0pt}
  \AtEndDocument{\outputempty}
}
\begin{document}
\begin{frame}[label=frame-a]{A Frame}%
  \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{example-image-a}
\end{frame}
\begin{annot}{frame-a}
  Not much to say about image A.
\end{annot}

\begin{frame}[label=frame-b]{B Frame}%
  \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{example-image-b}
\end{frame}
\begin{annot}{frame-b}
  Not much to say about image b.
\end{annot}

\begin{frame}[label=frame-c]{C Frame}%
  \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{example-image-c}
\end{frame}
\begin{annot}{frame-c}
  Not much to say about image C.
\end{annot}

\begin{frame}[label=frame-another]{Another Frame}%
  \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{example-image}
\end{frame}

\begin{frame}[label=frame-tiger]{Tiger Frame}%
  \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{tiger}
\end{frame}
\begin{annot}{frame-tiger}
  This frame shows a large, wild cat.
  Well, what it actually shows is a small picture of a wild cat, but you are meant to infer that it represents a larger reality.
\end{annot}

\begin{frame}[label=frame-cats]{Cats Frame}%
  \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{cathod}
\end{frame}
\begin{annot}{frame-cats}
  \kant[1-2]
\end{annot}

\begin{frame}[label=frame-which]{Which Frame?}%
 \includegraphics[height=.75\textheight,width=\textwidth,keepaspectratio]{cauldron}
\end{frame}
\begin{annot}{frame-which}
  This frame includes a pun, a cauldron and a question.
  More accurately, it includes a pun, a depiction of a cauldron and a question mark.
\end{annot}

\begin{frame}[label=frame-gadael]
  \includegraphics[width=\textwidth]{cath-gadael-chartref}
\end{frame}

\end{document}

相关内容