4

I'm trying to produce a document to compare a bunch of fontfaces. I'd like to parse an array to load and try them all.

This is what I have done:

\documentclass{article}

\usepackage{lipsum}
\usepackage{pgffor}
\usepackage{fontspec}

\def\LoadFont#1{\expandafter\newfontface\csname#1\endcsname{#1}}
\def\UseFont#1{\csname#1\endcsname}

\def\FontList{Charter,Lato,Linux Libertine O}

% these work just fine
%\LoadFont{Charter}
%\LoadFont{Lato}
%\LoadFont{Linux Libertine O}

% THIS DOES NOT WORK
\foreach \FontName in \FontList {\LoadFont\FontName}

\begin{document}
\foreach \FontName in \FontList {\UseFont\FontName\lipsum[1]}
\end{document}

While the cycle with \UseFont works fine, the one with \LoadFont does not. On its own, \LoadFont does what's expected.

I think this could be an expansion problem, but I'm not sure where it stands exactly; blind attempts led nowhere.

What's wrong with the loading cycle?

3

As already explained, the behaviour you observed comes from the established feature of \foreach to do its iterations inside scope-limiting groups.

Here is with \xintFor. I switched to another font, as I don't have Lato installed.

\documentclass{article}

\usepackage{lipsum}
\usepackage{xinttools}
\usepackage{fontspec}

\def\LoadFont#1{\expandafter\newfontface\csname#1\endcsname{#1}}
\def\UseFont#1{\csname#1\endcsname}

% original
% \def\FontList{Charter,Lato,Linux Libertine O}
% as I don't have Lato:

\def\FontList {Charter, TeX Gyre Heros, Linux Libertine O}

\xintFor #1 in \FontList \do {\LoadFont {#1}}

\begin{document}

\xintFor #1 in \FontList \do {\UseFont {#1}\lipsum[1]}

\end{document}

% Local Variables:
% TeX-engine: xetex
% End:

Blockquote

  • syntax xintFor #1 in {Charter, TeX Gyre Heros, Linux Libertine O} \do {\LoadFont {#1}} is also possible, but do not forget the braces around the comma separated values.The spaces around commas are silently removed. – user4686 Feb 18 '16 at 7:10
2

When you do

\foreach \FontName in \FontList {\LoadFont\FontName}

the \newfontface instruction is performed inside a group, so the definition of the font face is lost as soon as the group ends. This is a feature of \foreach.

Here's a set of macros in expl3 that can give you some ideas for extending them.

\documentclass{article}

\usepackage{fontspec}
\usepackage{lipsum}

\ExplSyntaxOn
\NewDocumentCommand{\LoadFont}{m}
 {
  \exp_args:Nc \newfontface { #1 } { #1 }
 }
\NewDocumentCommand{\LoadFonts}{m}
 {
  \clist_map_inline:nn { #1 }
   {
    \LoadFont{##1}
   }
 }
\NewDocumentCommand{\UseFont}{m}
 {
  \use:c { #1 }
 }
\NewDocumentCommand{\UseFonts}{m +m}
 {
  \clist_map_inline:nn { #1 }
   {
    \group_begin:
    \UseFont{##1} ##1:~#2
    \group_end:
   }
 }
\ExplSyntaxOff

\LoadFonts{Charter,Lato,Linux Libertine O}

\begin{document}

\UseFonts{Charter,Lato,Linux Libertine O}{\lipsum[2]}

\end{document}

Note that \exp_args:Nc \newfontface { #1 } { #1 } is essentially the same as

\expandafter\newfontface\csname #1\endcsname{#1}

enter image description here

If you want to use a symbolic name for a list, define a *-variant:

\documentclass{article}

\usepackage{fontspec}
\usepackage{lipsum}

\ExplSyntaxOn
\NewDocumentCommand{\LoadFont}{m}
 {
  \exp_args:Nc \newfontface { #1 } { #1 }
 }
\NewDocumentCommand{\LoadFonts}{sm}
 {
  \IfBooleanTF{#1}
   { \clist_map_inline:Nn #2 }
   { \clist_map_inline:nn { #2 } }
   {
    \LoadFont{##1}
   }
 }
\NewDocumentCommand{\UseFont}{m}
 {
  \use:c { #1 }
 }
\NewDocumentCommand{\UseFonts}{s m +m}
 {
  \IfBooleanTF{#1}
   { \clist_map_inline:Nn #2 }
   { \clist_map_inline:nn { #2 } }
   {
    \group_begin:
    \UseFont{##1} ##1:~#3
    \group_end:
   }
 }
\ExplSyntaxOff

%\LoadFonts{Charter,Lato,Linux Libertine O}

\newcommand\FontList{Charter,Lato,Linux Libertine O}
\LoadFonts*{\FontList}

\begin{document}

%\UseFonts{Charter,Lato,Linux Libertine O}{\lipsum[2]}

\UseFonts*{\FontList}{\lipsum[2]}

\end{document}
  • Impeccable. I added a couple of commands to handle my specific situation. Also, thanks for giving me an excuse to study a bit of expl3. – Paolo Brasolin Feb 18 '16 at 0:20
  • 1
    @PaoloBrasolin Sorry, but there's a much better method. ;-) – egreg Feb 18 '16 at 0:32
  • Now I see. This is very elegant. Thanks for the self-explanatory code! – Paolo Brasolin Feb 18 '16 at 1:54

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.