1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
|
\documentclass{article}
\usepackage[scaled=0.9]{helvet}
\usepackage{lipsum,parskip,xspace}
\usepackage{fancyvrb}
\usepackage{xcolor}
\usepackage{multicol}
\usepackage{hyperref}
\usepackage[parser=;,macroprefix=mp@,keyprefix=KV,
keyfamily=myfamily]{keyreader}
\makeatletter
\newcommand*\email[1]{\href{mailto:#1}{#1}}
\skip\footins20pt\relax
\xglobal\definecolorset{rgb}{x}{1}{green,0.00,0.59,0.00;%
teal,0.00,0.82,0.82;magenta,0.50,0.00,1.00;purple,0.50,0.00,0.25}
\def\eg{\kr@ifnextchar.{e.g}{e.g.}\xspace}
\def\ie{\kr@ifnextchar.{i.e}{i.e.}\xspace}
\def\etc{\kr@ifnextchar.{etc}{etc.}\xspace}
\date{\textcolor{purple}{\today}\vadjust{\kern0ex}}
\newcommand*\krsty[1]{\textcolor{xgreen1}{\texttt{#1}}\xspace}
\newcommand*\krcmd[1]{\textcolor{xteal1}{\texttt{\@backslashchar#1}}\xspace}
\newcommand*\krcs[1]{\textcolor{xteal1}{\texttt{\string#1}}\xspace}
\hypersetup{colorlinks=true,linkcolor=red,pdfpagemode=UseThumbs,
implicit=true,breaklinks=true,pagebackref=true,backref=true,
bookmarks=true,bookmarksnumbered=true,hyperfootnotes=true,debug=true,
naturalnames=false,citecolor=purple,pdfview=FitH,pdfstartview=FitH}
\def\krvlabel{\textcolor{green}{\fboxrule1pt\fcolorbox{red}{gray!45}{\hspace{1cm}}}}
\CustomVerbatimEnvironment{krverbatim}{Verbatim}{numbers=left,
label={\krvlabel},labelposition=topline,numberblanklines=false, firstnumber=last,frame=single,rulecolor=\color{xmagenta1},framerule=1pt,
framesep=7pt,formatcom=\color{blue},xrightmargin=0pc,commandchars=\|\(\),
commentchar=&}
\begin{document}
\DefineShortVerb{\+}
\title{The \texttt{\color{blue}keyreader} Package\footnote{Version 0.1.}}
\author{Ahmed Musa\\\email{a.musa@rocketmail.com}}
\maketitle
\thispagestyle{empty}
\leavevmode\textcolor{blue}{\rule[0ex]{\hsize}{2pt}}
\columnseprule0.5pt\premulticols2cm\relax
\begin{multicols}{2}
\small\tableofcontents\normalsize
\end{multicols}
\vspace*{-.5cm}
\leavevmode\textcolor{blue}{\rule[0ex]{\hsize}{2pt}}
\section{Motivation}
The elaborate and powerful \krsty{xkeyval} package introduced \krcmd{define@cmdkeys} and
\krcmd{define@boolkeys}, which permit the setting of multiple command keys and
boolean keys, but in each category those keys must have the same default value
and no key macro/function. This package seeks to remove these restrictions,
so that multiple keys of all categories (ordinary keys, command keys, boolean
keys, and choice keys) can be set at one go and those keys can have different
default values and functions. This greatly minimizes tokens, as hundreds of keys
can, in principle, be issued simultaneously by one command.
Also, the \krsty{xkeyval} package doesn't have the notion of complementary keys,
which can be handy in the case of boolean keys. The present package introduces
this concept and additionally permits the submission of individual/different
key macros to the complementary keys.
\section{Usage}
The package can be loaded in style files by
\begin{krverbatim}
\RequirePackage[options]{keyreader}
\end{krverbatim}
and in document files via
\begin{krverbatim}
\usepackage[options]{keyreader}
\end{krverbatim}
where the options and their default values are
\begin{krverbatim}
parser=;, macroprefix=mp@, keyprefix=KV, keyfamily=myfamily.
\end{krverbatim}
The \krsty{parser} is the separator between the keys in the key list to be defined in one go (see examples in section~\ref{sec:examples}). All these options can be set dynamically by using the \krcmd{krsetup} macro:
\begin{krverbatim}
\krsetup{parser=;,macroprefix=mp@,keyprefix=KV,
keyfamily=myfamily}.
\end{krverbatim}
The main user interface is the \krcmd{define@keylist} macro, whose syntax is
\begin{krverbatim}
\define@keylist{<key type/id>, <key>, <key value>,
<key macro/function>; <another set of key specifiers>; etc}
\end{krverbatim}
There are four key types: 1 (ordinary key), 2 (command key), 3 (boolean key),
4 (choice key). The key and its attributes are separated by commas; they constitute one \krsty{object}. The objects are separated by the \krsty{parser}, which is the semicolon in the above example.
If the key list is available in a macro, say,
\begin{krverbatim}
\def\keylist{<key type/id>, <key>, <key value>,
<key macro/function>; <another set of key specifiers>; etc},
\end{krverbatim}
then the keys can be defined by
\begin{krverbatim}
\cmddefine@keylist\keylist.
\end{krverbatim}
\krcmd{cmddefine@keylist} takes a macro as argument, while \krcmd{define@keylist} accepts a key list.
The \krcmd{kr@altlist} macro is needed for choice keys; it lists the alternate
admissible values for a choice key and thus can't be empty when a choice key
is being defined or set. It has to be defined or redefined each time a choice
key is being defined, if its contents (ie, those of \krcmd{kr@altlist}) change from
one choice key to the next one being defined. This, unfortunately, implies the restriction that no two choice keys can appear in one \krcmd{define@keylist} statement. This restriction can be easily lifted but at the cost of some complication and extra requirement for the package user. So far this hasn't been a severe limitation (to me, anyway).
\section{Examples}
\label{sec:examples}
Suppose we wish to define a set of keys \krsty{\{color,angle,scale,align\}}. The keys \krsty{color}, \krsty{angle} and \krsty{scale} will de defined using command keys, while the key \krsty{align} will be defined by choice keys. Assume that the \krsty{align} key can only assume the values \krsty{\{center,right,left,justified\}}, where the first three values would further imply \krcmd{centering}, \krcmd{flushright}, and \krcmd{flushleft}, respectively. Moreover, we assume that the key \krsty{scale} will be associated with a macro called \krcmd{mydo}, where \krcmd{do} is assumed defined elsewhere. The keys \krsty{color} and \krsty{angle} aren't associated with macros. Then we can go:
\begin{krverbatim}
\def\kr@altlist{center,right,left,justified}
\def\f@align{%
\ifcase\kr@nr\relax
\def\kr@align{\centering}%
\or
\def\kr@align{\flushright}%
\or
\def\kr@align{\flushleft}%
\or
\let\kr@align\relax\fi
}
\define@keylist{2,color,gray!25,;2,angle,45,;
2,scale,1,\def\mydo##1{\do ##1};4,align,center,\f@align;
|color(red)\stopread|color(blue);3,mybool,true,}.
\end{krverbatim}
The \krcmd{kr@nr} macro is a bin parameter defined by the keyreader package in accordance with the instructions in the \krsty{xkeyval} guide. It refreshes with the choice key. See the \krsty{xkeyval} guide for further details.
Instead of defining the macro \krcmd{f@align} before hand, we can submit its replacement text directly to the macro \krcmd{define@keylist}, but, because \krcmd{f@align} contains a conditional, some care is needed in doing so (see section~\ref{sec:conditionals}). Once the key \krsty{align} has been defined, the macro \krcmd{f@align} can be reused---perhaps to define other keys---even before the key \krsty{align} is set. This is because it isn't \krcmd{f@align} that is used in defining the key \krsty{align} but its ``meaning'' (\ie, the meaning of \krcmd{f@align}). In this way, the user can economize on tokens. The same applies to all the macros that may be used in defining keys.
Note the \krcmd{stopread} command inserted above. Because of it, the key \krsty{mybool} will not be read and defined; the rest (\ie, \krsty{color}, \krsty{angle}, \krsty{scale} and \krsty{align}) will be read and defined. All the entries for \krsty{mybool} will instead be saved in the macro \krcmd{kr@remainder}.
Hundreds of keys can be defined efficiently in this way, using very few tokens.
As another example, we consider the following page setup keys:
\begin{krverbatim}
\def\kr@altlist{center,right,left,justified} % reused
\define@keylist{%
3,boolvar,true,;1,paperheight,\paperheight,;
1,paperwidth,\paperwidth,\f@paperwidth;
2,textheight,\textheight,\f@textheight;
2,textwidth,\textwidth,\f@textwidth;
1,evensidemargin,\evensidemargin,;
4,align,center,\f@align;
2,testdim,2cm,\long\def\f@testdim##1{A test dimension ##1
\par\bigskip}%
}
\end{krverbatim}
which have the following trivial key macros:
\begin{krverbatim}
\def\f@textwidth{\AtBeginDocument{\wlog{`textwidth' %
is \mp@textwidth}}}
\def\f@textheight{%
\ifx\@empty\mp@textheight
\wlog{`textheight' value empty}%
\else
\wlog{`textheight' value not empty}%
\fi
}
\def\f@paperwidth{\wlog{`paperwidth' was defined as %
ordinary key.}}
\newcommand\f@align{%
\ifcase\kr@nr\relax
\def\mp@align{\centering}%
\or
\def\mp@align{\flushright}%
\or
\def\mp@align{\flushleft}%
\or
\let\mp@align\relax
\fi
}
\end{krverbatim}
Again, once the keys have been defined, these macros can be reused.
Since the keys have been defined, they can now be set. In the following, we set only two of the keys:
\begin{krverbatim}
\setkeys[KV]{myfamily}{align=right,testdim=3cm}
\end{krverbatim}
The macro \krcmd{mp@align} holds the value \krcmd{flushright}, while
\begin{krverbatim}
\KV@myfamily@testdim
\end{krverbatim}
holds the macros:
\begin{krverbatim}
\def\mp@testdim{#1}
\long\def\f@testdim##1{A test dimension##1\par\bigskip},
\end{krverbatim}
where \krsty{\#1} is the value submitted for the key \krsty{testdim}.
Try \krcmd{show\string\mp@align}, \krcmd{show\string\KV@myfamily@testdim}, and \krcmd{show\string\f@testdim} to confirm the above assertions.
The rest of the defined keys can now be set as follows:
\begin{krverbatim}
\setkeys[KV]{myfamily}{boolvar=true,paperheight,paperwidth,
textheight,textwidth=6cm}
\end{krverbatim}
Try \krcmd{show\string\ifmp@boolvar} to confirm that \krsty{boolvar} is now \krsty{true}; it is originally set as \krsty{false}. The macro \krcmd{KV@myfamily@paperwidth} holds the function \krcmd{f@paperwidth}; \krcmd{mp@textheight} holds the value submitted to key \krsty{textheight} at any instance of \krcmd{setkeys}. By the above \krcmd{setkeys}, only the default values of \krsty{paperheight}, \krsty{paperwidth}, and \krsty{textheight} are presently available.
\subsection[Demonstrating an effect]%
{Demonstrating the effect of limiting {\tt\textbackslash textwidth}}
After defining and setting the keys above, the following tokens can be used in a source file to demonstrate the effect of setting the page setup keys shown above:
\begin{krverbatim}
\begin{center}
\begin{minipage}{\mp@textwidth}
\lipsum[1] % from the lipsum package
\end{minipage}
\end{center}
\lipsum[1]
\end{krverbatim}
\section{Complementary boolean keys}
The syntax of complementary boolean keys is
\begin{krverbatim}
\define@comp@boolkeys[<key-prefix>]{<family>}[<macro-prefix]
{<primary boolean>}[<default value for primary boolean>]
{<secondary boolean>}{<func for primary boolean>}
{<func for secondary boolean>}.
\end{krverbatim}
When the user doesn't supply the \krsty{key-prefix} and/or \krsty{macro-prefix}, the package will use \krsty{KV} and \krsty{mp@}, respectively. When one boolean (primary or secondary) is true, the other is
automatically set false. Infinite loops, which are possible in back-linked key settings, are avoided in the \krsty{keyreader} package.
As an example, we define below two complementary keys \krsty{draft} and \krsty{final} with different key macros:
\begin{krverbatim}
\define@comp@boolkeys[KV]{myfamily}[kr@]{draft}[true]{final}%
{%
\def\gobble##1{}%
}{%
\def\notgobble##1{##1}%
}.
\end{krverbatim}
The key prefix (default \krsty{KV}), macro prefix (default \krsty{mp@}), and key macros (no default) can be empty:
\begin{krverbatim}
\define@comp@boolkeys{myfamily}{draft}[true]{final}{}{}.
\end{krverbatim}
The defined complementary keys \krsty{draft} and \krsty{final} can now be set as follows:
\begin{krverbatim}
\setkeys[KV]{myfamily}{draft=true}
\setkeys[KV]{myfamily}{final=true}
\end{krverbatim}
The second statement above reverses the boolean \krsty{draft} to \krsty{false}, which had been set in the first statement to \krsty{true}. There is no meaning to the following:
\begin{krverbatim}
\setkeys[KV]{myfamily}{draft=true,final=true}.
\end{krverbatim}
As an exercise, in a document file, after defining and setting the above keys, one can issue the command \krcmd{krsetup\{draft=true\}} and do
\begin{krverbatim}
\show\ifkr@draft \show\ifkr@final \show\gobble
\show\KV@myfamily@draft.
\end{krverbatim}
These statements assume the macro prefix to be \krsty{kr@}. Next, we may set
\begin{krverbatim}
\krsetup{final=true}
\end{krverbatim}
and do
\begin{krverbatim}
\show\ifkr@final \show\ifkr@draft \show\notgobble.
\end{krverbatim}
\section{Input error}
Both boolean and choice keys issue error messages if the input is not valid, \ie, not in the list of admissible values. The default input error is defined by \krcmd{kr@inputerr} macro to be
\begin{krverbatim}
<Erroneous value `#1' for key `#2'>.
\end{krverbatim}
\krcmd{kr@inputerr} can be redefined by the user. It takes two arguments (\ie, value and key).
\section{Conditionals in key macros}
\label{sec:conditionals}
The \TeX{} conditional primitives \krcmd{if} and \krcmd{fi} cannot appear in the key macro when \krcmd{define@keylist} is being invoked. The reason can be traced to the discussion on page~211 of the \TeX Book. Key macros/functions involving conditional operations such as
\begin{krverbatim}
\ifmp@boolone \do \fi
\end{krverbatim}
can be submitted to \krcmd{define@keylist} via macros, as seen above. We give more examples below.
Suppose we want to submit the following:
\begin{krverbatim}
\define@keylist{3,boolone,true,\ifmp@boolone \do \fi}.
\end{krverbatim}
The presence of \krcmd{if...} and \krcmd{fi} in the argument will trigger an error when \TeX{} is scanning or skipping tokens (see the \TeX Book). Neither \krcmd{protect} nor \krcmd{noexpand} is helpful here. One solution is to first define
\begin{krverbatim}
\def\f@boolone{\ifmp@boolone \do \fi}
\end{krverbatim}
and then do
\begin{krverbatim}
\define@keylist{3,boolone,true,\f@boolone},
\end{krverbatim}
which will execute \krcmd{f@boolone} when the key \krsty{boolone} is set. Once the key \krsty{boolone} has been defined by the above statement, the function \krcmd{f@boolone} may be redefined and reused many times, any time, even before the setting of the key \krsty{boolone}. It isn't the function \krcmd{f@boolone} that is used in defining the key \krsty{boolone}, but the meaning of \krcmd{f@boolone}.
As another example, we may do
\begin{krverbatim}
\def\f@bool{\ifmp@bool\def\do####1{%
\def####1########1{\expandafter\expandafter\expandafter\in@
\expandafter\expandafter\expandafter{\expandafter####1
\expandafter}\expandafter{########1}}}\fi}
\define@keylist{3,bool,true,\f@bool}.
\end{krverbatim}
``Toggles,'' introduced in the \krsty{etoolbox} package, can also be used to circumvent the problem of matching \krcmd{if} and \krcmd{fi} in difficult circumstances, since toggles aren't \TeX\ primitives, but the \krsty{xkeyval} doesn't as yet have a mechanism for defining and setting toggle keys. However, this shouldn't be difficult to implement in the future.
\section{Disabling keys}
The \krsty{keyreader} package has modified the definition of \krcmd{disable@keys} from the \krsty{xkeyval} package to allow for bespoke warnings and error messages. The new command is \krcmd{krdisable@keys}; the use syntax remains the same as that of \krcmd{disable@keys}:
\begin{krverbatim}
\krdisable@keys[<key prefix>]{<key family>}{<comma %
separated list of keys to disable>}.
\end{krverbatim}
Any attempt to subsequently set a disabled key will prompt the following error message. (The \krsty{xkeyval} package issues a warning in this case.) The error message can be modified by the user, but the ``names'' \krcmd{disabledkeyerr} and \krcmd{disabledkey} should be retained.
\begin{krverbatim}
\def\disabledkeyerr{%
\PackageError{keyreader}{%
Key `\disabledkey' has been disabled.\MessageBreak
You can't set or reset it at this late stage.\MessageBreak
You should have set it earlier in the\MessageBreak
\string\documentclass\space or \string\usepackage
}{\@ehc}%
}
\end{krverbatim}
If the user attempts to disable an undefined key, the \krsty{xkeyval} package issues a fatal error; the \krsty{keyreader} package, on the other hand, issues a warning in the transcript .log file, since the situation isn't fatal to the outcome.
\end{document}
%%% End of file keyreader-guide.tex %%%
|