0

In this post, I found a nice trick for dealing with lists. The code below allows to print lists with an optional separator argument.

\documentclass{article}
\usepackage{etoolbox}% http://ctan.org/pkg/etoolbox
\newcommand{\printlist}[2][,]{%
  \def\itemdelim{\def\itemdelim{#1}}% Item delimiter delayed by one cycle
  \renewcommand*{\do}[1]{\itemdelim##1}% How each item is processed
  \docsvlist{#2}}% Process CSV list
\begin{document}
$\printlist{1,2,3,4,5,6,7}$ \par
$\printlist[;]{a,b,c,d,e,f}$
\end{document}

However, if I use \printlist within the \author command, in combination with a newline \\, this won't work properly: The line break is set only for the first element of the list. For all other elements, the line break is ignored:

\documentclass{article}

\usepackage{etoolbox}% http://ctan.org/pkg/etoolbox
\newcommand{\printlist}[2][;]{%
  \def\itemdelim{\def\itemdelim{#1}}% Item delimiter delayed by one cycle
  \renewcommand*{\do}[1]{\itemdelim##1}% How each item is processed
  \docsvlist{#2}}% Process CSV list

\title{Test}
\author{\printlist[,\\]{abc,def,ghi,jkl}}
\begin{document}
\maketitle
\end{document}

Failing case

If I use a separator without line-break, e.g. ::, the above works as expected.

Successful test 1

Adding additional line-breaks \\ in the \author command also leads to the expected result:

\author{\printlisti[::]{abc,def,ghi}\\123\\456\\789}

Successful test 2

It seems that the combination of \printlist with line breaks \\ is causing a problem. How come?

5
  • 1
    The argment to \author will be put inside a tabular where each cell forms its own group. The definitions of \itemdelim and \do are local and won't survive this first row. Commented Mar 11, 2023 at 2:28
  • @Qrrbrbirlbel Thanks. I can't draw a link between tabular and local \do or \itemdelim. Why are they lost after the first row?
    – normanius
    Commented Mar 11, 2023 at 2:32
  • Try \begin{tabular}{c}\def\itemdelim{test} \\ \itemdelim \end{tabular}. It will lead to an Undefined control sequence \itemdelim. You basically need \gdefs for every instance of \def and \renewcommand. Or prepare the list beforehand. Commented Mar 11, 2023 at 2:35
  • Ah. Now it makes sense. Thanks. One more question: While \gdef helps in your example, why doesn't work for my problem? Using \gdef in the definition of \printlist leads to the same result.
    – normanius
    Commented Mar 11, 2023 at 2:46
  • 1
    My previous comment wasn't precise. The first \def\itemdelim will be used in the first row. It's that internal \def\itemdelim{#1} that needs to be global (as well as the \do too). I hope my answer is somewhat clearer. Commented Mar 11, 2023 at 2:49

1 Answer 1

1

The argument to \author will be typeset in a tabular. Each cell forms its own group thus, the internal definition of \itemdelim and the definition of \do won't survive your first row.

Essentially, this is what's happening:

\begin{tabular}{c}
  \def\itemdelim{test} \\
  \itemdelim
\end{tabular}

and the same for \do, though in the second row that will have the same definition as outside of tabular and won't lead to an error message.


You will need to do the definitions of \itemdelim (for the non-first entry) and \do global:

\newcommand{\printlist}[2][;]{%
  \def\itemdelim{\gdef\itemdelim{#1}}%
  \gdef\do##1{\itemdelim##1}%
  \docsvlist{#2}}
\author{\printlist[,\\]{abc,def,ghi,jkl}}

Though, you could apply the “trick” of \itemdelim directly for \do and skip \itemdelim by using #1 directly:

\newcommand{\printlist}[2][;]{%
  \def\do##1{##1\gdef\do####1{#1####1}}%
  \docsvlist{#2}}
\author{\printlist[,\\]{abc,def,ghi,jkl}}

With another auxilliary macro like \defdo we can avoid defining \do global (at the cost of another document-wide defined macro):

\newcommand*\defdo[1]{%
  \def\do##1{#1\defdo{#1}##1}}%
\newcommand{\printlist}[2][;]{%
  \def\do##1{##1\defdo{#1}}%
  \docsvlist{#2}}%
\author{\printlist[,\\]{abc,def,ghi,jkl}}

This sneaks the definition of \do from row to row behind the \\ so that it will be available in the next row.


Alternatively, you could pre-process the list and just forward that to \author:

\newcommand{\savelist}[3][;]{%
  \renewcommand*\do[1]{%
    \newcommand*#3{##1}%
    \renewcommand*\do[1]{%
      \appto#3{#1####1}%
    }%
  }%
  \docsvlist{#2}}
\savelist[,\\]{abc,def,ghi,jkl}\authors
\author{\authors}

In this case, the definition of \do is also “global” because it is defined on the top level of the document.

Defining \do global shouldn't create a conflict since every other code that uses \do should have defined it itself without assuming any definition. Mixing global and local assignments/definitions could be messy, though, so using \savelist might be preferable.


Looking beyond etoolbox, LaTeX3's l3clist package provides \clist_use:Nn which doesn't need any definitions to just place something (#1 = ,\\) between a list's entries:

\documentclass{article}
\ExplSyntaxOn
\DeclareDocumentCommand{\printlist}{ O{;} m}{
  \clist_set:Nn \l_tmpa_clist {#2}
  \clist_use:Nn \l_tmpa_clist {#1}
}
\ExplSyntaxOff
\author{\printlist[,\\]{abc,def,ghi,jkl}}
\title{Test}
\begin{document}
\maketitle
\end{document}
3
  • Wow, thanks a lot! Are there any potential side effects when defining \do globally? Therefore pre-processing the list might be a bit safer, right?
    – normanius
    Commented Mar 11, 2023 at 2:56
  • 1
    @normanius No, there shouldn't be a conflict with other usages of \do. But \savelist still seems like a cleaner approach. I've updated my answer with a LaTeX3 solution that works without having to use any definitions. (I left out a low-level implementation of a simple ,-list parser because I don't think you want to use that over \savelist or the LaTeX3 solution.) Commented Mar 11, 2023 at 3:43
  • Thank you so much. I wish I could upvote your answer more than once.
    – normanius
    Commented Mar 11, 2023 at 4:31

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .