Macro only to be defined in math mode
I would not use \everymath
.
\documentclass{article}
\usepackage{letltxmacro}
\makeatletter
\newcommand{\mathdef}[2]{%
\@ifundefined{#1}{\@mathdef@new{#1}{#2}}{\@mathdef@remember{#1}{#2}}
}
\newcommand{\@mathdef@remember}[2]{%
\expandafter\LetLtxMacro
\csname textmode@#1\expandafter\endcsname
\csname #1\endcsname
\expandafter\def\csname mathmode@#1\endcsname{#2}%
\expandafter\DeclareRobustCommand\csname#1\endcsname{%
\ifmmode\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{\csname mathmode@#1\endcsname}{\csname textmode@#1\endcsname}%
}%
}
\newcommand{\@mathdef@new}[2]{%
\expandafter\DeclareRobustCommand\csname#1\endcsname{#2}%
}
\makeatother
\mathdef{d}{\mathop{}\!\mathrm{d}}
\begin{document}
\d{x} is an x with a dot below and $\int f(x) \d x$ is an integral over $x$.
\end{document}
I don't think this is a good way to go, though. It's confusing and prone to errors.
See When to use \LetLtxMacro? for information about \LetLtxMacro
.
It's a bit easier with etoolbox
:
\documentclass{article}
\usepackage{etoolbox}
\makeatletter
\newcommand{\mathdef}[2]{%
\@ifundefined{#1}{\@mathdef@new{#1}{#2}}{\@mathdef@remember{#1}{#2}}
}
\newcommand{\@mathdef@remember}[2]{%
\expandafter\robustify\csname#1\endcsname
\csletcs{textmode@#1}{#1}%
\csdef{mathmode@#1}{#2}%
\protected\csdef{#1}{%
\ifmmode\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{\csuse{mathmode@#1}}{\csuse{textmode@#1}}%
}%
}
\newcommand{\@mathdef@new}[2]{%
\protected\csdef{#1}{#2}%
}
\makeatother
\mathdef{d}{\mathop{}\!\mathrm{d}}
\begin{document}
\d{x} is an x with a dot below and $\int f(x) \d x$ is an integral over $x$.
\end{document}
Why do I use \DeclareRobustCommand
(first version) or \protected
(second version) all around?
When TeX does a write operation it is in no mode at all, in particular it is not in math mode. A simplistic definition such as
\newcommand{\foo}{%
\relax % if this comes first in an alignment
\ifmmode
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
\foo@math\foo@text
}
would always choose \foo@text
if found in a \write
. The above protections make the \mathdef
commands to write themselves, so no choice is made at \write
time.
Why not using \everymath
? Try the following example and see.
\documentclass{article}
\everymath{\let\foo\foomath}
\newcommand{\foo}{Foo}
\newcommand{\foomath}{Ops}
\begin{document}
Text: \foo
Math: $\foo$
Ops: abc\textsuperscript{\foo}
\end{document}
My idea is very similar to egreg's, but I'd like to add an optional argument, so the math command could process arguments itself. The code:
\documentclass{article}
\usepackage{xparse}
\DeclareDocumentCommand{\mathdef}{mO{0}m}{%
\expandafter\let\csname old\string#1\endcsname=#1
\expandafter\newcommand\csname new\string#1\endcsname[#2]{#3}
\DeclareRobustCommand#1{%
\ifmmode
\expandafter\let\expandafter\next\csname new\string#1\endcsname
\else
\expandafter\let\expandafter\next\csname old\string#1\endcsname
\fi
\next
}%
}
\mathdef{\v}[1]{\tilde{#1}}
\mathdef{\d}{\mathrm{d}}
\begin{document}
Ha\v{c}ek and tilde $\v{a}+\v{b}=1$.
\d x is an x with a dot below and $\int f(x) \d x$ is an integral over $x$.
\end{document}
The result:
You wish to use the \PushPostHook
-macro from the everyhook-package for (re)defining macros that process arguments?
Issue 1:
In LaTeX arguments are denoted by #1
and #2
and the like, i.e., by sequences of hashes trailed by a digit in the range 1..9.
When it comes to nesting definitions, hashes need to be doubled for the inner definitions:
\def\outsidemacro#1{%
\def\insidemacro##1{This is insidemacro's argument: ##1.}%
This is outsidemacro's argument: #1.%
}
During expansion, two consecutive hashes will be collapsed into one hash, i.e., the amount of hashes will be halved.
I.e., \outsidemacro{foo}
yields:
\def\insidemacro#1{This is insidemacro's argument: #1.}%
This is outsidemacro's argument: foo.%
Looking at the definition of \PushPostHook
via \show\PushPostHook
yields:
> \PushPostHook=\protected\long macro:
#1#2->\eh@checkhook {#1}\PushPostHook \letcs \eh@tempi {eh@post#1}\expandafter
\gdef \csname eh@post#1\expandafter \endcsname \expandafter {\eh@tempi \eh@hook
separator #2}\undef \eh@tempi .
As you can see, the tokens are kept in macros whose names are of pattern
\eh@post⟨name of hook⟩
.
E.g., \eh@postmath
and \eh@postdisplay
.
For adding tokens to such a macro, \PushPostHook
lets the macro in question equal to \eh@tempi
and then redefines the macro in question by appending the tokens in question behind the expansion of \eh@tempi
.
Expanding \eh@tempi
is a crucial point:
In case the definition of \eh@tempi
contains hashes (#
), during expansion two consecutive hashes will collapse into one of them.
This implies:
Whenever \PushPostHook
is called for adding things to \eh@postmath
or \eh@postdisplay
, the amount of consecutive hashes with things that are already in \eh@postmath
or \eh@postdisplay
will be halved.
This will be a problem especially when calling \PushPostHook
several times for adding things to \eh@postmath
or \eh@postdisplay
.
You can avoid the halving of the amount of consecutive hashes by maintaining things by means of a token register because when the content of a token register is "spit out" via \the
, the amount of hashes will not be reduced. When "spitting out" due to \the
takes place during \edef
, the amount of hashes will not only be not reduced but it will be doubled.
If you do, e.g.,
\myscratchtoks{#}
\edef\mymacro{\the\myscratchtoks}
, in the definition of \mymacro
the amount of hashes coming from \myscratchtoks
will be doubled. When expanding \mymacro
, that doubled amount will be halved and thus the expansion of \mymacro
delivers the same amount of hashes as would be delivered by \the\myscratchtoks
.
Therefore I suggest adding things to a token-register and using \PushPostHook
only for "flushing" that token-register.
Issue 2:
If you wish to maintain macros that can also process arguments, I suggest implementing something that can be used similarly to the prefixes \long
or \global
.
In the example below I used #{
-notation for implementing a macro \mathcommand
which processes left-brace-delimited arguments that are trailed by brace-nested arguments. As the ⟨definition text⟩
of a macro always is to be nested in braces, you can use the processing of left-brace-delimited-arguments for fetching all tokens that come before a ⟨definition text⟩
.
Such tokens can be the definition-command itself (e.g., \renewcommand*
or \global\long\def
), the control-sequence-token that is to be (re)defined, and the ⟨parameter text⟩
.
E.g., with
\mathcommand\renewcommand*\mymacrowitharguments[2]{%
\mbox{math-arg~1: }(#1)
\mbox{ math-arg~2: }(#2)
}%
, \mathcommand
's first (left-brace-delimited) argument will be the sequence \renewcommand*\mymacrowitharguments[2]
and
its second argument is formed by the stuff that is nested inside braces: \mbox{math-arg~1: }(#1) \mbox{ math-arg~2: }(#2)
.
\mathcommand
will add the sequence ⟨first argument⟩{⟨second argument⟩}
, i.e., the sequence \renewcommand*\mymacrowitharguments[2]{\mbox{math-arg~1: }(#1) \mbox{ math-arg~2: }(#2) }
to the token-register \mymathhooktoks
.
I also implemented a macro \mathcommandfromname
which also fetches a left-brace-delimited argument and takes the stuff that is behind that argument and that therefore is nested in braces for the name of a control-sequence-token which can be formed via \csname..\endcsname
:
E.g.,
\mathcommandfromname\renewcommand*{mymacrowitharguments}[2]{%
\mbox{math-arg~1: }(#1)
\mbox{ math-arg~2: }(#2)
}%
yields:
\mathcommand\renewcommand*\mymacrowitharguments[2]{%
\mbox{math-arg~1: }(#1)
\mbox{ math-arg~2: }(#2)
}%
\documentclass{article}
\usepackage{everyhook}
\newtoks\myscratchtoks
\newcommand\mymathhookmacro{}%
\PushPostHook{math}{\mymathhookmacro}%
\PushPostHook{display}{\mymathhookmacro}%
\newcommand{\mathcommand}{}%
\long\def\mathcommand#1#{\innermathcommand{#1}}%
\newcommand{\innermathcommand}[2]{%
\begingroup
\expandafter\myscratchtoks\expandafter{\mymathhookmacro#1{#2}}%
\xdef\mymathhookmacro{\the\myscratchtoks}%
\endgroup
}
\newcommand\exchange[2]{#2#1}%
\newcommand\mathcommandfromname{}%
\long\def\mathcommandfromname#1#{\romannumeral0\innermathcommandfromname{#1}}%
\newcommand\innermathcommandfromname[2]{%
\expandafter\exchange\expandafter{\csname#2\endcsname}{ \mathcommand#1}%
}%
%----------------------------------------------------------------
\newcommand*\mymacrowitharguments[2]{%
non-math-arg~1: \textbf{(#1)} %
non-math-arg~2: \textbf{(#2)}%
}%
\mathcommand\renewcommand*\mymacrowitharguments[2]{%
\mbox{math-arg~1: }(#1)
\mbox{ math-arg~2: }(#2)
}%
\newcommand*\myothermacrowitharguments[2]{%
other-non-math-arg~1: \textbf{(#1)} %
other-non-math-arg~2: \textbf{(#2)}%
}%
\mathcommandfromname\renewcommand*{myothermacrowitharguments}[2]{%
\mbox{other-math-arg~1: }(#1)
\mbox{ other-math-arg~2: }(#2)
}%
\mathcommand\renewcommand*\d{\mathrm{d}}%
\parindent=0ex
\begin{document}
\d x is an x with a dot below and $\int f(x) \d x$ is an
integral over $x$.
\bigskip
Testing with \verb|\mymacrowitharguments|:\smallskip
outside math:\\
\mymacrowitharguments{arg A}{arg B}
\smallskip
inside math:\\
$\mymacrowitharguments{arg A}{arg B}$
\bigskip
Testing with \verb|\myothermacrowitharguments|:\smallskip
outside math:\\
\myothermacrowitharguments{arg A}{arg B}
\smallskip
inside math:\\
$\myothermacrowitharguments{arg A}{arg B}$
\end{document}