1

I find that the value of a key defined by \pgfkeys inside an environment can not be invoked outside this environment.

In the following example, I want to typeset the value of the key aaa outside the environment minipage and fail.

How to make this kind of keys be "seen" outside environment?

Example:

\documentclass{article}
\usepackage{tikz}
\begin{document}

\begin{minipage}{1.0\linewidth} \pgfkeys{aaa/.initial=aaa,bbb/.initial=bbb} Inside minipage, the value of the key "aaa" is \pgfkeysvalueof{/aaa} \end{minipage} Outside minipage, the value of the key "aaa" is |\pgfkeysvalueof{/aaa}|

\end{document}

lyl
  • 2,727
  • 2
    This is due to scoping. You will get the same effect with using \def inside the minipage. – Jasper Habicht Aug 12 '22 at 08:28
  • Is this correct for all environment? I mean scoping. – lyl Aug 12 '22 at 08:31
  • In general, yes, since virually all environments use scoping. But scoping is a very basic thing: You will aready get an error if you try {\def\hello{hello}} \hello. In your case, you would need to assign the key gloablly (or outside of the scope). See: https://tex.stackexchange.com/q/15204/47927 – Jasper Habicht Aug 12 '22 at 08:37
  • 2
    @lyl Yes, all() LaTeX environments form a group. ( document avoids a group for technical reasons, but as the LaTeX run ends with \end{document} is this not really an issue.) – Joseph Wright Aug 12 '22 at 08:53
  • Currently pgfkeys has no provisions to set keys globally. It is recommended to instead move the keys definition to the global scope (usually the document preamble). – Henri Menke Aug 12 '22 at 10:12
  • I suggest either the "hack" adding global handlers like in the answer by Qrrbrbirlbel, or use another key=value implementation that supports global assignments out of the box. – Skillmon Aug 12 '22 at 11:18

2 Answers2

3

Since the other answer and comments explain why your code behaves the way it does, here's a .ginitial handler that is global.

That means that both the initialization aaa/.ginitial = aaa as well as just assigning a new value via aaa = AAA will be global.

However, the handlers .add, .prefix, .append, .get and .link will not change the value globally.
(We'll need .gadd, .gprefix, … for that.)

In the code below, the key /bbb remains local.

Code

\documentclass{article}
\usepackage{tikz}

\makeatletter \long\def\pgfkeysgdef#1#2{% \long\def\pgfkeys@temp##1\pgfeov{#2}% \pgfkeysglet{#1/.@cmd}{\pgfkeys@temp}% \pgfkeyssetgvalue{#1/.@body}{#2}% } \long\def\pgfkeysglet#1#2{% \expandafter\global\expandafter\let\csname pgfk@#1\endcsname#2% } \long\def\pgfkeyssetgvalue#1#2{% \pgfkeys@temptoks{#2}\expandafter\xdef\csname pgfk@#1\endcsname{\the\pgfkeys@temptoks}% } \pgfkeys{ /handlers/.ginitial/.code=% \edef\pgfkeys@temp{% \pgfkeysgdef is basically /.gcode \noexpand\pgfkeysgdef{\pgfkeyscurrentpath}% {\noexpand\pgfkeyssetgvalue{\pgfkeyscurrentpath}{####1}}}% \pgfkeys@temp \pgfkeyssetgvalue{\pgfkeyscurrentpath}{#1}% } \makeatother \begin{document}

\noindent \begin{minipage}{1.0\linewidth} \pgfkeys{aaa/.ginitial = aaa, bbb/.initial = bbb, aaa = AAA} Inside minipage, the values of the keys --/aaa--/bbb-- are --\pgfkeysvalueof{/aaa}--\pgfkeysvalueof{/bbb}-- \end{minipage} Outside minipage, the values of the key --/aaa--/bbb-- are --\pgfkeysvalueof{/aaa}--\pgfkeysvalueof{/bbb}-- \end{document}

Output

enter image description here

Qrrbrbirlbel
  • 119,821
  • That said, the point and power of PGFkeys is to only have keys/styles be local. Maybe there's a better solution if we'd know the real world application. – Qrrbrbirlbel Aug 12 '22 at 15:37
1

Due to scoping, the keys you set inside the minipage are only defined inside this environment. Therefore, you would need to define the key outside of the environment or define it gobally somehow.

You could apply the approach in this answer and create a global version of the \pgfkeys macro. However, this approach is probably risky because everything \pgfkeys does internally will be global. This may lead to unintended results in certain cases and break other code (thanks to Skillmon and David Carlisle for pointing to this).

For very simple assignments, you could maybe also use \global\pgfkeyslet, but using this approach, things like .initial would not be applicable. Also, the same warning as above applies here. So, do not use this if you plan to have others use your code!

I'd recommend, therefore, to restructure the logic of your document and define the keys outside of the environment.

\documentclass{article}
\usepackage{tikz}

%%% not recoomended! \newcommand\gpgfkeys[1]{% \begingroup% \globaldefs=1\relax% \pgfkeys{#1}% \endgroup% } %%%

\begin{document}

\pgfkeys{aaa/.initial=aaa}

\noindent \begin{minipage}{1.0\linewidth}

\def\mybbbkey{bbb} %%% \global\pgfkeyslet{/bbb}{\mybbbkey} %%% %%% \gpgfkeys{ccc/.initial=ccc} %%% not recommended!

Inside minipage, the value of the key "aaa" is \pgfkeysvalueof{/aaa} \ Inside minipage, the value of the key "aaa" is \pgfkeysvalueof{/bbb} \ Inside minipage, the value of the key "ccc" is \pgfkeysvalueof{/ccc} \end{minipage}

\bigskip

\noindent Outside minipage, the value of the key "aaa" is ---\pgfkeysvalueof{/aaa}--- \ Outside minipage, the value of the key "bbb" is ---\pgfkeysvalueof{/bbb}--- \ Outside minipage, the value of the key "ccc" is ---\pgfkeysvalueof{/ccc}---

\end{document}

enter image description here

  • 2
    I'd not recommend switching on \globaldefs on code you haven't completely written yourself and have not absolute control over! – Skillmon Aug 12 '22 at 09:02
  • @Skillmon Wouldn't your concerns then also apply to the linked answer? – Jasper Habicht Aug 12 '22 at 09:16
  • 2
    pgfkeys makes hundreds of internal definitions parsing the structure and this makes all of them global, it might work in some cases but only accidentally, and it may break arbitrary other code with global settings to interal registers. – David Carlisle Aug 12 '22 at 09:23
  • 1
    Yes comments apply to that answer too – David Carlisle Aug 12 '22 at 09:25
  • @DavidCarlisle Would \global\pgfkeyslet be a better way then? – Jasper Habicht Aug 12 '22 at 09:25
  • that would make the top level macro holding the key global but if the key has any additional structure or properties such as .initial, they would still be local – David Carlisle Aug 12 '22 at 09:29
  • @DavidCarlisle Ok, thank you! I updated my answer to include a warning. – Jasper Habicht Aug 12 '22 at 09:52
  • 1
    I'd have made the warning stronger, "do not use this in production" for example. \global\pgfkeyslet is like \global\newcommand if it ever does what you expect either your are very lucky or you know every line of code executed and your expectations are acurate – David Carlisle Aug 12 '22 at 10:06