我希望能够将代码插入到我的自定义宏的定义中,而不必修改每个宏定义。这看起来像是重新定义的简单情况\newcommand
,但结果却不那么容易(至少对我来说)。我最终得到:
\MacroB 定义中的参数编号非法。
需要重新读取
1 l.45 \newcommand*{\MacroB}[1]{b#1b}
我猜想有些地方需要加倍,#
但我不明白为什么,而且猜测哪些需要加倍也没有用。所以也许这不是问题所在。
笔记:
- 下面的 MWE 编译得很好——需要取消注释
\def\EnableTrace{}
才能看到问题。 - 这样做的目的是在宏被调用时建立它们的堆栈跟踪。
代码:
%\def\EnableTrace{}
\documentclass{article}
%% All packages included here...
\usepackage{xparse}
\usepackage{letltxmacro}
%% Start of custom macros...
\ifdefined\EnableTrace
\newcounter{NestingDepth}
\newcommand*{\StartMacro}[1]{%
\typeout{**** DEBUG: (Depth=\arabic{NestingDepth}) Started macro "\string#1".}%
\stepcounter{NestingDepth}%
}%
\newcommand*{\EndMacro}[1]{%
\addtocounter{NestingDepth}{-1}%
\typeout{**** DEBUG: (Depth=\arabic{NestingDepth}) Completed macro "\string#1".}%
}%
% --------------
\LetLtxMacro{\OldNewcommand}{\newcommand}%
\RenewDocumentCommand{\newcommand}{%
s% #1 = * (ignored for now to keep the code below simple)
m% #2 = macro name
O{1}% #3 = number of paramaters
o% #4 = default value for first optional parameter (if there is one)
m% #5 = code to execute
}{%
%
\ifnum#3=1\relax
\OldNewcommand{#2}{\StartMacro{#2}#5\EndMacro{#2}}%
\else
\IfBooleanTF{#4}{%
% first parameter of macro being defined is optional, as default value is provided
\OldNewcommand{#2}[#3][#4]{\StartMacro{#2}#5\EndMacro{#2}}%
}{%
% first parameter of macro being defined is mandatory
\OldNewcommand{#2}[#3]{\StartMacro{#2}#5\EndMacro{#2}}%
}%
\fi
}%
\fi
\newcommand*{\MacroB}[1]{b#1b}%
\newcommand*{\MacroA}[1]{a\MacroB{#1}a}%
\begin{document}
\MacroA{XXX}
\MacroB{YYY}
\end{document}
答案1
您的代码中存在奇怪的条件。此外,对于或\IfBooleanTF
类型的参数, 是,而对于 不是。s
t
o
\documentclass{article}
\usepackage{xparse}
\newif\ifEnableTrace
\newcounter{NestingDepth}
\let\latexnewcommand\newcommand
\newcommand{\StartMacro}[1]{%
\ifEnableTrace
\typeout{**** DEBUG: (Depth=\arabic{NestingDepth}) Started macro `\string#1'.}%
\stepcounter{NestingDepth}%
\fi
}
\newcommand{\EndMacro}[1]{%
\ifEnableTrace
\addtocounter{NestingDepth}{-1}%
\typeout{**** DEBUG: (Depth=\arabic{NestingDepth}) Completed macro `\string#1'.}%
\fi
}
\NewDocumentCommand{\NewCommand}{smO{0}om}{%
\IfBooleanTF{#1}
{\IfNoValueTF{#4}{\latexnewcommand*{#2}[#3]}{\latexnewcommand*{#2}[#3][#4]}}%
{\IfNoValueTF{#4}{\latexnewcommand{#2}[#3]}{\latexnewcommand{#2}[#3][#4]}}%
{\StartMacro{#2}#5\EndMacro{#2}}%
}
% if you want to enable tracing
\let\newcommand\NewCommand
\newcommand*{\MacroB}[1]{b#1b}
\newcommand*{\MacroA}[1]{a\MacroB{#1}a}
\begin{document}
\MacroA{XXX}
\MacroB{YYY}
\EnableTracetrue
\MacroA{XXX}
\MacroB{YYY}
\end{document}
这是终端输出
**** DEBUG: (Depth=0) Started macro `\MacroA'.
**** DEBUG: (Depth=1) Started macro `\MacroB'.
**** DEBUG: (Depth=1) Completed macro `\MacroB'.
**** DEBUG: (Depth=0) Completed macro `\MacroA'.
**** DEBUG: (Depth=0) Started macro `\MacroB'.
**** DEBUG: (Depth=0) Completed macro `\MacroB'.
答案2
你用
\ifnum#3=1\relax
\OldNewcommand{#2}{\StartMacro{#2}#5\EndMacro{#2}}%
\else
检查完之后,\newcommand\…[1]
你会得到类似的结果\newcommand\…[0]
。
\ifnum#3=1\relax
\OldNewcommand{#2}[1]{\StartMacro{#2}#5\EndMacro{#2}}%
\else
作品。
顺便问一下……为什么这\ifnum
完全是必要的?只需保留“else”分支\ifnum
就足够了:
%\def\EnableTrace{}
\documentclass{article}
%% All packages included here...
\usepackage{xparse}
\usepackage{letltxmacro}
%% Start of custom macros...
\ifdefined\EnableTrace
\newcounter{NestingDepth}
\newcommand*{\StartMacro}[1]{%
\typeout{**** DEBUG: (Depth=\arabic{NestingDepth}) Started macro "\string#1".}%
\stepcounter{NestingDepth}%
}%
\newcommand*{\EndMacro}[1]{%
\addtocounter{NestingDepth}{-1}%
\typeout{**** DEBUG: (Depth=\arabic{NestingDepth}) Completed macro "\string#1".}%
}%
% --------------
\LetLtxMacro{\OldNewcommand}{\newcommand}%
\RenewDocumentCommand{\newcommand}{%
s% #1 = * (ignored for now to keep the code below simple)
m% #2 = macro name
O{1}% #3 = number of paramaters
o% #4 = default value for first optional parameter (if there is one)
m% #5 = code to execute
}{%
%
% \ifnum#3=1\relax
% \OldNewcommand{#2}{\StartMacro{#2}#5\EndMacro{#2}}%
% \else
\IfBooleanTF{#4}{%
% first parameter of macro being defined is optional, as default value is provided
\OldNewcommand{#2}[#3][#4]{\StartMacro{#2}#5\EndMacro{#2}}%
}{%
% first parameter of macro being defined is mandatory
\OldNewcommand{#2}[#3]{\StartMacro{#2}#5\EndMacro{#2}}%
}%
% \fi
}%
\fi
\newcommand*{\MacroB}[1]{b#1b}%
\newcommand*{\MacroA}[1]{a\MacroB{#1}a}%
\begin{document}
\MacroA{XXX}
\MacroB{YYY}
\end{document}
顺便问一下,为什么不将参数数量默认为,[0]
以便它能够像原始一样工作\newcommand
?