Apologies for the rather general title, while trying to sort out a very specific problem:
I'm trying to enhance the framework that Alan Munn provided here
to represent naturally occurring discourse (with some extras, omitted here), with code from this answer by frougon.
The point of it all is to have a mechanism for Alan's code (which uses the expex package) to not print repeated labels of speakers. I thought I would be able to integrate the two solutions, yet, with increased complexity, somehow along the way I managed to screw it up and for the life of me I can't figure out what's wrong.
This is as minimal a WE as it gets:
% !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}
It works as expected on the first couple of instances of the \spkr macro, but on the next page it behaves weirdly. Anyone able to spot what's wrong?

\gdef\discourse@storedval{}would be unnecessary? – jan Apr 11 '19 at 08:12\def. – egreg Apr 11 '19 at 08:45