我(再次)在扩展方面遇到困难。这次我有一个通用函数\misdirection
,可以根据一些选项创建一个 TikZ 环境。然后,我创建一个宏\freezeStyle
,该宏创建一个新宏,该宏已将一些选项冻结为\misdirection
。因此\freezeStyle
接收了我最终想要传递给的样式\misdirection
。
我尝试了几次\edef
,但无法让它工作,所以我选择将代码置于一种状态,以演示编译但具有不良行为的情况。这次尝试的灵感来自如何使用 pgfkeys 提交一组 tikz 命令?。
那么:我应该如何修改它以使其按预期工作?请注意,我的实际误导调用将涉及\csname
,因此,我希望 expandafter 解决方案也能展示如何使您的解决方案适应这种情况(有关详细信息,请参阅代码)。
为了交叉引用,这里有一个类似的问题:编写宏的宏和意外的副作用,具有相同类型的不良行为,但解决方案与定义定制的有关\csname
,这并不适用于这个问题。
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{arrows.meta}
\newcommand{\misdirection}[2][]{
\begin{tikzpicture}
\node (tree) at (0,0) {tree};
\node (apple) at (3,0) {#2};
\draw[blue,#1] (tree) -- (apple);
\end{tikzpicture}
}
\pgfkeys{
/tikz/.cd,
execute style/.style = {#1},
execute macro/.style = {execute style/.expand once=#1},
/demo/.cd,
name/.store in=\savedname,
style/.store in=\savedstyle
}
\newcommand{\freezeStyle}[1][]{%
\pgfqkeys{/demo}{#1}
\expandafter\def\csname\savedname\endcsname##1{%
% Incorrect because \savedstyle is not expanded until runtime.
% I want the value of \savedstyle hardcoded into this macro.
\misdirection[execute macro = \savedstyle]{##1}
% This doesn't work either...
%\expandafter\misdirection\expandafter[\savedstyle]{##1}
% In my real code, the misdirection call looks more like:
%\csname someArgumentDependentStuff \endcsname[put style here]{args}
}
}
\begin{document}
\freezeStyle[name=helloMom, style={red,thick}]
\freezeStyle[name=helloDad, style={-{>[length=5mm]},green}]
\helloMom{4} % Undesirably, this is green with a big arrow.
\helloDad{5}
\end{document}
答案1
我只需使用“辅助”宏,以便\savedstyle
可以扩展(一次):
\documentclass[varwidth,border=5]{standalone}
\usepackage{tikz}
\usetikzlibrary{arrows.meta}
\newcommand{\misdirection}[2][]{%
\begin{tikzpicture}
\node (tree) at (0,0) {tree};
\node (apple) at (3,0) {#2};
\draw [blue,#1] (tree) -- (apple);
\end{tikzpicture}\ignorespaces% or \par?
}
\pgfkeys{demo/.cd,
name/.store in=\savedname,
style/.store in=\savedstyle
}
\newcommand\freezeStyle[1][]{%
\pgfqkeys{/demo}{#1}%
\expandafter\FreezeStyle\expandafter{\savedstyle}{\savedname}}
\def\FreezeStyle#1#2{%
\expandafter\def\csname#2\endcsname##1{%
\misdirection[#1]{##1}}}
\begin{document}
\freezeStyle[name=helloMom, style={red,thick}]
\freezeStyle[name=helloDad, style={-{>[length=5mm]},green}]
\helloMom{4}
\helloDad{5}
\end{document}
注意,我\ignorespaces
在命令中添加了一个\misdirection
。
答案2
有了expl3
,只是为了好玩:)
\documentclass{article}
\usepackage{xparse} % automatically loads expl3
\usepackage{tikz}
\usetikzlibrary{arrows.meta}
\newcommand{\misdirection}[2][]{%
\begin{tikzpicture}
\node (tree) at (0,0) {tree};
\node (apple) at (3,0) {#2};
\draw[blue,#1] (tree) -- (apple);
\end{tikzpicture}}
\ExplSyntaxOn
% Declare our variables; it's good practice :)
\tl_new:N \l_demo_name_tl
\tl_new:N \l_demo_style_tl
% Set up our keys (`tl` is short for `token list`)
\keys_define:nn { demo } {
name .tl_set:N = \l_demo_name_tl,
style .tl_set:N = \l_demo_style_tl,
}
% Create a macro to behave as if we would call
% \demo_freeze_style:Nn \helloMom { red, thick }...
\cs_new:Nn \demo_freeze_style:Nn {
\cs_new:Npn #1 ##1 {
\misdirection[#2]{##1}
}
}
% ...but then add support for saner syntax in our use case
\cs_generate_variant:Nn \demo_freeze_style:Nn { cV }
% Now, set our keys and use our command :)
\NewDocumentCommand \freezeStyle { O{} } {
\group_begin:
\keys_set:nn { demo } { #1 }
\demo_freeze_style:cV { \tl_use:N \l_demo_name_tl } \l_demo_style_tl
\group_end:
}
\ExplSyntaxOff
\begin{document}
\freezeStyle[name=helloMom, style={red,thick}]
\freezeStyle[name=helloDad, style={-{>[length=5mm]},green}]
\helloMom{4}
\helloDad{5}
\end{document}
答案3
不使用 的方法如下expl3
:
\newcommand\freezeStyle[1][]{%
\pgfqkeys{/demo}{#1}%
\expandafter\edef\csname\savedname\endcsname##1{%
\noexpand\misdirection[\savedstyle]{##1}}}
注意\edef
这里使用了,\noexpand
用于保护不应扩展的宏。
\typeout{\meaning\helloMom}
macro:#1->\misdirection [execute macro=red,thick]{#1}
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{arrows.meta}
\pgfkeys{
/demo/.cd,
name/.store in=\savedname,
style/.store in=\savedstyle
}
\newcommand{\misdirection}[2][]{%
\begin{tikzpicture}
\node (tree) at (0,0) {tree};
\node (apple) at (3,0) {#2};
\draw[blue,#1] (tree) -- (apple);
\end{tikzpicture}}
\newcommand\freezeStyle[1][]{%
\pgfqkeys{/demo}{#1}%
\expandafter\edef\csname\savedname\endcsname##1{%
\noexpand\misdirection[\savedstyle]{##1}}}
\begin{document}
\freezeStyle[name=helloMom, style={red,thick}]
\freezeStyle[name=helloDad, style={-{>[length=5mm]},green}]
\helloMom{4}
\helloDad{5}
\end{document}