14

Why does the following not work at all?

\documentclass{article}

\makeatletter
\newcommand{\foo}[1]{\@ifstar{\textbf{#1}}{\textit{#1}}}
\makeatother

\begin{document}

\foo{test}
\foo*{test}

\end{document}

The output seems to be "test" written correctly as italicized for the non-star variant and "*test" ("test" written normally with no bold weight, "*" written italicized) written for the star variant.

25

The reason is that with \foo*{test} * is the argument for \foo and {test} is just the word text in a group. \foo must be a macro without argument, which calls another macro with argument

\documentclass{article}

\makeatletter
\newcommand{\foo}{\@ifstar{\@foob}{\@fooi}}
\newcommand{\@foob}[1]{\textbf{#1}}
\newcommand{\@fooi}[1]{\textit{#1}}
\makeatother

\begin{document}

\foo{test}
\foo*{test}

\end{document}
  • Of course, the definition of \foo could be simplified as in the other answers. But this answer is valuable because it covers the general case, if the code arguments of \@ifstar are more complex than a simple \textbf or \textit. – Heiko Oberdiek Jun 22 '17 at 22:37
  • 1
    I marked this as the answer because the original issue I had was with redefining \section, and I came up with \textbf vs \textit as a better minimal example, which coincidentally had a better solution not applicable to my problem. – thkim1011 Jun 22 '17 at 22:55
15

Macro \foo is defined with one argument. If it is called as \foo*{test}, then the star becomes the argument (#1); then \foo is expanded and \@ifstar is called. But the following token { is not a star. The argument, the star, is then set as \textit{*}. The processing of \foo is finished and {test} is interpreted as group with the word test inside.

The example can be fixed the following way:

\documentclass{article}

\makeatletter
\newcommand*{\foo}{\@ifstar\textbf\textit}
\makeatother

\begin{document}

\foo{test}
\foo*{test}

\end{document}

Result

Macro \foo is defined without argument, thus that \@ifstar can look for a following star. Then the code in the arguments for "with star" and "without star" of \@ifstar read the following argument.

If the code in the argument of \@ifstar is more complicate, then the more general answer of Mike helps.

9

In your definition the argument has already been read before the \@ifstar comes into the picture. So you would have to put the star behind the argument (remaek that it eats a space::

\documentclass{article}

\makeatletter
\newcommand{\foo}[1]{\@ifstar{\textbf{#1}}{\textit{#1}}}
\makeatother

\begin{document}

\foo{test}
\foo{test}*

\end{document}

enter image description here

But what you want is probably this:

\documentclass{article}

\makeatletter
\newcommand{\foo}{\@ifstar\textbf\textit}
\makeatother

\begin{document}

\foo{test}
\foo*{test}

\end{document}

enter image description here

8

As you have it, with \foo* the * is already consumed as #1, use:

\documentclass{article}

\makeatletter
\newcommand{\foo}{\@ifstar{\textbf}{\textit}}
\makeatother

\begin{document}

\foo{test}
\foo*{test}

\end{document}
8

With xparse it would be:

\usepackage{xparse}
\NewDocumentCommand\foo{sm}{\IfBooleanTF{#1}{\textbf{#2}}{\textit{#2}}}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.