7

In beamer, I would like to be able to use the tilde character ~ in the name of a command sequence. I tried with adjusting catcodes. While this was successful with the standard article class, it failed with beamer:

Working article example:

\documentclass{article}
\begin{document}

\section{cs with tilde}

\catcode`\~=12%

\expandafter\def\csname cswith~\endcsname{foo}
cs value:\csname cswith~\endcsname.

\catcode`\~=13%

\end{document}

Beamer example producing Missing \endcsname inserted error:

\documentclass{beamer}
\begin{document}

\begin{frame}{cs with tilde}

\catcode`\~=12%

\expandafter\def\csname cswith~\endcsname{foo}
cs value:\csname cswith~\endcsname.

\catcode`\~=13%

\end{frame}
\end{document}

What am I doing wrong?

Martin Scharrer
  • 262,582
AlexG
  • 54,894
  • 2
    Does it work outside the frame? Also it's safer to do \begingroup\catcode`\~=12 \expandafter … \endgroup, since this will restore the whatever catcode ~ had. – Andrey Vihrov Mar 21 '11 at 09:59
  • Outside it seems to work, at least no error. But I want it to work inside the frame environment too. – AlexG Mar 21 '11 at 10:05
  • 2
    I'm pretty sure the reason is the same as in this question: Conditional compilation of beamer slides. As Martin Scharrer notes there, the frame environment is a pseudo-environment, i.e. actually a macro that reads everything until \end{frame} as an argument. – Hendrik Vogt Mar 21 '11 at 10:09
  • 2
    You must - as with verbatim content - use the fragile option. \begin{frame}[fragile] – Ulrike Fischer Mar 21 '11 at 10:13
  • @Ulrike: this produces Runaway argument? ! File ended while scanning use of \next. <inserted text> \par error, with whatever frame content. fragile is not an option anyway, because I need the problem solved for package writing purposes. (Don't want the user to set the fragile option.) – AlexG Mar 21 '11 at 10:25
  • @Alexander: Using [fragile] works for your minimal example. – Martin Scharrer Mar 21 '11 at 10:32
  • 2
    [fragile] works fine for me and beamer 2010/06/21 development version 3.10 (and it should work fine!). – Ulrike Fischer Mar 21 '11 at 10:36
  • @Ulrike: While it seem not to be what the OP wants, it is a good general solution for catcode changes in beamer frames, so you really should post it as an answer. – Martin Scharrer Mar 21 '11 at 10:42
  • @Martin: fragile is mentioned in your answer and this is quite enough at my opinion. – Ulrike Fischer Mar 21 '11 at 11:08

1 Answers1

13

As Hendik Vogt already mentioned (by citing me) in the question comments this doesn't work because beamer actually reads the content as macro argument and therefore the catcode change comes to late.

One way to solve this is already mentioned by Ulrike Fischer: use the [fragile] option to make beamer process the frame content in a way which allows catcode changes.

You could also define all the code you require outside the frame as a macro while the catcode changes are in effect and then simply use that macro inside the frame. The catcode is important when the ~ is read not when it is executed/processed.

However, I would solve it quite simple: Use \string~ instead to get ~ as a string:

\documentclass{beamer}
\begin{document}

\begin{frame}{cs with tilde}

\expandafter\def\csname cswith\string~\endcsname{foo}%
cs value:\csname cswith\string~\endcsname.

\end{frame}
\end{document}

Note that you can also use \csdef{cswith\string~}{foo} and \csuse{cswidth\string~} if you load the etoolbox package.


Or even simpler: Redefine ~ locally to produce \string~. Then you have to type less if you need it more often. However, any normal ~ inside the frame or used by macros will not work as usual anymore.

\documentclass{beamer}
\begin{document}

\begin{frame}{cs with tilde}

\def~{\string~}%
\expandafter\def\csname cswith~\endcsname{foo}%
cs value:\csname cswith~\endcsname.

\end{frame}
\end{document}
Martin Scharrer
  • 262,582
  • Thanks for your answer. I will use the \def~{\string~} answer approach embedded into a \begingroup \endgroup bracket to limit its effect to the scope of the user command I am writing. – AlexG Mar 21 '11 at 11:25
  • 1
    @Alexander: Why not use \def~{\ifincsname\string~\else\nobreak\ \fi}? I didn't test, but I think that should do the right thing. – TH. Mar 26 '11 at 12:24