2

I am quite new to LaTeX and am a software engineer by day, so please bear with me.

I am trying to create list of items that can be generated through the use of some commands to add to that list, though I can't figure out how to do so.

Essentially I want to be able to do something like this...

\def\list{}
\newcommand{\createlist}{
    \begin{description}
        \list{}
    \end{description}
}
\newcommand{\addtolist}[2]{
    \edef\list{\list{}\item[#1]{#2}}
    %\edef\list{\list{}#1 - #2}
}

\addtolist{Thing 1}{blah blah blah}
\addtolist{Thing 2}{other thing}

\createlist{}

If I were to use the \edef that is commented out, this code would compile and run, but I'd like to generate the \item tags as well which isn't behaving and causes a crash. Is there a proper way to achieve this?

As a programmer, my instinct is to create an array and push each new line into that so that it can then be looped through and printed into an item inside of the environment, but I just cannot figure this out.

2
  • 1
    Instead of inventinhæg your own, have a look at the list featured in the etoolbox package. It might be easiest to just gather the data and then process the list data in a manner that adds the \item on each element.
    – daleif
    Jul 24 at 6:37
  • I'll look into etoolbox package later, it does sound like it could work. I will continue to try this at least as an exercise to learn LaTeX some more Jul 24 at 7:04
1

The first big problem with the OP code was redefining \list, which is widely used code used to make a variety of lists, such as the description environment. Oops. So I renamed it \llist, so as to leave the list-making \list intact.

Then, I also used \g@addto@macro rather than an \edef to build the list items, because I felt it was a safer way to proceed.

\documentclass{article}

\begin{document}
\newcommand\llist{}
\newcommand{\createlist}{
    \begin{description}
        \llist{}
    \end{description}
}
\makeatletter
\newcommand{\addtolist}[2]{
    \g@addto@macro\llist{\item[#1]{#2}}
}

\addtolist{Thing 1}{blah blah blah}
\addtolist{Thing 2}{other thing}

\createlist{}
\end{document}

enter image description here

3
  • To be fair my actual code has \test so I thought it made sense to name it more appropriately for the example here. Unfortunately I'm running into the issue where is seems if you put a macro into the list, it won't be parsed until it is run entirely. So if I step a counter for each item added, and then print it with \arabic{mycounter} it will be read out as the same number for each item. Solution to that? Jul 24 at 7:06
  • @MaximSrour Certainly, you can use \edef approach instead of \g@addto@macro, if it makes sense for your application. One just has to be careful, because not all arguments are expandable. Jul 24 at 12:31
  • @MaximSrour I recommend ensuring that stepping counters for items takes place via \refstepcounter at the time when \item is carried out, right before the item-label is placed. This way in case of using hyperref, a named destination for hyperlinks will be placed. Jul 24 at 19:52
1

Does the following code provide what you have in mind?

\RequirePackage{xparse}
\documentclass{article}

\newcommand\ItemContainer{}%
\NewDocumentCommand\ResetItemContainer{}{%
  \gdef\ItemContainer{}%
}%
\makeatletter
\newcommand\AddtoItemContainer[2][]{%
  \@bsphack
  % use \xdef .. \unexpanded to avoid hash-reducing within \ItemContainer's definition.
  \xdef\ItemContainer{%
    \unexpanded\expandafter{\ItemContainer\item}\IfNoValueF{#1}{\unexpanded{[{#1}]}}\unexpanded{#2}%
  }%
  % \@esphack should be safe as -afaik - \edef doesn't affect \lastskip.
  \@esphack
}%
\makeatother
\NewDocumentCommand\PrintItemContainer{}{%
  \begin{description}\ItemContainer\end{description}%
}%

\newcounter{ThingCounter}

\begin{document}
\ResetItemContainer
\AddtoItemContainer[\refstepcounter{ThingCounter}Thing~\theThingCounter]{thing}%
\AddtoItemContainer[\refstepcounter{ThingCounter}Thing~\theThingCounter]{other thing}%
\AddtoItemContainer[\refstepcounter{ThingCounter}Thing~\theThingCounter]{yet another thing}%
\PrintItemContainer
\end{document}

enter image description here

0

It's very easy with expl3, that's included in the LaTeX kernel since 2020-10-01 (if you have an earlier release you need to add \usepackage{xparse}).

\documentclass{article}

\ExplSyntaxOn

\seq_new:N \l_srour_list_seq

\NewDocumentCommand{\addtolist}{mm}
 {
  \seq_put_right:Nn \l_srour_list_seq { \item[#1] #2 }
 }

\NewDocumentCommand{\uselist}{}
 {
  \begin{description}
  \seq_use:Nn \l_srour_list_seq { }
  \end{description}
 }

\ExplSyntaxOff

\begin{document}

\addtolist{Thing 1}{blah blah blah}
\addtolist{Thing 2}{other thing}

\uselist

\end{document}

enter image description here

This will obey standard scoping rules. If you need the assignments \addtolist to be given inside environments, they have to be global. Change the code into

\documentclass{article}

\ExplSyntaxOn

\seq_new:N \g_srour_list_seq

\NewDocumentCommand{\addtolist}{mm}
 {
  \seq_gput_right:Nn \g_srour_list_seq { \item[#1] #2 }
 }

\NewDocumentCommand{\uselist}{}
 {
  \begin{description}
  \seq_use:Nn \g_srour_list_seq { }
  \end{description}
 }

\ExplSyntaxOff

\begin{document}

\addtolist{Thing 1}{blah blah blah}
\addtolist{Thing 2}{other thing}

\uselist

\end{document}

The items are added to a sequence variable, that can be used whenever you like. The second argument to \seq_use:Nn specifies something that should be inserted between the sequence items, in this case nothing.

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.