Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I am trying to use the xkeyval package to include key arguments in a new environment. It seems to work except for default values. Here's my best try so far:

\documentclass{article}

\usepackage{xkeyval}


\makeatletter
\define@key{Mystuff}{foo}[what]{\def\foo{#1}}
\define@key{Mystuff}{bar}[whatever]{\def\bar{#1}}
\savekeys{Mystuff}{foo,bar}
\makeatother

\newenvironment{myenv}[1][]%
{\setkeys{Mystuff}{#1}BEGIN \foo}
{END \bar}

\begin{document}

\begin{myenv}[bar=BAAAR]
Uh?
\end{myenv}

\end{document}

But this will cause LaTeX to complain about \foo being undefined:

! Undefined control sequence.
\\myenv [#1]->\setkeys {Mystuff}{#1}BEGIN \foo 

l.18 \begin{myenv}[bar=BAAAR]

And the output will be something like "BEGIN Uh? END BAAAR" (without the default "what" value to \foo).

What am I doing wrong there, and how can I change this example so the default value for \foo will be used?

share|improve this question
add comment

2 Answers 2

up vote 5 down vote accepted

The default value is used when you specify the key, but don't assign a value: \begin{myenv}[foo] will define \foo to what. Say

\newenvironment{myenv}[1][]%
{\setkeys{Mystuff}{foo,bar,#1}BEGIN \foo}
{END \bar}

so that the default values will be applied.

Or say

\define@key{Mystuff}{foo}{\def\foo{#1}}
\define@key{Mystuff}{bar}{\def\bar{#1}}

and

\newenvironment{myenv}[1][]%
{\setkeys{Mystuff}{foo=what,bar=whatever,#1}BEGIN \foo}
{END \bar}

A key is never evaluated if it's not specified in \setkeys.


Actually, as pointed out by Ulrike Fischer and Ahmed Musa, one can "preset" some keys, and this will be equivalent to specify them in the \setkeys list:

\define@key{Mystuff}[what]{foo}{\def\foo{#1}}
\define@key{Mystuff}[whatever]{bar}{\def\bar{#1}}
\presetkeys{Mystuff}{foo,bar}{}

What strategy to employ depends mostly on the applications. If you always need that foo and bar are set, then \presetkeys is more economical, as the assignment wouldn't be performed twice when the key is specified.

The \presetkeys, however, can go also in the definition of the environment, so the definition of your environment can be

\newenvironment{myenv}[1][]%
  {\presetkeys{foo,bar}{}%
   \setkeys{Mystuff}{#1}BEGIN \foo}
  {END \bar}

and this wouldn't influence other environments using the Mystuff keys.

share|improve this answer
    
Thanks a lot! It works (and I understnad the mechanism better now). –  Jay Jun 9 '12 at 12:28
2  
@egreg: In xkeyvals keys are evaluated by \setkeys even if they are not specified explicitly in the key list if you preset them with \presetkeys. –  Ulrike Fischer Jun 9 '12 at 12:49
    
@UlrikeFischer Good to know. I think that the two methods both have pros and cons: it all depends on the actual application. –  egreg Jun 9 '12 at 12:51
    
So, if I have a key family for which I'd like the defaults to be always the same, I can use \presetkeys, and if I want to be able to specify the defaults in each \newcommand or \newenvironment, I would use \setkeys with them in the new defined command, as @egreg showed. Sounds really good (very flexible)! :-) –  Jay Jun 9 '12 at 15:06
2  
\setkeys{Mystuff}{foo=what,bar=whatever,#1} will most likely result in setting the same keys twice: once by the hardwired foo=what,bar=whatever and again by #1. \presetkeys will not set from the preset list the keys whose values have been supplied by the user (in #1 in the above example). –  Ahmed Musa Jun 9 '12 at 20:43
show 2 more comments

\savekeys is the wrong command. What you want is

\presetkeys{Mystuff}{foo,bar}{}

The key foo will then be inserted at the start of the \setkeys list.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.