6

expl3 has defeated me again so I'm relying on the kindness of strangers again.

I think the underlying problem is more about splitting input rather than the file reading.

Context: I want to load the parameters to the geometry package's \geometry{} command from a file using expl3. I have tried at least 4 ways of reading the file. But however I load the file, the entire contents is being passed to \geometry{} as a single token / string / block / thing because the geometry package complains the entire thing top=2cm,bottom=2cm is not a valid key Package keyval Error: top=2cm,bottom=2cm undefined. Yet if I put \geometry{top=2cm,bottom=2cm} in the document then that is processed correctly.

I have seen this answer which splits key-value pairs but I need all the key-value pairs at once in the input stream not one at a time.

Minimal working examples

This works:

\documentclass{article}

\ExplSyntaxOn % Also works without expl3 syntax
\usepackage{geometry}
\geometry{top=2cm,bottom=2cm}
\ExplSyntaxOff

\begin{document}
Document content.
\end{document}

Minimal not working examples

(Not using the recommended expl3 naming conventions for brevity)

Token list

Token list fails resulting in Package keyval Error: top=2cm,bottom=2cm undefined.

\documentclass{article}

\ExplSyntaxOn
\tl_clear_new:N \geotoks_tl
\tl_set:Nn \geotoks_tl {top=2cm,bottom=2cm}
% Also fails with {top=2cm, bottom=2cm}

\usepackage{geometry}
\geometry{\geotoks_tl} % fail
% \geometry{\tl_use:N \geotoks_tl}  % fail
\ExplSyntaxOff

\begin{document}
Document content.
\end{document}

String

String fails resulting in Package keyval Error: top=2cm,bottom=2cm undefined.

\documentclass{article}

\ExplSyntaxOn

\str_clear_new:N \geotoks_str
\str_set:Nn \geotoks_str {top=2cm,bottom=2cm}
% Also fails with {top=2cm, bottom=2cm}

\usepackage{geometry}
\geometry{\geotoks_str} % fail
% \geometry{\str_use:N \geotoks_str} % fail
\ExplSyntaxOff

\begin{document}
Document content.
\end{document}

Clist

Clist fails resulting in Package keyval Error: top=2cm,bottom=2cm undefined.

\documentclass{article}

\usepackage{geometry}
\ExplSyntaxOn
\clist_clear_new:N \geotoks_clist
\clist_set:Nn \geotoks_clist {top=2cm, bottom=2cm}

\usepackage{geometry}
\geometry{\clist_use:Nn \geotoks_clist {,}}
% Also fails with
% \geometry{\clist_use:Nn \geotoks_clist {~}}
% though error message is `Package keyval Error: top=2cm bottom=2cm undefined.`
\ExplSyntaxOff

\begin{document}
Document content.
\end{document}

Seq

\documentclass{article}

\usepackage{geometry}
\ExplSyntaxOn
\clist_clear_new:N \geotoks_clist
\clist_set:Nn \geotoks_clist {top=2cm, bottom=2cm}
\seq_clear_new:N \geotoks_seq
\seq_set_from_clist:NN \geotoks_seq \geotoks_clist

\usepackage{geometry}
\geometry{\seq_use:Nn \geotoks_seq {,}}
% Also fails with {~} as the separator
\ExplSyntaxOff

\begin{document}
Document content.
\end{document}

I have also met the same fail with splitting into a sequence as described here.

File loading

I have met the same Package keyval Error: top=2cm,bottom=2cm undefined. fails by using the file loading methods in these answers:

In desperation I also tried \geometry{\file_input:n {geometryParams.txt}} which at least gave me a different error Missing \endcsname inserted. Same error with \geometry{\input{params.txt}} inside or outside ExplSyntax.

2
  • 3
    As \geometry doesn't expands its argument nothing that you do inside will help, you need something like \ExpandArgs{o}\geometry{\geotoks_str} Commented Sep 5, 2023 at 12:04
  • @Ulrike Fischer That works. Please make it an answer so I can accept. I don't think I've seen \ExpandArgs before.
    – Doc Octal
    Commented Sep 5, 2023 at 12:32

2 Answers 2

8

\geometry doesn't expand it argument, it wants a key list as argument, not a key list hidden in some command. So nothing what you do inside the argument will work. Assuming that your key list is in a simple command \mykeylist you can expand it from the outside. Either with the old

\expandafter\geometry\expandafter{\mykeylist}

or with the new LaTeX command \ExpandArgs:

\ExpandArgs{o}\geometry{\mykeylist}

Unrelated but you are not following the expl3 naming scheme. Variables should start with a prefix showing if they are a global or local variable, followed by the module name and then something showing their use.

So

\geotoks_str  -> \l_geotoks_keys_str
1
  • 1
    Thanks :) I promise I am following the naming scheme in my real code. I just couldn't be bothered with it for the question.
    – Doc Octal
    Commented Sep 5, 2023 at 12:52
6

From the question's title I guess you want to load the options from a file.

\begin{filecontents*}{\jobname.geo}
top=2cm,
bottom=2cm
left=2cm,a4paper
\end{filecontents*}

\documentclass{article}
\usepackage[showframe]{geometry}

\ExplSyntaxOn
\NewDocumentCommand{\geometryfromfile}{m}
 {
  \dococtal_geometry_fromfile:n { #1 }
 }

\ior_new:N \g_dococtal_geometry_file_ior
\clist_new:N \g_dococtal_geometry_options_clist

\cs_new_protected:Nn \dococtal_geometry_fromfile:n
 {
  \ior_open:Nn \g_dococtal_geometry_file_ior { #1 }
  \clist_gclear:N \g_dococtal_geometry_options_clist
  \ior_map_inline:Nn \g_dococtal_geometry_file_ior
   {
    \clist_gput_right:Nn \g_dococtal_geometry_options_clist { ##1 }
   }
  \exp_args:NV \geometry \g_dococtal_geometry_options_clist
 }

\ExplSyntaxOff

\geometryfromfile{\jobname.geo}

\begin{document}

Test

\end{document}

You see that the file is typed quite lazily, but the command above works without glitches, because we read the file line by line and \clist_gput_right:Nn does the rest. Indeed, the contents of the clist is

The comma list \g_dococtal_geometry_options_clist contains the items (without
outer braces):
>  {top=2cm}
>  {bottom=2cm}
>  {left=2cm}
>  {a4paper}.
2
  • Thanks @egreg this is neat. Is it more flexible / efficient / robust to input than the \file_get:nnNTF {filename} {} \token_list {\ExpandArgs{o}\geometry\token_list} {} I'm currently using? I had tried and failed with something similar to your answer. I was missing the \exp_args:NV and I had braces around the clist \geometry{\options_clist} which may be why it didn't work.
    – Doc Octal
    Commented Sep 5, 2023 at 13:25
  • 1
    @DocOctal With \file_get:nnnTF you can't be lazy in typing in your settings file.
    – egreg
    Commented Sep 5, 2023 at 13:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .