I've set up some pgfkeys keys and I'm trying to load the settings from an external file. The only way I know in LaTeX to load files is \input, but it seems to not be the right choice.

\begin{filecontents}{keys.def}
key = Hellò
\end{filecontents}

\documentclass{article}
\usepackage[utf8]{inputenc}

\usepackage{pgfkeys}

\pgfkeys{
/mykeys/key/.initial = {}
}

\pgfqkeys{/mykeys}{
\input{keys.def}
}

\begin{document}
Values: \pgfkeysvalueof{/mykeys/key}
\end{document}


This code fails to compile with awful messages about undefined control sequences.

What's the right way to give the contents of a file to \pgfkeys?

Note: I've included inputenc and an accented letter in the MWE because in the real use case, the keys will be localized strings and I need to be sure there are no encoding issues.

• Why can't you put the \pgfkeys{} in the file, too? – cfr Nov 30 '17 at 4:41
• Because the file is meant to be edited by third parties and its syntax should be simple with as few latex quirks as possible – gigabytes Nov 30 '17 at 4:51

Proof of concept using expl3. This reads the input file one bit at a time and feeds the bit the the key-setting function. Presumably, something similar is possible without expl3, but this method is straightforward.

\begin{filecontents}{keys.def}
key = Hellò
\end{filecontents}

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage{expl3}

\begin{document}
\ExplSyntaxOn
\ior_new:N \l_gigabytes_stream
\ior_open:Nn \l_gigabytes_stream { keys.def }
\ior_get:NN \l_gigabytes_stream \l_tmpa_tl
\keys_define:nn { gigabytes / mykeys }
{
key .tl_set:N = \l_gigabytes_mykeys_key_tl,
key .initial:n = ,
}
\ior_map_inline:Nn \l_gigabytes_stream
{
\keys_set:nn { gigabytes / mykeys } { #1 }
}
\ior_close:N \l_gigabytes_stream
\l_gigabytes_mykeys_key_tl
\ExplSyntaxOff
\end{document}


The result is unexciting but correct:

EDIT

Note that although it is clearly a bit mad, it is possible to use this to set PGF keys, should you so desire. For example, the following produces the same output as the code above.

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage{expl3,pgfkeys}

\begin{document}
\pgfkeys{
gigabytes pgf/mykeys/.cd,
key/.initial={},
}
\ExplSyntaxOn
\ior_new:N \l_gigabytes_stream
\ior_open:Nn \l_gigabytes_stream { keys.def }
\ior_map_inline:Nn \l_gigabytes_stream
{
\pgfkeys { gigabytes~pgf / mykeys/.cd, #1}
}
\ior_close:N \l_gigabytes_stream
\pgfkeysvalueof{gigabytes~pgf /mykeys / key}
\ExplSyntaxOff
\end{document}

• Nice, thank you! However, I specifically needed pgfkeys, not l3keys, because all the rest of the thing I’m writing uses it. Is this solution adaptable? So let me understand (I’m not used to expl3): the code is reading one character at the time? Anyway, do you know which is exactly the expansion issue that prevents the trivial code from working? – gigabytes Dec 3 '17 at 1:50
• @gigabytes It is reading one chunk at a time. It reads one or more lines until it has something with matching right and left curly brackets. Then it feeds that to the function (which here treats it as input to set keys). Then it does the next chunk (but here there is no next chunk). It is not really expansion - I shouldn't have said that. \input is not expandable, I don't think. I assume you can do what I did in TeX - it is just easier using expl3. – cfr Dec 3 '17 at 3:06
• @gigabytes Note that you could pass each chunk to pgf keys instead. At least, you should be able to. I'm not entirely certain what might happen to spaces. User input is usually fine, but I don't know with this .... – cfr Dec 3 '17 at 3:08
• @gigabytes See edit above. But I do mention it is a bit mad. – cfr Dec 3 '17 at 3:16
• I don’t see the madness in all of this, honestly 😅 – gigabytes Dec 3 '17 at 12:22