5

If you define \bletter with \DeclareRobustCommand\bletter[1]{\textbf{#1}} it works fine even within section commands. But if you want to use it in an \edef or \xdef command, \bletter will be broken (except if you define \let\protect\noexpand). That means:

\xdef\boldyletter{\bletter{y}} will throw an error message.

Is there any command to define always unbreakable commands?

4 Answers 4

9

You can use

\NewDocumentCommand\bletter{m}{\textbf{#1}} 

which makes an e-tex \protected definition which does not expand in an edef.

But you should never use \xdef on unknown latex input, use \protected@xdef then LaTeX robust commands will be protected.

7

Simply use \protected\def primitive for declaration of your \bletter macro:

\protected\def\bletter#1{\textbf{#1}}

The \protected macros are not expanded during \edef, \xdef, \write, \message etc.

0

Sorry to answer my own question, but I have no idea how to share my solution with the community.

\def\RJDeclareRobustCommand#1% #1 name of new command, #2 same instructions as \newcommand
 {%
  \gdef#1%
   {%
    \begingroup%
     \let\relax\aftergroup% this has to be redefined before processing \csname @\string#1\endcsname
     \ifx\aftergroup\relax% this is false in expandations
      \expandafter\aftergroup\csname RJ@\expandafter\@gobble\string#1\endcsname%
     \else%  \expandafter\aftergroup\expandafter\noexpand\csname\expandafter\@gobble\string#1@RJ\endcsname%
     \fi%
    \endgroup%
   }%
  \expandafter\gdef\csname\expandafter\@gobble\string#1@RJ\endcsname%
   {%
    \begingroup%
     \let\relax\aftergroup% this has to be redefined before processing \csname @\string#1\endcsname
     \ifx\aftergroup\relax% this is false in expandations
      \expandafter\aftergroup\csname RJ@\expandafter\@gobble\string#1\endcsname%
     \else%
      \expandafter\aftergroup\expandafter\aftergroup\expandafter\aftergroup%
       \expandafter\noexpand\csname\expandafter\@gobble\string#1@RJ\endcsname%
     \fi%
    \endgroup%
   }%
%  read the instructions (see \new@command)
  \expandafter\new@command\csname RJ@\expandafter\@gobble\string#1\endcsname%
 }%
%

\RJDeclareRobustCommand\bletter[1]{\textbf{#1}} will be robust.

\xdef\boldyletter{\bletter{y}} works fine even in the command \xdef\boldxyletter{x\boldyletter}}.

2
  • 1
    sorry this doesn't work (either of the other two answers will work in section headings etc) \tableofcontents \section{\bletter{x}} will put \begingroup \let \relax \aftergroup \endgroup {x}}{1} in the aux file and the \textbf is lost. Apr 24 at 20:32
  • 1
    similarly your definition gives no error but is \begingroup \let \relax \aftergroup \endgroup {y} so no bold. and the leading \begingroup \let \relax \aftergroup \endgroup isn't always safe eg in messages etc a robust command should appear as itself. Apr 24 at 20:35
0

Many thanks for the very helpful answers. They were also a challenge for me, which I gladly accepted.

In order to use a new command in a chapter heading, it is necessary, among other things, to add and redefine the command in \pdfstringdef. This was not taken into account in my old code. When adding this requirement, I was also able to optimise the code.

Below is a test example with the new code. New commands, not their arguments, will be ignored in bookmarks.

\documentclass[a4paper,12pt]{report}
\RequirePackage[pdftex,colorlinks,linkcolor=blue,%
                urlcolor=blue,bookmarksnumbered]{hyperref}
%
\makeatletter
%
\let\RJ@aftergroup\aftergroup%
\let\RJ@begingroup\begingroup%
\let\RJ@endgroup\endgroup%
\let\RJ@let\let%
%
\@ifundefined{pdfstringdefPreHook}{}%
 {%
  \gdef\Addpdfstringdef#1%
   {%
    \global\@temptokena\expandafter%
     {\pdfstringdefPreHook#1}%
    \xdef\pdfstringdefPreHook{\the\@temptokena}%
   }%     
%     
  \Addpdfstringdef%
   {%
    \let\RJ@aftergroup\@empty%
    \let\RJ@begingroup\@empty%
    \let\RJ@endgroup\@empty%
    \let\RJ@let\@empty%%
   }%  
 }% 
%
\def\RJ@DRCentry#1%
 {%
  \RJ@begingroup%
   \RJ@let\relax\RJ@aftergroup%
   \ifx\RJ@aftergroup\relax% 
    \expandafter\RJ@aftergroup\csname RJ@\expandafter\@gobble\string#1\endcsname%
   \else%
    \expandafter\noexpand\csname RJ\expandafter\@gobble\string#1JR\endcsname%
   \fi%
  \RJ@endgroup%
 }%
%
\def\RJ@DeclareRobustCommand#1% #1 name of new command, #2 same instructions as \newcommand
 {%
  \gdef#1%
   {%
    \ifx\RJ@aftergroup\@empty%
    \else%
     \expandafter\RJ@DRCentry\expandafter#1%  
    \fi%
   }%
%
  \expandafter\gdef\csname RJ\expandafter\@gobble\string#1JR\endcsname%
   {%
    \ifx\RJ@aftergroup\relax%
     \gdef\next{\RJ@DRCentry{#1}}%
     \RJ@aftergroup\next%
    \else%
     \expandafter\noexpand\csname RJ\expandafter\@gobble\string#1JR\endcsname%
    \fi%
   }%
%
  \@ifundefined{pdfstringdefPreHook}{}%
   {%
    \expandafter\Addpdfstringdef\expandafter%
     {\expandafter\let\csname RJ\expandafter\@gobble\string#1JR\endcsname\@empty}%
     }%
    \expandafter\new@command\csname RJ@\expandafter\@gobble\string#1\endcsname%
 }%
%
\RJ@DeclareRobustCommand\iletter[1]{\textit{\huge #1}}%
%
\xdef\yiletter{\iletter{y}}%
\xdef\xyiletter{\iletter{x}\yiletter}%
\xdef\xyziletter{\xyiletter\iletter{z}}%
\xdef\jiletter{\iletter{j\iletter{i}}}%

\begin{document}

 \tableofcontents

 \newpage

 test \iletter{j\iletter{i}}, \jiletter{} test \iletter{a}, \yiletter, \xyiletter, \xyziletter{} test

 \section{italic \iletter{y}, \xyziletter}

  The following chapter heading is for comparison purposes only .

 \section{italic \textit{\huge y}, \textit{\huge xyz}}

  more text

\end{document}
1
  • why post a new answer rather than fix your first answer which did not work? as my or wipet's answer shows you can simply make the original csname protected then none of this aftergroup code is needed. Apr 29 at 20:08

You must log in to answer this question.

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