24

In my document, I'm often setting upper case words and abbreviations in small caps because it avoids breaking the flow (which upper case words does). Also, many words (like CUDA, for instance) are also entered as commands instead of directly as text.

Up to this point I have manually set these words in small caps where appropriate (like \textsc{\cuda}), but this becomes unnecessarily repetitive. What I would like to be able to do is to define a command like \cuda which prints CUDA in small caps where the text "mode" is normal roman, and sets CUDA in upper cases if the text mode is italics. The reason for doing this is the font I'm using doesn't support small caps in italics.

Hence I would like to be able to detect which text "mode" is currently in use, and act accordingly.

I've included a minimal example below to illustrate my point:

\documentclass{article}

\usepackage{textcase}

\newcommand{\cudaString}{CUDA}
\newcommand{\cuda}{\textsc{\MakeTextLowercase{\cudaString}}}

\begin{document}
Set \cuda in small caps here,
\itshape but do not set \cuda in small caps here.
\end{document}
5
  • 1
    There's little point in \newcommand{\cuda}{\textsc{CUDA}}, as it will appear in all caps anyway; it's probably \textsc{cuda}, isn't it?
    – egreg
    Oct 15, 2011 at 19:25
  • Ah of course; I forgot that in my code I use \MakeTextLowercase and I wrote the example code just from memory.
    – gablin
    Oct 17, 2011 at 8:51
  • So it would be better to show a real example, as solutions with \MakeUppercase might have problems.
    – egreg
    Oct 17, 2011 at 8:57
  • Probably. I've updated the example accordingly.
    – gablin
    Oct 17, 2011 at 9:07
  • Related: tex.stackexchange.com/questions/163991/…
    – jub0bs
    Mar 6, 2014 at 12:17

3 Answers 3

37

LaTeX's 'New Font Selection Scheme' (NFSS) stores information about the font in a number of macros. The macro \f@shape stores the shape: n for upright, it for italic and sc for small caps. \f@series stores the series: m for mid-weight and bx for bold, while \f@family stores the family: something like cmr for roman, cmss for sanserif and cmtt for monospaced (it's dependent on the current font).

Thus you can test for small caps using

\makeatletter
\newcommand*{\IfSmallCapsTF}{%
  \ifx\f@shape\my@test@sc
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}
\newcommand*{\my@test@sc}{sc}
\makeatother

 \IfSmallCapsTF{true-code}{false-code}
4
  • I would actually like to accept two answers - this on and egreg's - as I incorporated both to make a command which sets its argument in small caps if the current style is roman, fake small caps if it is italics, and otherwise just converts it to upper case.
    – gablin
    Oct 17, 2011 at 13:18
  • 1
    I'm wondering... Do you really have to define a command that expands to sc? Or is that name already stored in some kernel macro?
    – jub0bs
    Mar 6, 2014 at 11:22
  • @Jubobs That I know of latex.ltx doesn't provide any useful shortcuts for these. Of course, with an up-to-date engine you can use \pdfstrcmp or similar for the test (\ifx likely faster if used many times).
    – Joseph Wright
    Mar 6, 2014 at 12:01
  • @JosephWright Thanks. I need to perform a test on the current font shape, but I was wondering whether I was "reinventing the wheel" by defining those macros.
    – jub0bs
    Mar 6, 2014 at 12:05
8

You may want to fake an italic small caps font:

\makeatletter
\DeclareRobustCommand{\SCorIT}[1]{%
  \ifdim\fontdimen\@ne\font>\z@
    \begingroup\check@mathfonts
    \fontsize\sf@size\z@\selectfont
    \MakeUppercase{#1}\endgroup
  \else
    \textsc{#1}%
  \fi
}
\makeatother

\newcommand{\cuda}{\SCorIT{cuda}}

Depending on the font the result can turn out to be as desired. Beware that for bold face another test must be added.

enter image description here

If you use \MakeLowercase or textcase's \MakeTextLowercase for defining the acronym, you should modify the definition into

\makeatletter
\DeclareRobustCommand{\SCorIT}[1]{%
  \ifdim\fontdimen\@ne\font>\z@
    \begingroup\check@mathfonts
    \fontsize\sf@size\z@\selectfont
    \let\MakeTextLowercase\@firstofone % for textcase
    \let\MakeLowercase\@firstofone     % for standard LaTeX
    \MakeTextUppercase{#1}\endgroup
  \else
    \textsc{#1}%
  \fi
}
\makeatother

that will avoid accumulating case changes.

The example was generated with the following code:

\documentclass{standalone}
\usepackage{textcase}
\makeatletter
\DeclareRobustCommand{\SCorIT}[1]{%
  \ifdim\fontdimen\@ne\font>\z@
    \begingroup\check@mathfonts
    \fontsize\sf@size\z@\selectfont
    \let\MakeTextLowercase\@firstofone
    \MakeTextUppercase{#1}\endgroup
  \else
    \textsc{#1}%
  \fi
}
\makeatother

\newcommand{\cudaString}{CUDA}
\newcommand{\cuda}{\SCorIT{\MakeTextLowercase{\cudaString}}}

\begin{document}

\hbox{Set \cuda{} in small caps here,\strut}
\hbox{\itshape but do not set \cuda{} in small caps here.\strut}

\end{document}
2
  • Could you please extend it to a minimal example? I keep getting compilation errors when I try to use it in my document.
    – gablin
    Oct 17, 2011 at 13:00
  • My apologies. I must have done something wrong the first time, because now I got it running.
    – gablin
    Oct 17, 2011 at 13:12
3

Stealing a bit from the definition of \em (seen using latexdef em), we can create a command \SCorUC that typesets its argument in small caps or uppercase depending on context:

\makeatletter
\newcommand{\SCorUC}[1]{\ifdim\fontdimen\@ne\font>\z@\MakeUppercase{#1}\else\textsc{#1}\fi}
\makeatother
\newcommand{\cuda}{\SCorUC{cuda}}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .