Commit | Line | Data |
---|---|---|
86f6a31e | 1 | % \begin{meta-comment} <general public licence> |
2 | %% | |
3 | %% at package -- support for `@' commands' | |
8bc5bdd2 | 4 | %% Copyright (c) 1995, 1996, 2002, 2020 Mark Wooding |
86f6a31e | 5 | %% |
3d509049 | 6 | %% This file is part of the `mdwtools' LaTeX package collection. |
86f6a31e | 7 | %% |
3d509049 MW |
8 | %% `mdwtools' is free software: you can redistribute it and/or modify it |
9 | %% under the terms of the GNU General Public License as published by the | |
10 | %% Free Software Foundation; either version 2 of the License, or (at your | |
11 | %% option) any later version. | |
12 | %% | |
13 | %% `mdwtools' is distributed in the hope that it will be useful, but | |
14 | %% WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | %% General Public License for more details. | |
86f6a31e | 17 | %% |
18 | %% You should have received a copy of the GNU General Public License | |
3d509049 MW |
19 | %% along with `mdwtools'. If not, write to the Free Software Foundation, |
20 | %% Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
86f6a31e | 21 | %% |
22 | % \end{meta-comment} | |
23 | % | |
24 | % \begin{meta-comment} <Package preamble> | |
25 | %<+package>\NeedsTeXFormat{LaTeX2e} | |
26 | %<+package>\ProvidesPackage{at} | |
af8af7eb | 27 | %<+package> [2020/09/06 1.14.0 @-command support] |
86f6a31e | 28 | % \end{meta-comment} |
29 | % | |
30 | % \CheckSum{355} | |
31 | %% \CharacterTable | |
32 | %% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z | |
33 | %% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z | |
34 | %% Digits \0\1\2\3\4\5\6\7\8\9 | |
35 | %% Exclamation \! Double quote \" Hash (number) \# | |
36 | %% Dollar \$ Percent \% Ampersand \& | |
37 | %% Acute accent \' Left paren \( Right paren \) | |
38 | %% Asterisk \* Plus \+ Comma \, | |
39 | %% Minus \- Point \. Solidus \/ | |
40 | %% Colon \: Semicolon \; Less than \< | |
41 | %% Equals \= Greater than \> Question mark \? | |
42 | %% Commercial at \@ Left bracket \[ Backslash \\ | |
43 | %% Right bracket \] Circumflex \^ Underscore \_ | |
44 | %% Grave accent \` Left brace \{ Vertical bar \| | |
45 | %% Right brace \} Tilde \~} | |
46 | %% | |
47 | % | |
48 | % \begin{meta-comment} <driver> | |
49 | % | |
50 | %<*driver> | |
51 | \input{mdwtools} | |
52 | \describespackage{at} | |
1ae155da MW |
53 | \def\atsign{@} |
54 | \def\athyphen{@\mbox{-}} | |
86f6a31e | 55 | \aton |
56 | \atlet p=\package | |
57 | \atdef at{\package{at}} | |
58 | \atdef={\mbox{-}} | |
59 | \atdef-{@@@=} | |
60 | \atlet.=\syntax | |
61 | \mdwdoc | |
62 | %</driver> | |
63 | % | |
64 | % \end{meta-comment} | |
65 | % | |
66 | % \section{User guide} | |
67 | % | |
68 | % The @at\ package is an attempt to remove a lot of tedious typing that | |
69 | % ends up in \LaTeX\ documents, by expanding the number of short command | |
70 | % names available. The new command names begin with the `|@|' character, | |
71 | % rather than the conventional `|\|', so you can tell them apart. | |
72 | % | |
73 | % The package provides some general commands for defining @-commands, and | |
74 | % then uses them to define some fairly simple ones which will be useful to | |
75 | % most people. | |
76 | % | |
77 | % The rules for @-command names aren't terribly complex: | |
78 | % \begin{itemize} | |
79 | % \item If the first character of the name is a letter, then the command name | |
80 | % consists of all characters up to, but not including, the first | |
81 | % nonletter. Spaces following the command name are ignored. | |
82 | % \item If the first character of the name is a backslash, then the @-command | |
83 | % name consists of the control sequence introduced by the backslash. | |
84 | % \item Otherwise, the command name consists only of that first character. | |
85 | % Spaces following the name are not ignored, unless that character | |
86 | % was itself a space character. | |
87 | % \end{itemize} | |
88 | % | |
89 | % Usually, digits are not considered to be letters. However, the | |
90 | % \package{at} package will consider digits to be letters if you give it the | |
91 | % \textsf{digits} option in the |\usepackage| command. (Note that this | |
92 | % only affects the \package{at} package; it won't change the characters | |
93 | % allowed in normal command names.) | |
94 | % | |
95 | % \DescribeMacro{\atallowdigits} | |
96 | % \DescribeMacro{\atdisallowdigits} | |
97 | % You can enable and disable digits being considered as letters dynamically. | |
98 | % The |\atallowdigits| command allows digits to be used as letters; | |
99 | % |\atdisallowdigits| prevents this. Both declarations follow \LaTeX's | |
100 | % usual scoping rules. Both of these commands have corresponding | |
101 | % environments with the same names (without the leading `|\|', obviously). | |
102 | % | |
1ae155da | 103 | % \subsection{Defining \athyphen commands} |
86f6a31e | 104 | % |
105 | % \DescribeMacro{\newatcommand} | |
106 | % \DescribeMacro{\renewatcommand} | |
107 | % The |\newatcommand| command will define a new @-command using a syntax | |
108 | % similar to |\newcommand|. For example, you could define | |
109 | % \begin{listing} | |
110 | %\newatcommand c[1]{\chapter{#1}} | |
111 | % \end{listing} | |
112 | % to make @.{"@c{"<name>"}"} equivalent to @.{"\\chapter{"<name>"}"}. | |
113 | % | |
114 | % A |\renewatcommand| is also provided to redefine existing commands, should | |
115 | % the need arise. | |
116 | % | |
117 | % \DescribeMacro{\atdef} | |
118 | % For \TeX\ hackers, the |\atdef| command defines @-commands using a syntax | |
e8e9e5d8 | 119 | % similar to \TeX's built-in |\def|. |
86f6a31e | 120 | % |
121 | % As an example, the following command makes @.{"@/"<text>"/"} write its | |
122 | % argument \<text> in italics: | |
123 | % \begin{listing} | |
124 | %\atdef/#1/{\textit{#1}} | |
125 | % \end{listing} | |
126 | % The real implementation of the |@/|\dots|/| command is a bit more | |
127 | % complex, and is given in the next section. | |
128 | % | |
129 | % You can use all of \TeX's features for defining the syntax of your | |
130 | % command. (See chapter~20 of @/The \TeX book/ for more details.) | |
131 | % | |
132 | % \DescribeMacro{\atlet} | |
133 | % Since |\atdef| is provided to behave similarly to |\def|, @at\ provides | |
134 | % |\atlet| which works similarly to |\let|. For example you can say | |
135 | % \begin{listing} | |
136 | %\atlet!=\index | |
137 | % \end{listing} | |
138 | % to allow the short |@!| to behave exactly like |\index|. | |
139 | % | |
140 | % Note that all commands defined using these commands are robust even if you | |
141 | % use fragile commands in their definitions. Unless you start doing very | |
142 | % strange things, @-commands never need |\protect|ing. | |
143 | % | |
1ae155da | 144 | % \subsection{Predefined \athyphen commands} |
86f6a31e | 145 | % |
146 | % A small number of hopefully useful commands are provided by default. | |
147 | % These are described in the table below: | |
148 | % | |
149 | % \bigskip \begin{center} \begin{tabular}{lp{3in}} \hline | |
150 | % \bf Command & \bf Meaning \\ \hline | |
151 | % @.{"@@"} & Typesets an `@@' character. \\ | |
152 | % @.{"@/"<text>"/"} & In text (LR or paragraph) mode, typesets its | |
153 | % argument emphasised. In maths mode, it | |
154 | % always chooses italics. \\ | |
155 | % @.{"@*"<text>"*"} & Typesets its argument \<text> in bold. \\ | |
156 | % @.{"@i{"<text>"}"} & Equivalent to `@.{"\\index{"<text>"}"}'. \\ | |
157 | % @.{"@I{"<text>"}"} & As for |@i|, but also writes its argument | |
158 | % to the document. \\ \hline | |
159 | % \end{tabular} \end{center} \bigskip | |
160 | % | |
161 | % Package writers should not rely on any predefined @-commands -- they're | |
162 | % provided for users, and users should be able to redefine them without | |
163 | % fear of messing anything up. (This includes the `standard' commands | |
164 | % provided by the @at\ package, by the way. They're provided in the vague | |
165 | % hope that they might be useful, and as examples.) | |
166 | % | |
167 | % \implementation | |
168 | % | |
169 | % \section{Implementation} | |
170 | % | |
171 | % \begin{macrocode} | |
172 | %<*package> | |
173 | % \end{macrocode} | |
174 | % | |
175 | % \subsection{Options handling} | |
176 | % | |
177 | % We need a switch to say whether digits should be allowed. Since this | |
178 | % is a user thing, I'll avoid |\newif| and just define the thing by hand. | |
179 | % | |
180 | % \begin{macrocode} | |
181 | \def\atallowdigits{\let\ifat@digits\iftrue} | |
182 | \def\atdisallowdigits{\let\ifat@digits\iffalse} | |
183 | % \end{macrocode} | |
184 | % | |
185 | % Now define the options. | |
186 | % | |
187 | % \begin{macrocode} | |
188 | \DeclareOption{digits}{\atallowdigits} | |
189 | \DeclareOption{nodigits}{\atdisallowdigits} | |
190 | \ExecuteOptions{nodigits} | |
191 | \ProcessOptions | |
192 | % \end{macrocode} | |
193 | % | |
194 | % \subsection{How the commands work} | |
195 | % | |
196 | % Obviously we make the `@@' character active. It inspects the next | |
197 | % character (or argument, actually -- it can be enclosed in braces for | |
198 | % longer commands, although this is a bit futile), and builds the command | |
199 | % name from that. | |
200 | % | |
201 | % The |\at| command is equivalent to the active `@@' character always. | |
202 | % | |
203 | % | |
204 | % \subsection{Converting command names} | |
205 | % | |
206 | % We need to be able to read an @-command name, and convert it to a normal | |
207 | % \TeX\ control sequence. First, we declare some control sequences for | |
208 | % braces, which we need later. | |
209 | % | |
210 | % \begin{macrocode} | |
211 | \begingroup | |
212 | \catcode`\<1 | |
213 | \catcode`\>2 | |
214 | \catcode`\{12 | |
215 | \catcode`\}12 | |
216 | \gdef\at@lb<{> | |
217 | \gdef\at@rb<}> | |
218 | \gdef\at@spc< > | |
219 | \endgroup | |
220 | % \end{macrocode} | |
221 | % | |
222 | % I'll set up some helper routines now, to help me read the command | |
223 | % names. The way this works is that we |\futurelet| the token into | |
224 | % |\@let@token|. These routines will then sort out what to do next. | |
225 | % | |
226 | % \begin{macro}{\at@test} | |
227 | % | |
228 | % Given an |\if|\dots\ test, does its first or second argument. | |
229 | % | |
230 | % \begin{macrocode} | |
231 | \def\at@test#1\then{% | |
232 | #1\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi% | |
233 | } | |
234 | % \end{macrocode} | |
235 | % | |
236 | % \end{macro} | |
237 | % | |
238 | % \begin{macro}{\at@ifcat} | |
239 | % | |
240 | % Checks the category code of the current character. If it matches the | |
241 | % argument, it does its second argument, otherwise it does the third. | |
242 | % | |
243 | % \begin{macrocode} | |
244 | \def\at@ifcat#1{\at@test\ifcat#1\noexpand\@let@token\then} | |
245 | % \end{macrocode} | |
246 | % | |
247 | % \end{macro} | |
248 | % | |
249 | % \begin{macro}{\at@ifletter} | |
250 | % | |
251 | % This routine tests the token to see if it's a letter, and if so adds | |
252 | % it to the token list and does the first argument; otherwise it does the | |
253 | % second argument. It accepts digits as letters if the switch is turned | |
254 | % on. | |
255 | % | |
256 | % There's some fun later, so I'll describe this slowly. First, we compare | |
257 | % the category code to a letter, and if we have a match, we know we're done; | |
258 | % we need to pick up the letter as an argument. If the catcode is `other', | |
259 | % we must compare with numbers to see if it's in range. | |
260 | % | |
261 | % \begin{macrocode} | |
262 | \def\at@ifletter#1#2{% | |
263 | \at@ifcat x% | |
264 | {\at@ifletter@ii{#1}}% | |
265 | {\at@ifcat 0% | |
266 | {\at@ifletter@i{#1}{#2}}% | |
267 | {#2}% | |
e8e9e5d8 | 268 | }% |
86f6a31e | 269 | } |
270 | % \end{macrocode} | |
271 | % | |
272 | % Right. It's `other' (so it's safe to handle as a macro argument) and we | |
273 | % need to know if it's a digit. This is a little tricky: I use |\if| to | |
274 | % compare two characters. The first character is~`1' or~`0' depending on the | |
275 | % `digit' switch; the second is~`1' or~`x' depending on whether it's actually | |
276 | % a digit. They'll only match if everything's worked out OK. | |
277 | % | |
278 | % \begin{macrocode} | |
279 | \def\at@ifletter@i#1#2#3{% | |
280 | \at@test\if% | |
281 | \ifat@digits1\else0\fi% | |
282 | \ifnum`#3<`0x\else\ifnum`#3>`9x\else1\fi\fi% | |
283 | \then% | |
284 | {\at@ifletter@ii{#1}{#3}}% | |
285 | {#2#3}% | |
286 | } | |
287 | % \end{macrocode} | |
288 | % | |
289 | % Right; we have the character, so add it to the list and carry on. | |
290 | % | |
291 | % \begin{macrocode} | |
292 | \def\at@ifletter@ii#1#2{\toks@\expandafter{\the\toks@#2}#1} | |
293 | % \end{macrocode} | |
294 | % | |
295 | % \end{macro} | |
296 | % | |
297 | % Now we define the command name reading routines. We have @/almost/ the | |
298 | % same behaviour as \TeX, although we can't support `|%|' characters for | |
299 | % reasons to do with \TeX's tokenising algorithm. | |
300 | % | |
301 | % \begin{macro}{\at@read@name} | |
302 | % | |
303 | % The routine which actually reads the command name works as follows: | |
304 | % \begin{enumerate} | |
305 | % \item Have a peek at the next character. If it's a left or right brace, | |
306 | % then use the appropriate character. | |
307 | % \item If the character is not a letter, just use the character (or whole | |
308 | % control sequence. | |
309 | % \item Finally, if it's a letter, keep reading letters until we find one | |
310 | % that wasn't. | |
311 | % \end{enumerate} | |
312 | % | |
313 | % First, we do some setting up and read the first character | |
314 | % | |
315 | % \begin{macrocode} | |
316 | \def\at@read@name#1{% | |
317 | \let\at@next=#1% | |
318 | \toks@{}% | |
319 | \futurelet\@let@token\at@rn@i% | |
320 | } | |
321 | % \end{macrocode} | |
322 | % | |
323 | % Next, sort out what to do, based on the category code. | |
324 | % | |
325 | % \begin{macrocode} | |
326 | \def\at@rn@i{% | |
327 | \def\@tempa{\afterassignment\at@rn@iv\let\@let@token= }% | |
328 | \at@ifletter% | |
329 | {\futurelet\@let@token\at@rn@iii}% | |
330 | {\at@ifcat\bgroup% | |
331 | {\toks@\expandafter{\at@lb}\@tempa}% | |
332 | {\at@ifcat\egroup% | |
333 | {\toks@\expandafter{\at@rb}\@tempa}% | |
334 | {\at@ifcat\at@spc% | |
335 | {\toks@{ }\@tempa}% | |
336 | {\at@rn@ii}% | |
337 | }% | |
338 | }% | |
339 | }% | |
340 | } | |
341 | % \end{macrocode} | |
342 | % | |
343 | % Most types of tokens can be fiddled using |\string|. | |
344 | % | |
345 | % \begin{macrocode} | |
346 | \def\at@rn@ii#1{% | |
347 | \toks@\expandafter{\string#1}% | |
348 | \at@rn@iv% | |
349 | } | |
350 | % \end{macrocode} | |
351 | % | |
352 | % We've found a letter, so we should check for another one. | |
353 | % | |
354 | % \begin{macrocode} | |
355 | \def\at@rn@iii{% | |
356 | \at@ifletter% | |
357 | {\futurelet\@let@token\at@rn@iii}% | |
358 | {\@ifnextchar.\at@rn@iv\at@rn@iv}% | |
359 | } | |
360 | % \end{macrocode} | |
361 | % | |
362 | % Finally, we need to pass the real string, as an argument, to the | |
363 | % macro. We make |\@let@token| relax, since it might be something which will | |
364 | % upset \TeX\ later, e.g., a |#| character. | |
365 | % | |
366 | % \begin{macrocode} | |
367 | \def\at@rn@iv{% | |
368 | \let\@let@token\relax% | |
369 | \expandafter\at@next\csname at.\the\toks@\endcsname% | |
370 | } | |
371 | % \end{macrocode} | |
372 | % | |
373 | % \end{macro} | |
374 | % | |
375 | % \begin{macro}{\at@cmdname} | |
376 | % | |
377 | % Given a control sequence, work out which @-command it came from. | |
378 | % | |
379 | % \begin{macrocode} | |
380 | \def\at@cmdname#1{\expandafter\at@cmdname@i\string#1\@@foo} | |
381 | % \end{macrocode} | |
382 | % | |
383 | % Now extract the trailing bits. | |
384 | % | |
385 | % \begin{macrocode} | |
386 | \def\at@cmdname@i#1.#2\@@foo{#2} | |
387 | % \end{macrocode} | |
388 | % | |
389 | % \end{macro} | |
390 | % | |
391 | % \begin{macro}{\at@decode} | |
392 | % | |
393 | % The |\at@decode| macro takes an extracted @-command name, and tries to | |
394 | % execute the correct control sequence derived from it. | |
395 | % | |
396 | % \begin{macrocode} | |
397 | \def\at@decode#1{% | |
398 | \at@test\ifx#1\relax\then{% | |
399 | \PackageError{at}{Unknown @-command `@\at@cmdname#1'}{% | |
400 | The @-command you typed wasn't recognised, so I've ignored it. | |
401 | }% | |
402 | }{% | |
403 | #1% | |
404 | }% | |
405 | } | |
406 | % \end{macrocode} | |
407 | % | |
408 | % \end{macro} | |
409 | % | |
410 | % \begin{macro}{\@at} | |
411 | % | |
412 | % We'd like a measure of compatibility with @p{amsmath}. The @-commands | |
413 | % provided by @p{amsmath} work only in maths mode, so this gives us a way of | |
414 | % distinguishing. If the control sequence |\Iat| is defined, and we're in | |
415 | % maths mode, we'll call that instead of doing our own thing. | |
416 | % | |
417 | % \begin{macrocode} | |
418 | \def\@at{% | |
419 | \def\@tempa{\at@read@name\at@decode}% | |
420 | \ifmmode\ifx\Iat\not@@defined\else% | |
421 | \let\@tempa\Iat% | |
422 | \fi\fi% | |
423 | \@tempa% | |
424 | } | |
425 | % \end{macrocode} | |
426 | % | |
427 | % \end{macro} | |
428 | % | |
429 | % | |
430 | % \subsection{Defining new commands} | |
431 | % | |
432 | % \begin{macro}{\at@buildcmd} | |
433 | % | |
434 | % First, we define a command to build these other commands: | |
435 | % | |
436 | % \begin{macrocode} | |
437 | \def\at@buildcmd#1#2{% | |
438 | \expandafter\def\csname\expandafter | |
439 | \@gobble\string#1@decode\endcsname##1{#2##1}% | |
440 | \edef#1{% | |
441 | \noexpand\at@read@name% | |
442 | \expandafter\noexpand% | |
443 | \csname\expandafter\@gobble\string#1@decode\endcsname% | |
444 | }% | |
445 | } | |
446 | % \end{macrocode} | |
447 | % | |
448 | % \end{macro} | |
449 | % | |
450 | % \begin{macro}{\newatcommand} | |
451 | % \begin{macro}{\renewatcommand} | |
452 | % \begin{macro}{\provideatcommand} | |
453 | % \begin{macro}{\atdef} | |
454 | % \begin{macro}{\atshow} | |
455 | % | |
456 | % Now we define the various operations on @-commands. | |
457 | % | |
458 | % \begin{macrocode} | |
459 | \at@buildcmd\newatcommand\newcommand | |
460 | \at@buildcmd\renewatcommand\renewcommand | |
461 | \at@buildcmd\provideatcommand\providecommand | |
462 | \at@buildcmd\atdef\def | |
463 | \at@buildcmd\atshow\show | |
464 | % \end{macrocode} | |
465 | % | |
466 | % \end{macro} | |
467 | % \end{macro} | |
468 | % \end{macro} | |
469 | % \end{macro} | |
470 | % \end{macro} | |
471 | % | |
472 | % \begin{macro}{\atlet} | |
473 | % | |
474 | % |\atlet| is rather harder than the others, because we want to allow people | |
475 | % to say things like @.{"\\atlet"<name>"=@"<name>}. The following hacking | |
476 | % does the trick. I'm trying very hard to duplicate |\let|'s behaviour with | |
477 | % respect to space tokens here, to avoid any surprises, although there | |
478 | % probably will be some differences. In particular, |\afterassignment| | |
479 | % won't work in any sensible way. | |
480 | % | |
481 | % First, we read the name of the @-command we're defining. We also open | |
482 | % a group, to stop messing other people up, and make `@@' into an `other' | |
483 | % token, so that it doesn't irritatingly look like its meaning as a control | |
484 | % sequence. | |
485 | % | |
486 | % \begin{macrocode} | |
487 | \def\atlet{% | |
488 | \begingroup% | |
489 | \@makeother\@% | |
490 | \at@read@name\atlet@i% | |
491 | } | |
492 | % \end{macrocode} | |
493 | % | |
494 | % Put the name into a scratch macro for later use. Now see if there's an | |
495 | % equals sign up ahead. If not, this will gobble any spaces in between the | |
496 | % @-command name and the argument. | |
497 | % | |
498 | % \begin{macrocode} | |
499 | \def\atlet@i#1{% | |
500 | \def\at@temp{#1}% | |
501 | \@ifnextchar=\atlet@ii{\atlet@ii=}% | |
502 | } | |
503 | % \end{macrocode} | |
504 | % | |
505 | % Now we gobble the equals sign (whatever catcode it is), and peek at the | |
506 | % next token up ahead using |\let| with no following space. | |
507 | % | |
508 | % \begin{macrocode} | |
509 | \def\atlet@ii#1{\afterassignment\atlet@iii\global\let\at@gnext=} | |
510 | % \end{macrocode} | |
511 | % | |
512 | % The control sequence |\at@gnext| is now |\let| to be whatever we want the | |
513 | % @-command to be, unless it's picked up an `@@' sign. If it has, we've | |
514 | % eaten the |@| token, so just read the name and pass it on. Otherwise, | |
515 | % we can |\let| the @-command directly to |\at@gnext|. There's some | |
516 | % nastiness here to make |\the\toks@| expand before we close the group and | |
517 | % restore its previous definition. | |
518 | % | |
519 | % \begin{macrocode} | |
520 | \def\atlet@iii{% | |
521 | \if @\noexpand\at@gnext% | |
522 | \expandafter\at@read@name\expandafter\atlet@iv% | |
523 | \else% | |
524 | \expandafter\endgroup% | |
525 | \expandafter\let\at@temp= \at@gnext% | |
526 | \fi% | |
527 | } | |
528 | % \end{macrocode} | |
529 | % | |
530 | % We've read the source @-command name, so just copy the definitions over. | |
531 | % | |
532 | % \begin{macrocode} | |
533 | \def\atlet@iv#1{% | |
534 | \expandafter\endgroup% | |
535 | \expandafter\let\at@temp=#1% | |
536 | } | |
537 | % \end{macrocode} | |
538 | % | |
539 | % \end{macro} | |
540 | % | |
541 | % | |
1ae155da | 542 | % \subsection{Robustness of \athyphen commands} |
86f6a31e | 543 | % |
544 | % We want all @-commands to be robust. We could leave them all being | |
545 | % fragile, although making robust @-commands would then be almost impossible. | |
546 | % There are two problems which we must face: | |
547 | % | |
548 | % \begin{itemize} | |
549 | % | |
550 | % \item The `|\@at|' command which scans the @-command name is (very) | |
551 | % fragile. I could have used |\DeclareRobustCommand| for it (and in | |
552 | % fact I did in an earlier version), but that doesn't help the other | |
553 | % problem at all. | |
554 | % | |
555 | % \item The `name' of the @-command may contain active characters or control | |
556 | % sequences, which will be expanded at the wrong time unless we do | |
557 | % something about it now. | |
558 | % | |
559 | % \end{itemize} | |
560 | % | |
561 | % We must also be careful not to introduce extra space characters into any | |
562 | % files written, because spaces are significant in @-commands. Finally, | |
563 | % we have a minor problem in that most auxiliary files are read in with | |
564 | % the `@@' character set to be a letter. | |
565 | % | |
566 | % \begin{macro}{\at} | |
567 | % | |
568 | % Following the example of \LaTeX's `short' command handling, we'll define | |
569 | % |\at| to decide what to do depending on what |\protect| looks like. If | |
570 | % we're typesetting, we just call |\@at| (above) and expect it to cope. | |
571 | % Otherwise we call |\at@protect|, which scoops up the |\fi| and the |\@at|, | |
572 | % and inserts other magic. | |
573 | % | |
574 | % \begin{macrocode} | |
575 | \def\at{\ifx\protect\@typeset@protect\else\at@protect\fi\@at} | |
576 | % \end{macrocode} | |
577 | % | |
578 | % \end{macro} | |
579 | % | |
580 | % \begin{macro}{\at@protect} | |
581 | % | |
e8e9e5d8 MW |
582 | % Since we gobbled the |\fi| from the above, we must put that back. We then |
583 | % need to do things which are more complicated. If |\protect| is behaving | |
86f6a31e | 584 | % like |\string|, then we do one sort of protection. Otherwise, we assume |
585 | % that |\protect| is being like |\noexpand|. | |
586 | % | |
587 | % \begin{macrocode} | |
588 | \def\at@protect\fi#1{% | |
589 | \fi% | |
590 | \ifx\protect\string% | |
591 | \expandafter\at@protect@string% | |
592 | \else% | |
593 | \expandafter\at@protect@noexpand% | |
594 | \fi% | |
595 | } | |
596 | % \end{macrocode} | |
597 | % | |
598 | % \end{macro} | |
599 | % | |
600 | % \begin{macro}{\at@protect@string} | |
601 | % | |
602 | % When |\protect| is |\string|, we don't need to be able to recover the | |
603 | % original text particularly accurately -- it's for the user to look at. | |
604 | % Therefore, we just output a $|@|_{11}$ and use |\string| on the next | |
605 | % token. This must be sufficient, since we only allow multi-token command | |
606 | % names if the first token is a letter (code~11). | |
607 | % | |
608 | % \begin{macrocode} | |
609 | \def\at@protect@string{@\string} | |
610 | % \end{macrocode} | |
611 | % | |
612 | % \end{macro} | |
613 | % | |
614 | % \begin{macro}{\at@protect@noexpand} | |
615 | % | |
616 | % This is a little more complex, since we're still expecting to be executed | |
617 | % properly at some stage. However, there's a cheeky dodge we can employ | |
618 | % since the |\at| command is thoroughly robustified (or at least it will be | |
619 | % by the time we've finished this). All |\@unexpandable@protect| does | |
620 | % is confer repeated robustness on a fragile command. Since our command | |
621 | % is robust, we don't need this and we can get away with just using a | |
622 | % single |\noexpand|, both for the |\@at@| command and the following token | |
623 | % (which we must robustify, because no-one else can do it for us -- if | |
624 | % anyone tries, they end up using the |@\protect| command which is rather | |
625 | % embarassing). | |
626 | % | |
627 | % I'll give the definition, and then examine how this expands in various | |
628 | % cases. | |
629 | % | |
630 | % \begin{macrocode} | |
631 | \def\at@protect@noexpand{\noexpand\@at@ @\noexpand} | |
632 | \def\@at@#1{\at} | |
633 | % \end{macrocode} | |
634 | % | |
635 | % A few points, before we go into the main examination of the protection. | |
636 | % I've inserted a $|@|_{11}$ token, which is gobbled by |\@at@| when the | |
637 | % thing is finally expanded fully. This prevents following space tokens | |
638 | % in an |\input| file from being swallowed because they follow a control | |
639 | % sequence. (I can't use the normal $|@|_{13}$ token, because when files | |
640 | % like the |.aux| file are read in, |@| is given code~11 by | |
641 | % |\makeatletter|.) | |
642 | % | |
643 | % \setbox0\hbox{|@at@|} | |
644 | % Now for a description of why this works. When |\at| is expanded, it works | |
645 | % out that |\protect| is either |\noexpand| or |\@unexpandable@protect|, and | |
646 | % becomes |\at@protect@noexpand|. Because of the |\noexpand| tokens, this | |
647 | % stops being expanded once it reaches $\fbox{\box0}\,|@|_{11}\,x$ (where | |
648 | % $x$ is the token immediately following the $|@|_{13}$ character). If this | |
649 | % is expanded again, for example in another |\edef|, or in a |\write| or a | |
650 | % |\mark|, the |\@at@| wakes up, gobbles the following |@| (whatever catcode | |
651 | % it is -- there may be intervening |\write| and |\input| commands) and | |
652 | % becomes |\at|, and the whole thing can start over again. | |
653 | % | |
654 | % \end{macro} | |
655 | % | |
656 | % | |
657 | % \subsection{Enabling and disabling @-commands} | |
658 | % | |
659 | % \begin{macro}{\aton} | |
660 | % | |
661 | % We define the |\aton| command to enable all of our magic. We store | |
662 | % the old catcode in the |\atoff| command, make `@@' active, and make it | |
663 | % do the stuff. | |
664 | % | |
665 | % \begin{macrocode} | |
666 | \def\aton{% | |
667 | \ifnum\catcode`\@=\active\else% | |
668 | \edef\atoff{\catcode`\noexpand\@\the\catcode`\@}% | |
669 | \catcode`\@\active% | |
670 | \lccode`\~`\@% | |
671 | \lowercase{\let~\at}% | |
672 | \fi% | |
673 | } | |
674 | % \end{macrocode} | |
675 | % | |
676 | % \end{macro} | |
677 | % | |
678 | % \begin{macro}{\atoff} | |
679 | % | |
680 | % The |\atoff| command makes `@@' do the stuff it's meant to. We remember | |
681 | % the old catcode and revert to it. This is largely unnecessary. | |
682 | % | |
683 | % \begin{macrocode} | |
684 | \def\atoff{\catcode`\@12} | |
685 | % \end{macrocode} | |
686 | % | |
687 | % \end{macro} | |
688 | % | |
689 | % \begin{macro}{\makeatother} | |
690 | % | |
691 | % Now we make our active `@@' the default outside of package files. | |
692 | % | |
693 | % \begin{macrocode} | |
694 | \let\makeatother\aton | |
695 | % \end{macrocode} | |
696 | % | |
697 | % \end{macro} | |
698 | % | |
699 | % And we must make sure that the user can use all of our nice commands. | |
700 | % Once the document starts, we allow @-commands. | |
701 | % | |
702 | % \begin{macrocode} | |
703 | \AtBeginDocument{\aton} | |
704 | % \end{macrocode} | |
705 | % | |
706 | % \begin{macro}{\dospecials} | |
707 | % \begin{macro}{\@sanitize} | |
708 | % | |
709 | % We must add the `@@' character to the various specials lists. | |
710 | % | |
711 | % \begin{macrocode} | |
712 | \expandafter\def\expandafter\dospecials\expandafter{\dospecials\do\@} | |
713 | \expandafter\def\expandafter\@sanitize\expandafter{% | |
714 | \@sanitize\@makeother\@} | |
715 | % \end{macrocode} | |
716 | % | |
717 | % \end{macro} | |
718 | % \end{macro} | |
719 | % | |
1ae155da | 720 | % \subsection{Default \athyphen commands} |
86f6a31e | 721 | % |
722 | % We define some trivial examples to get the user going. | |
723 | % | |
724 | % \begin{macrocode} | |
725 | \expandafter\chardef\csname at.@\endcsname=`\@ | |
726 | \atdef*#1*{\ifmmode\mathbf{#1}\else\textbf{#1}\fi} | |
727 | \atdef/#1/{\ifmmode\mathit{#1}\else\emph{#1}\fi} | |
728 | \atlet i=\index | |
729 | \atdef I#1{#1\index{#1}} | |
730 | %</package> | |
731 | % \end{macrocode} | |
732 | % | |
733 | % \hfill Mark Wooding, \today | |
734 | % | |
735 | % \Finale | |
736 | % | |
737 | \endinput |