ltfntcmd.dtx

Frank Mittelbach, Chris Rowley

1995/07/03

Abstract

The commands defined in this file ltfntcmd are part of the kernel code for L^{A}TEX 2ε/NFSS2.

It is also meant to serve as documentation for package writers since it demonstrates how to define high-level font changing commands using a small number of creator functions.

1 Introduction

Font changes such as \bfseries, \sffamily, etc. are declarations; this means that their scope is delimited by the grouping structure, either by the next \end of some environment or by explicitly using a group, e.g., writing something like {\bfseries...} in the source. If you make the mistake of writing \bfseries{...} (thinking of \bfseries as a command with one argument) then the result is rather striking.

Font declarations are an artifact of the TEX system and for several reasons it is better to avoid them on the user level whenever possible. In L^{A}TEX3 they will probably all be replaced by environments and by font commands taking one argument.

This file defines a creator function for such declarative font switches. This function creates commands which can be used in both math and text.

This file also defines a number of high-level commands (all starting with \text..) that have one argument and typeset this argument in the requested way. Thus these commands are for typesetting short pieces of text in a specific family, series or shape. These are all produced as examples of the use of a creator function which is itself also defined in this file.

Table 1 shows all these high-level commands in action. A further advantage of using these commands is that they automatically take care of any necessary italic correction on either side of their argument.

Thus, when using such commands, one does not have to worry about forgetting the italic correction when changing fonts. Only in very few situations is this additional space wrong but, for example, most typographers recommend omitting the italic correction if a small punctuation character, like a comma, directly follows the font change. Since the amount of correction required is partly a matter of taste,

Command  Corresponds to Action
\textrm{..}  \rmfamily  Typeset argument in roman family
\textsf{..}  \sffamily  Typeset argument in sans serif family

\texttt{..}  \ttfamily  Typeset argument in typewriter family

\textmd{..}  \mdseries  Typeset argument in medium series
\textbf{..}  \bfseries  Typeset argument in bold series
\textup{..}  \upshape  Typeset argument in normal shape
\textit{..}  \itshape  Typeset argument in italic shape
\textsl{..}  \slshape  Typeset argument in slanted shape
\textsc{..}  \scshape  Typeset argument in small caps shape
\emph{..}    \em  Typeset argument emphasized

Table 1: Font-change commands with arguments

The font change commands provided here all start with \text.. to emphasize that they are for use in normal text and to be easily memorable. They automatically take care of any necessary italic correction on either side of the argument.

you can define in what situations the italic correction should be suppressed. This is done by puttiing the characters that should cancel a preceding italic correction in the list \nocorrlist.^{1} The default definition for this list is produced by the following.

\newcommand \nocorrlist {,.}

It is best to declare the most often used characters first, because this will make the processing slightly faster. For example,

\emph{When using the \NFSS{} high-level commands,
the \emph{proper} use of italic corrections is
automatically taken care of}. Only
\emph{sometimes} one has to help \LaTeX{} by
adding a \verb=\nocorr= command.

which results in:

When using the NFSS high-level commands, the proper use of italic corrections is automatically taken care of. Only sometimes one has to help L^{A}TEX by adding a \nocorr command.

1Any package that changes the \catcode of a character inside \nocorrlist must then explicitly reset the list. Otherwise the changed character will no longer be recognized by the suppression algorithm.

In contrast, the use of the declaration forms is often more appropriate when you define your own commands or environments.

 \newenvironment{bfitemize}{\begin{itemize}\normalfont\bfseries}
                           {\end{itemize}}
 \begin{bfitemize}
 \item This environment produces boldface items.
 \item It is defined in terms of \LaTeX's
   \texttt{itemize} environment and NFSS
   declarations.
 \end{bfitemize}

This gives:

• This environment produces boldface items.

• It is defined in terms of L^{A}TEX’s itemize environment and NFSS declarations.

In addition to global customization of when to insert the italic correction, it is of course sometimes necessary to explicitly insert one with \/.

It is also possible to suppress the italic correction in individual instances. For this, the command \nocorr is provided.

The \nocorr must appear as the first or last token inside the braces of the argument of the \text... commands, at that end of the text where you wish to suppress the italic correction.

It is worth pointing out here that inserting a \/ in places where it can have no function (i.e. anywhere except immediately after a slanted letter) is not an error— it will just be silently ignored. Unfortunately this is not true if the redefinition of \/ in amstex.sty is used as this version can cause space to be removed immediately before the \/.

2 The implementation

\DeclareTextFontCommand This is the creator function for \text.. commands. It gives a warning if \foo or

\fragfoo is already defined.

In math mode it simply puts the font declaration and text into a box (possibly an automagically sized one).

Otherwise it first scans the text to see where \nocorr occurs within it. This sets the \check@ic commands to do what is necessary concerning the italic correction at both ends.

Note that it is necessary to put in the \aftergroup\maybe@ic at the end of the group so that it comes after any other aftergroup tokens and immediately before the following tokens. It is also necessary to remove the \fi from the token list before the group ends; this is done by adding an \expandafter just before the closing brace.

This now checks for empty contents of text command and optimises this case.

1 ⟨∗2ekernel⟩

 2 \def \DeclareTextFontCommand #1#2{%
 3 \DeclareRobustCommand#1[1]{%
 4  \ifmmode
 5  \nfss@text{#2##1}%
 6  \else
 7  \leavevmode
 8  {\text@command{##1}%
 9  #2\check@icl ##1\check@icr
10  \expandafter}%
11  \fi
12  }%

13 }

\textrm \textsf \texttt \textnormal Now we define the \text⟨family⟩ commands in terms of the above; \texttt does not look very nice!

14 \DeclareTextFontCommand{\textrm}{\rmfamily}
15 \DeclareTextFontCommand{\textsf}{\sffamily}
16 \DeclareTextFontCommand{\texttt}{\ttfamily}
17 \DeclareTextFontCommand{\textnormal}{\normalfont}

\textbf \textmd For the series attribute:

18 \DeclareTextFontCommand{\textbf}{\bfseries}
19 \DeclareTextFontCommand{\textmd}{\mdseries}
\textit \textsl \textsc \textup And for the shapes:
20 \DeclareTextFontCommand{\textit}{\itshape}
21 \DeclareTextFontCommand{\textsl}{\slshape}
22 \DeclareTextFontCommand{\textsc}{\scshape}
23 \DeclareTextFontCommand{\textup}{\upshape}

\emph Finally we have the \em font change declaration of L^{A}TEX. The corresponding definition with argument is

24 \DeclareTextFontCommand{\emph}{\em}

\nocorr This is just a label, so it does nothing; it should also be unexpandable.

25 \let \nocorr \relax

\text@command \check@nocorr@ \check@icl \check@icr This checks for a \nocorr as the first token in its argument and also for one in any other position not protected within braces (the latter is treated as if it were at the end of the argument).

Is this the correct action in the ‘empty’ case? It is efficient but typographically it is, strictly, incorrect!

26 \def \text@command #1{%
27 \def \reserved@a {#1}%
28 \ifx \reserved@a \@empty
29  \let \check@icl \@empty
30  \let \check@icr \@empty
31 \else

\space is a reserved word in L^{A}TEX or actually already in plain TEX. If somebody really redefines it so many things will break that I don’t see any reason to make this routine here slower than necessary.

32 %    \def \reserved@b { }%
33 %    \ifx \reserved@a \reserved@b
34  \ifx \reserved@a \space
35  \let \check@icl \@empty
36  \let \check@icr \@empty
37  \else
38  \check@nocorr@ #1\nocorr\@nil
39  \fi
40 \fi

41 }

42 \def \check@nocorr@ #1#2\nocorr#3\@nil {%

The two checks are initialised here to their values in the normal case.

43 \let \check@icl \maybe@ic
44 \def \check@icr {\aftergroup \maybe@ic}%
45 \def \reserved@a {\nocorr}%
46 \def \reserved@b {#1}%
47 \def \reserved@c {#3}%
48 \ifx \reserved@a \reserved@b
49  \ifx \reserved@c \@empty

In this case there is a \nocorr at the start but not at the end, so \check@icl should be empty.

50  \let \check@icl \@empty
51  \else

Otherwise there is a \nocorr both at the start and elsewhere, so no italic corrections should be added.

52  \let \check@icl \@empty
53  \let \check@icr \@empty
54  \fi
55 \else
56  \ifx \reserved@c \@empty

In this case there is no \nocorr anywhere, so we need to check for an italic corection at both the beginning and the end.

57  \else

In this case there is no \nocorr at the start but there is one elsewhere, so no

\aftergroup is needed.
58  \let \check@icr \@empty
59  \fi
60 \fi

61 }

\maybe@ic \maybe@ic@ These macros implement the italic correction.

62 \def \maybe@ic {\futurelet\@let@token\maybe@ic@}
63 \def \maybe@ic@ {%

We first check to see if the current font is also sloped. (But do not forget the message Rainer sent about an upright font with non-zero slope!)

64 \ifdim \fontdimen\@ne\font>\z@
65 \else
66  \@tempswatrue

It would be possible, but probably not worthwhile, to continue the forward scan beyond any closing braces.

67  \expandafter\@tfor\expandafter\reserved@a\expandafter:\expandafter=%
68  \nocorrlist

We have to hide the \@let@token in the macro \t@st@ic rather than testing it directly in the loop since it might be \let to a \fi or \else, which would result in chaos.

69  \do \t@st@ic

Frank thinks that the next bit it is inefficient if done after the second change. Chris thinks that most all of this is inefficient for the commonest cases: but that is the price of a cleverer algorithm. It is certainly needed to deal with the use of

\nolinebreak.
70  \if@tempswa \sw@slant \fi
71 \fi

72 }

\t@st@ic The next token in the input stream is stored in \@let@token via a \let, the current token from \nocorrlist is stored via \def in \reserved@a. To compare them we have to fiddle around a bit.

If the only things to check were characters then this could be done via an \if thus their catcodes would not matter; but this will not work whilst \futurelet is used above.

73 \def \t@st@ic {%
74 \expandafter\let\expandafter\reserved@b\expandafter=\reserved@a\relax
75 \ifx\reserved@b\@let@token

If they are the same we record the fact and jump out of the loop.

76  \@tempswafalse
77  \@break@tfor
78 \fi

79 }

\sw@slant \fix@penalty The definition of the mysterious \sw@slant command is as follows.

80 \def \sw@slant {%

It is surely correct to put in an italic correction when there is no skip. If the last thing on the list is actually a zero skip (including things whose dimension part is zero, such as \hfill), or anything other than a sloped character, then the italic correction will have no effect.

In order to work correctly with unbreakable spaces from ~ (and other common forms of line-breaking control) we also move back across a penalty before the glue.

81 \ifdim \lastskip=\z@
82  \fix@penalty
83 \else
84  \skip@ \lastskip
85  \unskip
86  \fix@penalty
87  \hskip \skip@
88 \fi

89 }

The above code means: “If there is a non-zero space just before the current position (\ifdim...) save the amount of that space (\skip@\lastskip), remove it (\unskip), then do a similar thing if there is a penalty just before the skip, and finally put the space back in.”

Since zero glue cannot be distinguished in this context from no glue, we dare not put in an \hskip in this case as this may produce an unwanted breakpoint. This is not satisfactory.

The penalty before the glue is handled similarly, with the same caveats concerning the zero case. Is this the first recorded use of \unpenalty in standard L^{A}TEX code?

90 \def \fix@penalty {%
91 \ifnum \lastpenalty=\z@
92  \@@italiccorr
93 \else
94  \count@ \lastpenalty
95  \unpenalty
96  \@@italiccorr
97  \penalty \count@
98 \fi

99 }

\nocorrlist This holds the list of characters that should prevent italic correction. They should be ordered by decreasing frequency of use. If any such character is made active later on one needs to redefine the list so that the active character becomes part of it.

100 \def \nocorrlist {,.}

\nfss@text This command will by default behave like a L^{A}TEX \mbox but may be redefined by packages such as amstext.sty to be a bit cleverer.

101 \ifx \nfss@text\@undefined
102 \def \nfss@text {\leavevmode\hbox}
103 \fi

\DeclareOldFontCommand This is the function used to create declarative font-changing commands that can

also be used to change alphabets in math-mode.

Usage: \DeclareOldFontCommand \fn{⟨font-change decls⟩} ⟨math-alphabet⟩ Here \fn is the font-declaration command being defined, ⟨font-change decls⟩ is

the declaration it will expand to in text-mode, and ⟨math-alphabet⟩ is the (single) math alphabet specifier which is to be used in math-mode.

It does not care whether the command being defined already exists but it does give a warning if it redefines anything.

Here are some typical examples of its use in conjunction with more basic NFSS2 font commands.

     \DeclareOldFontCommand{\rm}{\normalfont\rmfamily}{\mathrm}
     \DeclareOldFontCommand{\sf}{\normalfont\sffamily}{\mathsf}
     \DeclareOldFontCommand{\tt}{\normalfont\ttfamily}{\mathtt}

104 \def \DeclareOldFontCommand #1#2#3{%
105 \DeclareRobustCommand #1{\@fontswitch {#2}{#3}}%

106 }

\@fontswitch \@@math@egroup \@@math@egroup These two commands actually do the necessary tests and declarative font- or alphabet-changing.

107 \def \@fontswitch #1#2{%
108 \ifmmode
109  \let \math@bgroup \relax
110  \def \math@egroup {\let \math@bgroup \@@math@bgroup
111  \let \math@egroup \@@math@egroup}%

We need to have a \relax in the following line in case the #2 is something like \mathsf grabbing the next token as an argument. For this reason the code also uses explicit arguments again (see pr/1275).

112  #2\relax
113 \else
114  #1%
115 \fi

116 }

117 \let \@@math@bgroup \math@bgroup
118 \let \@@math@egroup \math@egroup

These commands are available only in the preamble.

119 \@onlypreamble \DeclareTextFontCommand
120 \@onlypreamble \DeclareOldFontCommand

3 Initialization

\normalsize This is defined to produce an error.

121 \def\normalsize{%
122 \@latex@error {The font size command \protect\normalsize\space
123  is not defined:\MessageBreak
124  there is probably something wrong with
125  the class file}\@eha

126 } 127 ⟨/2ekernel⟩