10

The MWE below

However, when the ! is active within the \hcancel compilation seems to hang?


The desired output is:

enter image description here

but if I uncomment the code intend to produce the the last canceled term the compilation seems to hang.

Code:

\documentclass{article}
\usepackage{amsmath}
\usepackage{xcolor,etoolbox}
\usepackage{tikz}
\usetikzlibrary{calc}

\makeatletter %% https://tex.stackexchange.com/questions/299798/make-characters-active-via-macro-in-math-mode \newcommand{\DeclareMathActive}[2]{% % #1 is the character, #2 is the definition \expandafter\edef\csname keep@#1@code\endcsname{\mathchar\the\mathcode#1 } \begingroup\lccode~=#1\relax \lowercase{\endgroup\def~}{#2}% \AtBeginDocument{\mathcode#1="8000 }% }

\newcommand{\std}[1]{\csname keep@#1@code\endcsname} \patchcmd{\newmcodes@}{\mathcode\-\relax}{\std@minuscode\relax}{}{\ddt} \AtBeginDocument{\edef\std@minuscode{\the\mathcode-}} \makeatother

\DeclareMathActive{!}{\mathclose{\textcolor{blue}{\std{!}}}}

%% https://tex.stackexchange.com/questions/20643/diagonal-strikeout-starting-too-low-and-ending-too-high \newcommand{\hcancel}[5]{% \tikz[baseline=(tocancel.base)]{ \node[inner sep=0pt,outer sep=0pt] (tocancel) {#1}; \draw[red] ($(tocancel.south west)+(#2,#3)$) -- ($(tocancel.north east)+(#4,#5)$); }% }%

\begin{document}

Active ! works: $3!$

Cancel with non-active ! works: \hcancel{$3\std{!}$}{-3pt}{0pt}{3pt}{0pt}

\medskip Combine cancel with active ! hangs: %\hcancel{$3!$}{-3pt}{0pt}{3pt}{0pt}% <-- This hangs!!

\end{document}

Peter Grill
  • 223,288
  • 1
    As part of its workarounds connected to babel, TikZ changes the meaning of the active ! to \tikz@nonactiveexlmark, which expands to a ! with category code 12, which then expands to \tikz@nonactiveexlmark, which… – egreg May 12 '16 at 21:30

1 Answers1

5

You're being very unlucky.

The French module for babel makes ! into an active character, in order to implement the French conventions about punctuation. Therefore, since the beginning, TikZ takes precautions against this, because it uses ! in its syntax. Therefore it assigns a new meaning to the active ! in case French is being used.

It essentially does

\begingroup\lccode`~=`! \lowercase{\endgroup\def~}{\tikz@nonactiveexlmark}
\edef\tikz@nonactiveexlmark{\string!}

Similarly for ;, : and |. So in a tikzpicture environment the assigned meaning \mathclose{\textcolor{blue}{\std{!}}} is lost. Worse, when ! is math active, TeX enters an infinite loop:

  • ! in math mode is treated as if it were active, so it is replaced by its meaning \tikz@nonactiveexlmark

  • \tikz@nonactiveexlmark is replaced by its meaning, a ! with category code 12

  • ! in math mode is treated as if it were active, so it is replaced by its meaning \tikz@nonactiveexlmark

Since you're not using French, you can redefine \tikz@nonactiveexlmark do to the same as the math active !.

\documentclass{article}
\usepackage{amsmath}
\usepackage{xcolor,etoolbox}
\usepackage{tikz}
\usetikzlibrary{calc}

\makeatletter
%% http://tex.stackexchange.com/questions/299798/make-characters-active-via-macro-in-math-mode
\newcommand{\DeclareMathActive}[2]{%
  % #1 is the character, #2 is the definition
  \expandafter\edef\csname keep@#1@code\endcsname{\mathchar\the\mathcode`#1 }
  \begingroup\lccode`~=`#1\relax
  \lowercase{\endgroup\def~}{#2}%
  \AtBeginDocument{\mathcode`#1="8000 }%
}

\def\tikz@nonactiveexlmark{\mathclose{\textcolor{blue}{\std{!}}}}

\newcommand{\std}[1]{\csname keep@#1@code\endcsname}
\patchcmd{\newmcodes@}{\mathcode`\-\relax}{\std@minuscode\relax}{}{\ddt}
\AtBeginDocument{\edef\std@minuscode{\the\mathcode`-}}
\makeatother

\DeclareMathActive{!}{\mathclose{\textcolor{blue}{\std{!}}}}



%% http://tex.stackexchange.com/questions/20643/diagonal-strikeout-starting-too-low-and-ending-too-high
\newcommand{\hcancel}[5]{%
    \tikz[baseline=(tocancel.base)]{
        \node[inner sep=0pt,outer sep=0pt] (tocancel) {#1};
        \draw[red] ($(tocancel.south west)+(#2,#3)$) -- ($(tocancel.north east)+(#4,#5)$);
    }%
}%

\begin{document}

Active ! works: $3!$

Cancel with non-active ! works: 
\hcancel{$3\std{!}$}{-3pt}{0pt}{3pt}{0pt}

\medskip
Combine cancel with active ! hangs: 
\hcancel{$3!$}{-3pt}{0pt}{3pt}{0pt}% <-- This hangs!!

\end{document}

The text now tells a lie. ;-)

enter image description here

egreg
  • 1,121,712
  • Wow, those darn French go and make things complicated! :-) I would have thought since these are active only in math mode, that I would not run into such problems - oh, well. So, what would I need to do for the other characters, especially the : and|. Don't think I'll have an issue with the ;. – Peter Grill May 12 '16 at 22:09
  • @PeterGrill The same as for !, I'd say. – egreg May 12 '16 at 22:12