Saving arguments of commands to be used later
I have made it so that \@name[<index>]
\@work[<index>]
, and \@email[<index>]
are arrays, where the index is stepped with every call to \information{}{}{}
.
\listcontact{<index>}
will provide the contact info for the one specified index. In the MWE, I loop through all indices.
\documentclass{article}
\usepackage{pgffor}
\makeatletter
\newcounter{infocnt}
\newcommand{\name}[1]{%
\expandafter\def\csname @name[\theinfocnt]\endcsname{#1}}
\newcommand{\work}[1]{%
\expandafter\def\csname @work[\theinfocnt]\endcsname{#1}}
\newcommand{\email}[1]{%
\expandafter\def\csname @email[\theinfocnt]\endcsname{#1}}
\newcommand{\information}[3]{%
\stepcounter{infocnt}%
\name{#1}%
\work{#2}%
\email{#3}%
}
\newcommand\listcontact[1]{\noindent%
NAME: \textbf{\csname @name[#1]\endcsname}\\
WORK: \textbf{\csname @work[#1]\endcsname}\\
EMAIL: \textbf{\csname @email[#1]\endcsname}\par
\vskip 1in
}
\makeatother
\information{Faa Foo}{Univ.\ Blah}{[email protected]}
\information{XXX}{YYY}{[email protected]}
\begin{document}
\foreach\x in {1,2,...,\theinfocnt}{\listcontact{\x}}
\end{document}
If I had my 'druthers, though, I would input the list all at once, quite simply, with the same output. The listofitems
package immediately stores the list as an accessible array:
\documentclass{article}
\usepackage{listofitems}
\newcommand\listcontact[1]{\noindent%
NAME: \textbf{\contacts[#1,1]}\\
WORK: \textbf{\contacts[#1,2]}\\
EMAIL: \textbf{\contacts[#1,3]}\par
\vskip 1in
}
\setsepchar{\\/&}
\begin{document}
\readlist*\contacts{
Faa Foo & Univ.\ Blah & [email protected]\\
XXX & YYY & [email protected]}
\foreachitem\x\in\contacts[]{\listcontact{\xcnt}}
Here is the email of contact 2: \contacts[2,3].
\end{document}
With a small supplement from the readarray
package, the list of contacts could even be stored in an external file.
This is “property lists” playground. Here I define \newcontact
for defining a contact with a key-value interface.
With \newcontactscheme
one defines different ways to print the data; default
is used by \listcontact
if no optional argument is supplied. In the definition, use \getcontact{<key>}{#1}
to print the value corresponding to <key>
for the current contact, represented by #1
.
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\newcontact}{mm}
{% #1 = contact label, #2 = data
\prop_new:c { g_sigur_contact_#1_prop }
\prop_gset_from_keyval:cn { g_sigur_contact_#1_prop } { #2 }
}
\NewDocumentCommand{\listcontact}{O{default}m}
{
\cs_set_eq:Nc \__sigur_contact_list:n { sigur_contact_list_#1:n }
\__sigur_contact_list:n { #2 }
}
\NewDocumentCommand{\getcontact}{mm}
{
\sigur_contact_print:nn { #1 } { #2 }
}
\NewDocumentCommand{\newcontactscheme}{m+m}
{% #1 = scheme name, #2 = definition
\cs_new_protected:cn { sigur_contact_list_#1:n } { #2 }
}
\cs_new_protected:Nn \sigur_contact_print:nn
{
\prop_item:cn { g_sigur_contact_#2_prop } { #1 }
}
\ExplSyntaxOff
\newcontactscheme{default}{%
\par\noindent
\getcontact{name}{#1}\\
\getcontact{work}{#1}\\
\getcontact{email}{#1}\par
}
\newcontactscheme{short}{%
\getcontact{name}{#1}, \getcontact{email}{#1}%
}
\newcontactscheme{alternate}{%
\begin{tabular}[t]{@{}l@{ }l@{}}
Name: & \getcontact{name}{#1} \\
Work: & \getcontact{work}{#1} \\
Email: & \texttt{\getcontact{email}{#1}}
\end{tabular}%
}
\newcontact{foo}{
name=Faa Foo,
work=Univ.\ Blah,
[email protected]
}
\newcontact{xxx}{
name=XXX,
work=YYY,
[email protected]
}
\begin{document}
\listcontact{foo}
\medskip
\listcontact{xxx}
\medskip
Short: \listcontact[short]{xxx}
\medskip
Alternate: \listcontact[alternate]{foo}
\end{document}
A version that also defines \listallcontacts
(the optional argument is one of the defined schemes).
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\newcontact}{mm}
{% #1 = contact label, #2 = data
\prop_new:c { g_sigur_contact_#1_prop }
\prop_gset_from_keyval:cn { g_sigur_contact_#1_prop } { #2 }
\seq_gput_right:Nn \g_sigur_contact_seq { #1 }
}
\NewDocumentCommand{\listcontact}{O{default}m}
{
\cs_set_eq:Nc \__sigur_contact_list:n { sigur_contact_list_#1:n }
\__sigur_contact_list:n { #2 }
}
\NewDocumentCommand{\listallcontacts}{O{default}}
{
\cs_set_eq:Nc \__sigur_contact_list:n { sigur_contact_list_#1:n }
\seq_map_inline:Nn \g_sigur_contact_seq
{
\__sigur_contact_list:n { ##1 } \par
}
}
\NewDocumentCommand{\getcontact}{mm}
{
\sigur_contact_print:nn { #1 } { #2 }
}
\NewDocumentCommand{\newcontactscheme}{m+m}
{% #1 = scheme name, #2 = definition
\cs_new_protected:cn { sigur_contact_list_#1:n } { #2 }
}
\seq_new:N \g_sigur_contact_seq
\cs_new_protected:Nn \sigur_contact_print:nn
{
\prop_item:cn { g_sigur_contact_#2_prop } { #1 }
}
\ExplSyntaxOff
\newcontactscheme{default}{%
\par\noindent
\getcontact{name}{#1}\\
\getcontact{work}{#1}\\
\getcontact{email}{#1}\par
}
\newcontactscheme{short}{%
\getcontact{name}{#1}, \getcontact{email}{#1}%
}
\newcontactscheme{alternate}{%
\begin{tabular}[t]{@{}l@{ }l@{}}
Name: & \getcontact{name}{#1} \\
Work: & \getcontact{work}{#1} \\
Email: & \texttt{\getcontact{email}{#1}}
\end{tabular}%
}
\newcontact{foo}{
name=Faa Foo,
work=Univ.\ Blah,
[email protected]
}
\newcontact{xxx}{
name=XXX,
work=YYY,
[email protected]
}
\begin{document}
\listcontact{foo}
\medskip
\listcontact{xxx}
\medskip
Short: \listcontact[short]{xxx}
\medskip
Alternate: \listcontact[alternate]{foo}
\medskip
\listallcontacts
\medskip
\listallcontacts[short]
\end{document}
This is similar to Steven Seglets solution with slightly different packaging. You can show a single contact with \ShowContact{}
or list all the contact with \listcontacts
Notes:
- The values are stored based on
#1
which is used as the key to access the contacts. An attempt to reuse the same key is now flagged as an error. - This has now been updated to add a
\medskip
between entries when the entire list is printed. The\medskip
is not added before the first entry, nor after the last as shown in the figure.
Code:
\documentclass{article}
\usepackage{etoolbox}
\makeatletter
\newtoggle{@IsFirstEntryInList}
\newcommand*{\@ShowContact}[1]{%
\iftoggle{@IsFirstEntryInList}{%
\global\togglefalse{@IsFirstEntryInList}%
}{%
\medskip% <-- separator between entries
}%
\ShowContact{#1}%
}
\newcommand*{\ShowContact}[1]{%
\par\noindent\textbf{\csuse{name #1}}%
\par\noindent\textit{\csuse{work #1}}%
\par\noindent\texttt{\csuse{email #1}}%
}%
%% https://tex.stackexchange.com/a/14394/4301
\newcommand*{\listcontacts}{% Initialize
\global\toggletrue{@IsFirstEntryInList}%
}
\newcommand{\AddToListOfContacts}[1]{%
\g@addto@macro\listcontacts{{#1}}%
}
\newcommand{\information}[3]{%
\ifcsdef{name #1}{%
\PackageError{\jobname}{Multiple uses of the key: '#1'}{}%
}{%
\csdef{name #1}{#1}%
\csdef{work #1}{#2}%
\csdef{email #1}{#3}%
\AddToListOfContacts{\unexpanded{\@ShowContact{#1}}}%
}%
}
\makeatother
\information{Faa Foo}{Univ.\ Blah}{[email protected]}
\information{Harvard}{Harvard University}{[email protected]}
%\information{Harvard}{xxx University}{[email protected]}% <-- Triggers an error
\begin{document}
\noindent
To show one contact:
\ShowContact{Harvard}
\medskip\noindent
To show all contacts:
\listcontacts
\par\noindent
Text following to check that there is no extra space at end...
\end{document}