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}

#1
for the macro:\newcommand{\mathdef}[2]{% \PushPostHook{math}{\def#1{#2}}% \PushPostHook{display}{\def#1{#2}}}
and then use\mathdef{\d}{\mathrm{d}}
, it is not required to use\csname
here. – Martin Scharrer♦ Mar 1 '19 at 12:05\md
for a differential. Or, especially for short substitutions, don't use macros at all, because they make the text less readable, for example\vec v
or\vec{v}
are immediately clear to yourself and possibly others, while for\v
you need to remember or look up the definition somewhere - and it is not that much extra typing. – Marijn Mar 1 '19 at 12:13\md
for the differential is not really mnemonic, and maybe trying to do this in a consistent way, you run into other clashes. Second, writing explicitly\vec v
and stuff like that is usually ok for short documents (and I do that myself), but for longer ones and long formulas it can become cumbersome. Sometimes, you don't see the formula anymore for all the\vec
s,\mathbb
s,\mathcal
s and so on, and I also find it annoying when I want to put the variable into a sub- or superscript and I always have to enclose it in curly braces. – Elmar Zander Mar 4 '19 at 9:32\let\Hungarumlaut\H\renewcommand{\H}{\mathcal{H}}
My thinking is that I don't use the Hungarumlaut that much, so it isn't too much of an inconvenience to typeErd\Hungarumlaut os
– Matthew Leingang Mar 5 '19 at 17:51