是否可以使用pgfkeys
从样式中删除键的包来创建键处理程序?
这是一个最小的工作示例:
\documentclass[preview,margin=10pt,convert]{standalone}
\usepackage{pgfkeys}
\pgfkeys{/a/.code={a#1},
/b/.code={b#1},
/c/.code={c#1}}
\pgfkeys{/my style/.style = {/a=1, /b=2, /c=3}}
\begin{document}
\pgfkeys{/my style}\par
%\pgfkeys{/my style/.remove from style = {b}}
\pgfkeys{/my style}
\end{document}
输出为
如果取消注释注释行,则所需的输出将是
a1b2c3
a1c3
这里有几个密切相关的问题。它们不是这个问题的重复,但第二个问题的答案可能有助于设计这个问题的答案。
答案1
下面在的帮助下实现了这一点expkv
(因为它可扩展并且速度快,所以我可以更轻松地设置键过滤)。
它利用 的内部结构.style
,解析存储的键列表,并过滤该键列表内的值。
警告:您必须提供与样式中定义完全一致的关键路径,此解决方案不进行广泛的路径解析。
\documentclass[preview,margin=10pt]{standalone}
\usepackage{pgfkeys}
% how a style is defined (current code 2023-06-17)
\iffalse
\pgfkeys{/handlers/.style/.code=\pgfkeys{\pgfkeyscurrentpath/.code=\pgfkeysalso{#1}}}
\pgfkeysdef{/handlers/.code}{\pgfkeysdef{\pgfkeyscurrentpath}{#1}}
\long\def\pgfkeysdef#1#2{%
\long\def\pgfkeys@temp##1\pgfeov{#2}%
\pgfkeyslet{#1/.@cmd}{\pgfkeys@temp}%
\pgfkeyssetvalue{#1/.@body}{#2}%
}
\long\def\pgfkeyslet#1#2{%
\expandafter\let\csname pgfk@#1\endcsname#2%
}
\fi
\pgfkeys
{
/a/.code={a#1}
,/b/.code={b#1}
,/c/.code={c#1}
,/my style/.style = {/a=1, /b=2, /c=3}
}
\usepackage{expkv} % yes, I use expkv to filter pgfkeys...
\makeatletter
\ExplSyntaxOn
\cs_new:Npn \mypgfkeys@checkstyle #1
{
\bool_lazy_and:nnF
{ \tl_if_head_eq_meaning_p:nN {#1} \pgfkeysalso }
{ \exp_args:No \tl_if_single_p:n { \use_none:n #1 } }
}
\ExplSyntaxOff
\protected\def\mypgfkeys@not@a@style
{%
\PackageError{mypgfkeys}{Not a style: \pgfkeyscurrentpath}{}
\mypgfkeys@break
}
\def\mypgfkeys@breakpoint#1{}
\def\mypgfkeys@break#1\mypgfkeys@breakpoint#2{#2}
\pgfkeys{/handlers/.remove from style/.code=\mypgfkeysrmfromstyle{#1}}
\def\mypgfkeysrmfromstyle@mark{\mypgfkeysrmfromstyle@mark}
\protected\def\mypgfkeysrmfromstyle#1%
{%
\begingroup
\ekvcsvloop\mypgfkeysrmfromstyle@makemark{#1}%
\expandafter\let\csname mypgfkeys@@#1\endcsname\mypgfkeysrmfromstyle@mark
\pgfkeysgetvalue{\pgfkeyscurrentpath/.@body}\mypgfkeysrmfromstyle@body
\ifx\mypgfkeysrmfromstyle@body\relax
\mypgfkeys@not@a@style
\fi
\expandafter\mypgfkeys@checkstyle\expandafter
{\mypgfkeysrmfromstyle@body}%
\mypgfkeys@not@a@style
\edef\mypgfkeysrmfromstyle@body
{%
\expanded
{%
\expandafter\mypgfkeysrmfromstyle@do\expandafter
{\mypgfkeysrmfromstyle@body}%
}%
}%
\expanded{%
\endgroup
\unexpanded{\pgfkeys}%
{%
\pgfkeyscurrentpath/.style=
{%
\unexpanded\expandafter\expandafter\expandafter
{\expandafter\@gobble\mypgfkeysrmfromstyle@body}%
}%
}%
}%
\mypgfkeys@breakpoint\endgroup
}
\protected\def\mypgfkeysrmfromstyle@makemark#1%
{\expandafter\let\csname mypgfkeys@@#1\endcsname\mypgfkeysrmfromstyle@mark}
\def\mypgfkeysrmfromstyle@do#1%
{\expandafter\mypgfkeysrmfromstyle@do@\expandafter{\@secondoftwo#1}}
\def\mypgfkeysrmfromstyle@do@
{\ekvparse\mypgfkeysrmfromstyle@do@k\mypgfkeysrmfromstyle@do@kv}
\def\mypgfkeysrmfromstyle@do@k#1%
{%
\expandafter\ifx\csname mypgfkeys@@#1\endcsname\mypgfkeysrmfromstyle@mark
\expandafter\@gobbletwo
\fi
\unexpanded{,#1}%
}
\long\def\mypgfkeysrmfromstyle@do@kv#1#2%
{%
\expandafter\ifx\csname mypgfkeys@@#1\endcsname\mypgfkeysrmfromstyle@mark
\expandafter\@gobbletwo
\fi
\unexpanded{,#1= {#2}}%
}
\makeatother
%\expandafter\show\csname pgfk@/my style/.@body\endcsname
\begin{document}
\pgfkeys{/my style}\par
\pgfkeys{/my style/.remove from style={/b,/c}}
\pgfkeys{/my style}
\end{document}
答案2
根据您的使用情况,您可以安装密钥过滤器。
这不会/b
从中删除,只是在使用它时/my style
禁用样式(或任何其他样式) 。/b
/my style
\pgfkeysfiltered
代码
\documentclass{article}
\usepackage{pgfkeys}
\pgfkeys{
/a/.code={a#1},
/b/.code={b#1},
/c/.code={c#1},
/my style/.style = {/a=1, /b=2, /c=3},
/x/.style={/b=3, /c=4},
}
\begin{document}
normal: \pgfkeys{/my style}\par
\pgfkeys{
/pgf/key filters/not/.install key filter={
/pgf/key filters/equals=/b
}
}
filtered: \pgfkeysfiltered{/my style}\par
Add /x \pgfkeys{/my style/.append style=/x}
and filter: \pgfkeysfiltered{/my style}\par
\end{document}
输出
正常:a1b2c3
过滤:a1c3
添加/x 并过滤:a1c3c4