Make Characters Active via Macro in Math Mode
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=+
.
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}
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.
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.