![存储值、宏选项以及与其他包的交互的问题](https://linux22.com/image/393768/%E5%AD%98%E5%82%A8%E5%80%BC%E3%80%81%E5%AE%8F%E9%80%89%E9%A1%B9%E4%BB%A5%E5%8F%8A%E4%B8%8E%E5%85%B6%E4%BB%96%E5%8C%85%E7%9A%84%E4%BA%A4%E4%BA%92%E7%9A%84%E9%97%AE%E9%A2%98.png)
抱歉,标题太笼统了,我想解决一个非常具体的问题:
我正在尝试增强 Alan Munn 提供的框架这里
表示自然发生的话语(还有一些额外的内容,这里省略),代码来自这frougon 的回答。这一切的意义在于为 Alan 的代码(使用该expex
包)提供一种机制,使其不打印重复的说话者标签。我以为我能够整合这两种解决方案,但是,随着复杂性的增加,不知何故我设法把它搞砸了,我无论如何也想不出哪里出了问题。
这是最小的 WE:
% !TEX TS-program = xelatexmk
\RequirePackage{filecontents}
\begin{filecontents}{discourse.sty}
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{discourse}
\RequirePackage[user,savepos]{zref}
\RequirePackage{expex}
\newcounter{linenum}
\newlength{\largestspkr}
\newlength{\largestnum}
\newcommand{\deflargestlabel}[2][99]{
\settowidth{\largestnum}{#1}
\settowidth{\largestspkr}{~#2}}
\deflargestlabel[999]{speaker~99}
\RequirePackage{perpage}
\newcounter{spkrcounter}
\MakePerPage{spkrcounter}
\newenvironment{discourseenv}{%
\setcounter{linenum}{0}%
\setcounter{spkrcounter}{0}%
\ignorespaces
}{%
\par\ignorespacesafterend
}
\DeclareOption{skiprepetitions}{%
\AtBeginDocument{\let\discourse@print\discourse@print@skip}%
}
\DeclareOption{keeprepetitions}{%
\AtBeginDocument{\let\discourse@print\discourse@print@keep}%
}
\ExecuteOptions{skiprepetitions}
\ProcessOptions\relax
\RequirePackage{xifthen}
\def\discourse@storedval{} % create a macro to later store a value in
\newcommand{\spkr}[1]{%
% create line numbers:
\refstepcounter{linenum}\makebox[\largestnum][r]{\thelinenum}\hspace{1em}
\ifthenelse{\isempty{#1}}%
{\makebox[\largestspkr][l]{}}% if empty > empty box
{% If this is the first \stepcounter{spkrcounter} executed since the current
% page was started, this sets 'spkrcounter' to 1.
\stepcounter{spkrcounter}%
\discourse@print{#1}%
\def\discourse@storedval{#1}%
}%
}
\def\discourse@print@skip#1{%
\ifthenelse{\cnttest{\value{spkrcounter}}>{1}\AND
\equal{#1}{\discourse@storedval}}%
{\makebox[\largestspkr][l]{}}% if repeated > empty box
{\makebox[\largestspkr][l]{#1:}}%
}
\def\discourse@print@keep#1{\makebox[\largestspkr][l]{#1:}}
\end{filecontents}
\documentclass{article}
\usepackage{discourse}
\begin{document}
Here it works:
\spkr{A} OK
\spkr{A} OK
\spkr{B} OK
\spkr{A} OK
\vbox{}
Here too in the environment:
\begin{discourseenv}
\spkr{A} OK
\spkr{A} OK
\spkr{B} OK
\end{discourseenv}
\vbox{}
But in combination with expex it screws up:
\begin{discourseenv}
\ex[exno=\spkr{A}, exnoformat=X] OK (prints A) \xe
\ex[exno=\spkr{A}, exnoformat=X] OK (empty) \xe
\ex[exno=\spkr{B}, exnoformat=X] OK (prints B) \xe
\ex[exno=\spkr{A}, exnoformat=X] OK (empty) \xe
\ex[exno=\spkr{B}, exnoformat=X] OK (prints B) \xe
\end{discourseenv}
\begin{discourseenv}
\ex[exno=\spkr{B}, exnoformat=X] OK (prints B) \xe
\newpage
\ex[exno=\spkr{B}, exnoformat=X] OK (prints B) \xe
\ex[exno=\spkr{B}, exnoformat=X] This one should be empty \xe
\ex[exno=\spkr{B}, exnoformat=X] This one should be empty \xe
\ex[exno=\spkr{A}, exnoformat=X] This one should print A \xe
\ex[exno=\spkr{A}, exnoformat=X] OK (empty) \xe
\end{discourseenv}
\end{document}
宏的前几个实例运行正常\spkr
,但在下一页时,它的行为就很奇怪了。有人能发现哪里出了问题吗?
答案1
您只需要使定义全局化,因为\ex ... \xe
它是在组内执行的。
\newcommand{\spkr}[1]{%
% create line numbers:
\refstepcounter{linenum}\makebox[\largestnum][r]{\thelinenum}\hspace{1em}
\ifthenelse{\isempty{#1}}%
{\makebox[\largestspkr][l]{}}% if empty > empty box
{% If this is the first \stepcounter{spkrcounter} executed since the current
% page was started, this sets 'spkrcounter' to 1.
\stepcounter{spkrcounter}%
\discourse@print{#1}%
\gdef\discourse@storedval{#1}% <--- global!!!
}%
}