9

I am trying to make characters active in math mode, but can't seem to get past the most basic of examples. I would like to define a macro which is passed:

  1. the character to make active and

  2. the macro that should be executed once that macro is encountered.

The MNWE below attempts to make =, + and ! active and color code them. The desired output is that those characters get colored in math mode as. Thus, the input

a=+b $c=+4+d+3!$ e=+f

yields:

enter image description here

where the characters are not altered outside of math mode (the leading a=+b and trailing e=+f).

Notes:

  • There is a separate, but related (as it is in the context of active characters) question in the \MyPlus macro to detect a binary addition + versus a unary positive +. Perhaps that should be a separate question?

Related Questions:

Code (non-working):

\documentclass{article}
\usepackage{mathtools}
\usepackage{xparse}
\usepackage{xcolor}

\NewDocumentCommand{\MakeActiveChar}{%
    m% char to make active
    m% code to execute for this character
}{%
    \catcode`\#1=13\relax%
    \def#1{#2}%
}%

\let\OldEqual=
\newcommand*{\MyEqual}[1][green]{\mathrel{\textcolor{#1}{\OldEqual}}}%

\let\OldPlus+
\newcommand*{\MyPlus}[1][blue]{%
    %\catcode`\+=12% reset catcode so we can use it (not needed with \OldPlus?)
    %% Perhaps this if-then construct should be a separate question?
    %% if binary addition operator
        \mathbin{\textcolor{#1}{\OldPlus}}%
    %% if unary positive operator
    %%  \mathrel{\textcolor{red}{\OldPlus}}%
}%

\let\OldFactorial!
\newcommand*{\MyFactorial}{\textcolor{brown}{\OldFactorial}}%

\everymath{%
    \MakeActiveChar{=}{\MyEqual}%
    \MakeActiveChar{+}{\MyPlus}%
    \MakeActiveChar{!}{\MyFactorial}%
}%

\begin{document}
The ``math'' outside here is just to test that characters are active \emph{only} in math mode:

a=+b $c=+4+d+3!$ e=+f 
\end{document}
4
  • Perhaps that question about binary should indeed be a different question :)
    – Manuel
    Commented Mar 19, 2016 at 10:13
  • For the colour changing, can I point out this question: tex.stackexchange.com/q/335/86 Based on this, I had a working method that I used happily for many years. Commented Mar 19, 2016 at 12:44
  • @PeterGrill If you want a working implementation, just ask. Commented Mar 19, 2016 at 13:45
  • Follow-up Question: Active ! Character Hangs within TikZ Commented May 12, 2016 at 21:20

3 Answers 3

10

You have to be careful with the declarations if you load amsmath; in the body of the definition, use \std{<char>} where you need the old meaning.

\documentclass{article}
\usepackage{amsmath}
\usepackage{xcolor,etoolbox}

\makeatletter
\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{+}{\mathbin{\textcolor{blue}{\std{+}}}}
\DeclareMathActive{!}{\mathclose{\textcolor{brown}{\std{!}}}}
\DeclareMathActive{-}{\mathbin{\textcolor{red}{\hat{\std{-}}}}}

\begin{document}

a=+b $c=+4+d+3!-1$ e=+f

\end{document}

Don't do \let\OldPlus=+.

enter image description here

With Unicode engines (xelatex or lualatex), the patch must be done differently. Here's a version that copes with all engines.

\documentclass{article}
\usepackage{amsmath}
\usepackage{xcolor,etoolbox}
\usepackage{iftex}

\makeatletter
\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}
\iftutex
  \patchcmd{\newmcodes@}{\Umathcodenum `\-\relax}{\std@minuscode\relax}{}{\ddt}
\else
  \patchcmd{\newmcodes@}{\mathcode`\-\relax}{\std@minuscode\relax}{}{\ddt}
\fi
\AtBeginDocument{\edef\std@minuscode{\the\mathcode`-}}
\makeatother


\DeclareMathActive{+}{\mathbin{\textcolor{blue}{\std{+}}}}
\DeclareMathActive{!}{\mathclose{\textcolor{brown}{\std{!}}}}
\DeclareMathActive{-}{\mathbin{\textcolor{red}{\hat{\std{-}}}}}

\begin{document}

a=+b $c=+4+d+3!-1$ e=+f

\end{document}
8
  • Why does the - require special handling? Are there other characters that require special processing? Commented Mar 19, 2016 at 11:01
  • @PeterGrill I made a better fix.
    – egreg
    Commented Mar 19, 2016 at 11:14
  • You surely know that \expandafter\mathchardef\csname keep@#1@code\endcsname=\mathcode`#1 does similar work like your \edef.
    – wipet
    Commented Mar 19, 2016 at 13:43
  • 1
    Due to \newmcodes@ having been recently changed in amsopn.sty to better behave with Unicode engines, this (the patch) won't work with XeLaTeX/LuaLaTeX.
    – user4686
    Commented May 13, 2016 at 9:08
  • 1
    @Bolpat Added the modified version.
    – egreg
    Commented Apr 15, 2020 at 22:15
4

You can define \mathdef declarator and then use it:

\input opmac \localcolor

\def\mathdef#1{\mathcode`#1="8000 \bgroup \lccode`~=`#1\lowercase{\egroup\def~}}

\mathdef +{\mathbin{\Red\mathchar`+}}
\mathdef ={\mathrel{\Green\mathchar`=}}

aha + $a+b+c=d$

\bye

The \input opmac is here only for setting colors \Red, \Green etc. If you are using another macro for colors then use only the second line \def\mathdef... in your macros.

2
  • 1
    You surely know that \mathord{\mathchar`.} and \mathpunct{\mathchar`,} are different from . and , in math mode. Also \mathbin{\mathchar`-} is quite different from -. Period and comma are taken from the math letters font, whereas the minus is taken from the symbol font.
    – egreg
    Commented Mar 19, 2016 at 10:49
  • When I attempted to use this I got Illegal parameter number in definition of \mathdef. Commented Mar 19, 2016 at 11:03
3

There are a few problems:

\MakeActiveChar does \def#1{#2} which is not permitted since #1 is a character that is not active. Here's an alternative with The \lowercase trick

\NewDocumentCommand\MakeActiveChar{mm}
  {\begingroup\lccode`\~=`#1\lowercase{\endgroup\def~}{#2}%
   \catcode`#1=12 \mathcode`#1="8000 }

Apart from that, you have a missing = in a \let. The first equal is optional, so \let\a=\b is correct, the equal, however, is necessary when you want to let to = because if not, it would be treated as the optional one, so

\let\originalequal=

should be

\let\originalequal==

And the last part is that by making a character active in math mode, and then doing \newcommand\plus{\mathbin{\originalplus}} you get an endless loop like \def\a{\a}, so you need to use for instance \mathchar`\+ or \mathchar`+ instead.

Complete solution

\documentclass{article}
\usepackage{mathtools}
\usepackage{xparse}
\usepackage{xcolor}

\NewDocumentCommand\MakeActiveChar{mm}
  {\begingroup\lccode`\~=`#1\lowercase{\endgroup\def~}{#2}%
   \catcode`#1=12 \mathcode`#1="8000 }

\newcommand*\mathcolor[2]{\begingroup\color{#1}#2\endgroup}

\newcommand*\equal[1][green]{\mathrel{\mathcolor{#1}{\mathchar`\=}}}
\newcommand*\plus[1][blue]{\mathbin{\mathcolor{#1}{\mathchar`\+}}}
\newcommand*\factorial{\mathord{\mathcolor{brown}{\mathchar`\!}}}

\everymath{%
  \MakeActiveChar{=}{\equal}%
  \MakeActiveChar{+}{\plus}%
  \MakeActiveChar{!}{\factorial}%
}

\begin{document}
The ``math'' outside here is just to test that characters are active \emph{only} in math mode:

a=+b $c=+4+d+3!$ e=+f 
\end{document}

By the way, I defined \mathcolor because \textcolor works with \bgroup/\egroup which create an ord atom.

4
  • Can you post a compilable MWE? I get Missing \begin{document} when I replace my definition of \MakeActiveChar with yours. Also, can you explain why you suggest the double equal? If I use the double equal as you suggest, along with your ``\MakeActiveChar, I get TeX capacity exceeded, sorry [grouping levels=255]`. Commented Mar 19, 2016 at 10:26
  • Okey, sorry, I just did it without trying, and the error comes from somewhere else. I'll edit.
    – Manuel
    Commented Mar 19, 2016 at 10:28
  • Still not a compilable MWE. And again I get LaTeX Error: Missing \begin{document} when I replace your \MakeActiveChar in the MWE I posted in the question. Commented Mar 19, 2016 at 10:52
  • 1
    Sorry about the missing compilable example. The point about \std@minus in egreg answer is interesting, don't miss it.
    – Manuel
    Commented Mar 19, 2016 at 10:54

You must log in to answer this question.

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