# Choice keys and exception handling

Recently, I switched a self-written "bundle package" from using xkeyval to keyreader. One reason for this, beside the backward compatibility, was that the definition of keys is more convenient in keyreader, especially for choicekeys. One thing that is missing tough is the variant \define@choicekey+, where faulty user input can be caught by a self-defined macro.
My first, and rather obvious, question is if there is a solution for this in keyreader.

However, the more I thought about the problem, the more I wished there was an exception mechanism in LaTeX. As far as I understand it (which admittedly is not so much), in pgfkeys (and maybe ltxkeys?) there exists something like that when you define handlers for keys in the /error/ tree.

So apart from shoehorning code to fit pgfkeys paradigm, do approaches to exceptions in LaTeX exist?

-
Do you mean dealing with 'unknown' choices? – Joseph Wright Oct 7 '12 at 19:36
@JosephWright Yes. At least for the part with keyreader ;-) – Percival Ulysses Oct 7 '12 at 20:32
ltxkeys doesn't use pgfkeys-type of handlers. skeyval (version 1.0) does use handlers, while retaining xkeyval syntax for some of the commands. Well, I will try to answer your question about keyreader package. – Ahmed Musa Oct 8 '12 at 0:38

The plus form of choice key has the syntax

\define@choicekey+[<pref>]{<fam>}{<key>}[<bin>]{<nominations>}[<default>]{<f1>}{<f2>}


When the user input is found in <nominations>, <f1> will be executed, otherwise <f2> will be called. The command \krddefinekeys of keyreader package hardwires <f2> to \krd@keyvalerr because in most cases the user would usually enter an error message in <f2>. pgfkeys will call /errors/unknown choice value={<key>}{<value>} in this case, which is equivalent to \krd@keyvalerr.

<f1> and <f2> are called "functions" in the xkeyval package, and "callbacks" in the keyreader package.

When you specify the key type choice, the command \krddefinekeys automatically and always uses the star (*) and plus (+) variant of \define@choicekey internally. So the choice key align in

\krddefinekeys*[KV]{ebox}[mp@]{%
choice/align/center/
center.do=\let\mp@alignright\hfil\let\mp@alignleft\hfil,
right.do=\let\mp@alignright\hfill\let\mp@alignleft\relax,
left.do=\let\mp@alignright\relax\let\mp@alignleft\hfill,
justified.do=\let\mp@alignright\relax\let\mp@alignleft\relax
}


is equivalent to the following code. This is what is executed internally in defining the key align.

\define@choicekey*+[KV]{ebox}[mp@]{align}[\krduserinput\krdorder]{%
center,right,left,justified
}[{center}]{%
\krd@executealt{#1}{<f1>}%
}{%
\krd@keyvalerr
}


The macro \krd@keyvalerr is defined as

\protected\def\krd@keyvalerr{%
\krd@getinnoval
\@latex@error{Erroneous value '\krd@ival' \MessageBreak for key or
option '\XKV@tkey'}{Invalid value for key '\XKV@tkey'.}%
}


where \krd@ival is the "innocent value" of the key. It is computed by \krd@getinnoval and is normally of length 20 "innocent" characters at most. \krd@keyvalerr is perhaps the "exception handler" that you refer to. If you like, you can redefine it, but be careful.

The example file of keyreader package:

\documentclass{standalone}
\usepackage{xcolor}
\makeatletter
\krddefinekeys*[KV]{ebox}[mp@]{%
bool/frame/true;
cmd/framecolor/black;
cmd/framesize/.4pt;
cmd/boxsize/.1\columnwidth;
choice/align/center/
center.do=\let\mp@alignright\hfil\let\mp@alignleft\hfil,
right.do=\let\mp@alignright\hfill\let\mp@alignleft\relax,
left.do=\let\mp@alignright\relax\let\mp@alignleft\hfill,
justified.do=\let\mp@alignright\relax\let\mp@alignleft\relax
;
}
\savevaluekeys[KV]{ebox}{frame,framecolor,framesize}
\krdpresetkeys[KV]{ebox}{%
}
\krdpostsetkeys[KV]{ebox}{%
}
\newcommand*\ebox[2][]{%
\krdsetkeys[KV]{ebox}{#1}%
\begingroup
\ifmp@frame
\fboxrule=\dimexpr\mp@framesize\relax
\else
\fboxrule=0pt
\fi
\else
\fi
\setbox0=\hbox{%
\hbox to\mp@boxsize{%
\mp@alignright #2\mp@alignleft
}%
}%
}%
\rule[-\dp0]{\wd0}{\the\dimexpr\ht0+\dp0\relax}%
\endgroup
}
\makeatother

\begin{document}
\ebox[framecolor=magenta,boxsize=2cm,align=right]{ebox2}
\end{document}


I am submitting version 0.5 of keyreader to CTAN. The syntax for \krddefinekeys is extended to meet your need:

\krddefinekeys[<pref>]{<fam>}[<mp>]{
ord/<key>/<dft>/<f1>;
cmd/<key>/<dft>/<f1>;
bool/<key>/<dft>/<f1>;
bool+/<key>/<dft>/<f1>/<f2>;
choice/<key>/<dft>/<nominations>/<f1>;
choice+/<key>/<dft>/<nominations>/<f1>/<f2>;
}


Here <f2> is, hopefully, the "handler" you wanted. This is now in the package but you won't find it in the documentation yet.

Example:

\krddefinekeys*[KV]{fam}[mp@]{%
ord/keya/default-a/\def\x##1{#1*##1};
bool/keyb/true/;
bool+/keyc/true/\def\valueaccepted{#1}/\@latexerr{Invalid value '#1' for keyc}\@ehd;
cmd/keyd/black;
choice/keye/blue/green,blue,red,cyan/\def\emptycallback{};
choice+/keyf/center/
center.do=\let\mp@alignright\hfil\let\mp@alignleft\hfil,
right.do=\let\mp@alignright\hfill\let\mp@alignleft\relax,
left.do=\let\mp@alignright\relax\let\mp@alignleft\hfill,
justified.do=\let\mp@alignright\relax\let\mp@alignleft\relax
//
\let\mp@alignright\hfil\let\mp@alignleft\hfil
\@@warning{Invalid value for keyf; 'center' assumed}
;
}

-
I still did not read keyreaders code, but I have a feeling that \krd@keyvalerr is not only used by keyreaders choicekeys. Since I use \krdProcessOptions to set the keys, it seems that there is no easy way to define an individual Catch for my choice key; some kind of switch statement on \XKV@tkey in \krd@keyvalerr would be necessary; this is uncomfortable (but would also be needed in a handler for pgfkeys /error tree?). Putting that global macro in the else part of xkeyval +-variant just takes away a great Catch variant. BTW: What do the callbacks of choice keys do? – Percival Ulysses Oct 9 '12 at 12:37
What you're suggesting is in effect a key type choice+. That will allow the user to specify the error for each choice key. That is possible but to what end? – Ahmed Musa Oct 9 '12 at 13:21
Why not? The programmer may fall back to a standard choice for the value of the key and only throw a warning if the user supplied a value not defined in the choice key. I think there are many applications that neither you nor me think about, but I want just do that. My point is that it is possible in xkeyval, but not in keyreader, and I for one miss it. – Percival Ulysses Oct 9 '12 at 14:33
OK, that and more will be provided in the next release of keyreader package. – Ahmed Musa Oct 9 '12 at 15:40
All right, very nice :-) Thank you. – Percival Ulysses Oct 9 '12 at 15:59