6

I want to append some text to a command but expand a counter while doing so. Here is an example of what the problem is:

MWE:

\documentclass{article}

\newcommand{\topics}{}
\newcounter{topic}
\newcommand{\topic}[1]{\stepcounter{topic}\expandafter\def\expandafter\topics\expandafter{\topics\hangindent=0.5cm Topic \#\thetopic: #1\par}}

\topic{test A}
\topic{test B}
\topic{test C}

\begin{document}
    \topics
\end{document}

This produces:

Topic #3: test A
Topic #3: test B
Topic #3: test C

But it should produce:

Topic #1: test A
Topic #2: test B
Topic #3: test C

I've also tried this, to no avail:

\newcommand{\topic}[1]{\stepcounter{topic}\g@addto@macro\topics{\hangindent=0.5cm Topic \#\thetopic: #1\par}}
5

You can use \edef here:

\newcommand{\topic}[1]{%
    \stepcounter{topic}%
    \edef\topics{\unexpanded\expandafter{\topics}\hangindent=0.5cm
        \noexpand\textbf{Topic \#\thetopic:} \unexpanded{#1}\par}%
}

The \unexpanded\expandafter{...} expands the current \topics list once but prevents it from being fully expanded. This is important on later calls of \topic to make the expansion not break other commands that shouldn't be fully expanded (see the use of \textbf in my example).

Using this macros gives the desired output

enter image description here

2
\documentclass{article}

\newcommand{\topics}{}
\newcounter{topic}
\newcommand\topic[1]{%
    \stepcounter{topic}%
    \edef\topics{\topics\hangindent=0.5cm Topic \#\thetopic: #1\par}}

\topic{test A}
\topic{test B}
\topic{test C}

\begin{document}
    \topics
\end{document}

enter image description here

  • Try \topic{\textbf{A test}} – egreg May 17 at 7:06
  • @egreg I think that's why in siracusa's answer \unexpanded is used... @Red-Cloud: Another approach could be putting #1 into a token-register and taking advantage of the fact that \edef won't expand the result of \the\mytoks any further... – Ulrich Diez May 17 at 11:07
2

Your macro works fine if you move the \stepcounter after the expansion of \topics:

\documentclass{article}

\def\topics{}
\newcounter{topic}

\def\topics{}
\def\topic#1{%
   \expandafter\def\expandafter\topics\expandafter{\topics 
     \stepcounter{topic} 
     \hangindent=0.5cm
     Topic \#\thetopic: #1\par}}

\topic{test A}
\topic{test B}
\topic{test C}

\begin{document}
    \topics
\end{document}

Since \topics is only expanded once, you can have al kind of macros in it and in the argument of \topic.

enter image description here

  • Due to (La)TeX's \endlinechar-thingie at the time of reading and tokenizing you will get a space token behind \stepcounter{topics}. The first one might cause undesired horizontal glue as LaTeX might not yet have left horizontal mode when \topics gets executed. Subsequent ones in any case are preceded by \par which implies that LaTeX will encounter them while in vertical mode where space tokens don't yield (horizontal) glue. Perhaps it is a good idea to initialize the \topics-macro not to emptiness but to \par. – Ulrich Diez May 17 at 10:35
  • 1
    @UlrichDiez Thanks, but I just wanted show the OP that his macro was almost good. I have not intended to make a better macro. It is just that when you make a macro and it does not work and everything seems ok, it is very frustrating. So if it is only a detail, it is nice to know that you were not so wrong. At least, that is what happens to me and, I think, to many other non-TeXperts. – Raoul Kessels May 17 at 10:43
  • I think I can understand your feelings. ;-) For me (La)TeX is fun as long as I have the leisure and the muse for facing the challenge. But getting stuck and struggling with one inscrutable error message before the next while having to work productively and meeting deadlines is a horror. – Ulrich Diez May 17 at 10:54
1

In case you both don't wish to use \edef (which would also totally expand the token list contained in the argument #1 of the \topic-macro) and don't wish to integrate the \stepcounter-directives into the \topics-macro, you can easily use a combination of \romannumeral0-expansion and \exchange— the gist is:

\romannumeral is used for "gobbling" tokens that form a number and in return for them delivering character-tokens which form the representation of that number in lowercase roman numerals.
\romannumeral in any case triggers "gobbling" those tokens that form the number. But in case that number does form an integer which is not positive, silently, i.e., without error-message or the like, no tokens at all will be delivered in return.
Besides this when searching for more digits or the terminating space-token of a digit-sequence, \romannumeral will trigger expansion of expandable tokens. With a digit-sequence, the terminating space-token will be removed silently.

Thus you can (ab?)use \romannumeral for having (La)TeX doing a lot of expansion-work as long as it is ensured that in the end \romannumeral will find a non-positive integral number.

In the example below \romannumeral is used for triggering expansion of \thetopic three times (because expansion needs to be triggered three times until you get the value of the topic-counter) before exchanging things and triggering expansion of the \topics-macro once.

In the example below each instance of \romannumeral will in the end find the digit(-sequence) "0", which is formed by the character-token(-sequence) 0, trailed by a space-token (which terminates that digit-sequence(character-token-sequence) and thus will take these things for the non-positive number 0 and therefore will "gobble" both the character-token "0" which forms the digit(-sequence)/number "0" and the space-token while silently in return for them not delivering any token at all.

\documentclass{article}

\newcommand\exchange[2]{#2#1}%

\newcommand*{\topics}{}%
\newcounter{topic}
\newcommand{\topic}[1]{%
  \stepcounter{topic}%
  \expandafter\def\expandafter\topics\expandafter{%
     \romannumeral0%
     \expandafter\exchange\expandafter{%
       \romannumeral0\exchange{ }{%
         \expandafter\expandafter\expandafter
         \expandafter\expandafter\expandafter
         \expandafter
       }%
       \thetopic: #1\par}{%
       \ifx\topics\empty
          \exchange{ }{\expandafter\expandafter\expandafter}%
          \expandafter\expandafter\expandafter\par
       \else
          \exchange{ }{\expandafter\expandafter\expandafter}%
       \fi
       \topics\hangindent=0.5cm Topic \#%
     }%
  }%
}%

\topic{test A}
\topic{test B}
\topic{test C}

%\show\topics

\begin{document}
{\frenchspacing\texttt{\string\topics: \meaning\topics}}%

\bigskip
\noindent\hrulefill\null

\bigskip
\topics
\end{document}

enter image description here

Nonetheless the solution provided by Raoul Kessels, where \stepcounter-directives get integrated into the \topics-macro is preferable because when you do it in Raoul Kessel's way you can instead also use \refstepcounter-directives and place referencing-\labels into the argument of the \topic-macro for referencing single topics by means of the \label-\(page)ref-mechanism.

0

You need to expand \thetopic before doing the append operation:

\documentclass{article}

\newcommand{\topics}{}
\newcounter{topic}
\newcommand{\topic}[1]{%
  \stepcounter{topic}%
  % newer versions of the engines (TeX Live 2019)
  \expandafter\appendtotopics\expandafter{\expanded{\thetopic}}{#1}%
  % for older versions of the TeX engines use the following
  %\begingroup\edef\x{\endgroup\noexpand\appendtotopics{\thetopic}}\x{#1}%
}
\newcommand{\appendtotopics}[2]{%
  \expandafter\def\expandafter\topics\expandafter{%
    \topics\hangindent=0.5cm Topic \##1: #2\par
  }%
}

\topic{test A}
\topic{test B}
\topic{test C}

\begin{document}

\topics

\end{document}

enter image description here

An expl3 version:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\topics}{}
 {
  \tl_use:N \g_kessels_topics_tl
 }
\NewDocumentCommand{\topic}{m}
 {
  \kessels_topic:n { #1 }
 }

\int_new:N \g_kessels_topic_int
\tl_new:N \g_kessels_topics_tl

\cs_new_protected:Nn \kessels_topic:n
 {
  \int_gincr:N \g_kessels_topic_int
  \__kessels_topic_add:fn { \int_to_arabic:n { \g_kessels_topic_int } } { #1 }
 }

\cs_new_protected:Nn \__kessels_topic_add:nn
 {
  \tl_gput_right:Nn \g_kessels_topics_tl { \hangindent=0.5cm~Topic~\##1:~#2\par }
 }
\cs_generate_variant:Nn \__kessels_topic_add:nn { f }

\ExplSyntaxOff

\topic{test A}
\topic{test B}
\topic{test C}

\begin{document}

\topics

\end{document}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.