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