7

In the process to migrate from (x)keyval to pgfkeys, I realized that .estore in was not expanding my command properly.

Here is my minimal working example:

\documentclass{report}

\usepackage{pgfkeys}
\makeatletter

\newif\if@wgetdoc@title@ownpage
\pgfkeys{
    /wgetdoc/title/.cd,
    maintitle/.estore in=\@wgetdoc@title@maintitle,
    subtitle/.estore in=\@wgetdoc@title@subtitle,
    author/.estore in=\@wgetdoc@title@author,
    filename/.estore in=\@wgetdoc@title@filename,
    ownpage/.is if=@wgetdoc@title@ownpage
}

\renewcommand{\title}[1][]{%

    \pgfqkeys{/wgetdoc/title}{#1}

    \@ifundefined{@wgetdoc@title@filename}{

        \@ifundefined{@wgetdoc@title@maintitle}{
            \ClassError{wgetdoc}{You did not specify a main title}{}
        }{}

        \@ifundefined{@wgetdoc@title@maintitle}{
            \ClassError{wgetdoc}{You did not specify a main title}{}
        }{}

        \ifx\@wgetdoc@title@maintitle\@empty
            \ClassError{wgetdoc}{The main title you specified is empty}{}
        \fi

        % Custom horizontale rule only local to this environment
        \newcommand{\@wgetdoc@title@hrule}{\rule{\linewidth}{1mm}}

        \if@wgetdoc@title@ownpage
            \begin{titlepage}
                \begin{center}

                    \@wgetdoc@title@hrule%
                    \vspace{0.4cm}

                    {\Huge\textbf{\@wgetdoc@title@maintitle}\par}%

                    \vspace{0.4cm}%
                    \@wgetdoc@title@hrule

                    \@ifundefined{@wgetdoc@title@subtitle}{}{
                        \vspace{1.5cm}
                        {\Large{\@wgetdoc@title@subtitle}\par}%
                    }

                    \@ifundefined{@wgetdoc@title@author}{}{
                        \vspace*{\fill}
                        {\emph{\GetTranslation{author}: \@wgetdoc@title@author}\par}%
                    }

                \end{center}
            \end{titlepage}%
        \else
            \begin{center}
                {\huge\textbf{\@wgetdoc@title@maintitle}\par}
                \@ifundefined{@wgetdoc@title@subtitle}{}{
                    {\large{\@wgetdoc@title@subtitle}\par}%
                }
            \end{center}
            \@ifundefined{@wgetdoc@title@author}{}{
                {\emph{\GetTranslation{author}: \@wgetdoc@title@author}\par}%
            }
            \@wgetdoc@title@hrule%
        \fi

    }{
        \IfFileExists{\@wgetdoc@title@filename}{%
            \includepdf[pages={1}]{\@wgetdoc@title@filename}%
            \ClassInfo{wgetdoc}{\@wgetdoc@title@filename has been used as title page. Any other argument have been discarded.}{}
        }{%
            \ClassError{wgetdoc}{You specified \@wgetdoc@title@filename as filename for the page title, but it could not be found.}{}
        }
    }
}

\makeatother

\begin{document}

\title[maintitle=hello world, ownpage, subtitle=hello world]

Hello world

\end{document}

As soon I remove my formatting and type

\title[maintitle=hello world, ownpage, subtitle=hello world]

instead of

\title[maintitle=hello world, ownpage, subtitle=hello \textsc{world}]

This is working. Could anyone explain to me why estore in is not working as expected (expanding the value before assigning it). This was working properly with xkeyval.

The error I get when I try to compile (using xelatex):

! Use of \\title doesn't match its definition.
\text@command #1->\def \reserved@a {
                                    #1}\ifx \reserved@a \@empty \let \check@...
l.88 ...d, ownpage, subtitle=hello \textsc{world}]

?
3
  • \textsc (and many other text formatting macros) is unexpandable. That's causing the problem
    – percusse
    Aug 15, 2016 at 18:10
  • .estore breaks \\; I see no need for it; why not simply .store?
    – egreg
    Aug 15, 2016 at 18:14
  • @egreg Thanks that did the trick. Actually I was fearing that statements like \title[maintitle=my title, subtitle=\textsc{sub}, author=First \textsc{Last name} \href{mailto:me@example.org}{\nolinkurl{<me@example.org>}},ownpage=true]] would not be expanded. But after deeper tests it appears they are. Some missing packages on my side.
    – wget
    Aug 15, 2016 at 18:26

3 Answers 3

4

The .estore in handler is for cases when the value can depend on a macro that's likely to receive different values between the setting and the usage of the created macro. Such macros should be safe for full expansion.

Indeed, one has to be aware of the fact that .estore in uses \edef and several typesetting macros don't survive it: \textsc is one of them, together with all font selection macros.

With maintitle/.store in=\@wgetdoc@title@maintitle, when you do

maintitle=Hello world,

you just perform

\def\@wgetdoc@title@maintitle{Hello world}

and you need no expansion; when \@wgetdoc@title@maintitle is used, it will expand to Hello world.

It would be good if pgfkeys provided also a .protectedestore in handler, at least in a LaTeX context; alas, there is nothing like this and you wouldn't need it anyway.


I'd avoid all those blank lines in the code and protect end-of-lines more carefully.

2
  • Yes. Your explanation sounds completely logical to me. So even, if there wasn't anything expandable as value, .estore in shouldn't have in all cases worked as using edef with a command having a value like textscis not allowed. This is not due to an hypothetic bug in store inlike mentioned by @percusse.
    – wget
    Aug 15, 2016 at 20:11
  • 1
    @wget I don't know about the bug in .estore in. For the title, you're just storing the tokens, not typesetting it: it will be typeset later, when the title is processed.
    – egreg
    Aug 15, 2016 at 20:18
3

\textsc (and many other text formatting macros) is unexpandable and causes to be processed in time which is often referred to early expansion. That's causing the problem.

If you need an expansion before the macro storing, you can use the /.expand once,/.expand twice and /.expanded handlers instead and use store in.

Also there is a bug report waiting to be fixed about /.estore in

6
  • Unfortunately if I was using that solution with .expanded, I wouldn't be able to store the variable in a new command like .store in does do it for me :-/
    – wget
    Aug 15, 2016 at 18:27
  • @wget Hmm not sure I understood but store in is safer, the safest is to save the tokens.
    – percusse
    Aug 15, 2016 at 18:28
  • Corrected my comment.
    – wget
    Aug 15, 2016 at 18:31
  • @wget Still why can't you save it ? If there was something like subtitle=\mynonexpandedmacro you can use it at the correct place so TeX would expand it. You can also save things to keys as tokens instead of saving them to macros and use \pgfkeysvalueof too. So I guess I couldn't understand the actual problem
    – percusse
    Aug 15, 2016 at 18:34
  • 1
    @wget They are not expandable. They will be processed whereever they are called so you have to delay it until the last moment when the document is typeset otherwise you will get errors.
    – percusse
    Aug 15, 2016 at 19:06
1

Based on @egreg's answer.

So to solve the issue, I just had to use .store in instead of .estore in. This is really weird as the main purpose of the .estore in command is just to make sure things are expanded properly (cf. the pgfkeys documentation). But it appears in my use case that \url or \textsc are expanded properly even without the need to use .estore in.

If someone has a comment to make to explain why.

1
  • 1
    try \edef\mymacro{\textsc{stuff}} which is what /.estore in does.
    – percusse
    Aug 15, 2016 at 19:05

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.