使用 \foreach 循环生成 pgfkeys 路径

使用 \foreach 循环生成 pgfkeys 路径

我正在尝试使用循环生成一组密钥\foreach,但它们似乎没有正确创建。

我尝试使用显示按键的处理程序进行调试,但在我看来,它们在日志中是正确的。一定是我遗漏了什么,但我不知道是什么。

请参阅下面 MWE 中的注释,了解错误出现的位置。

梅威瑟:

\documentclass{article}

\RequirePackage{pgfkeys}
\RequirePackage{pgffor}

\RequirePackage{etoolbox}

\pgfkeys{/handlers/.store in cs/.code=\pgfkeysalso{%
    \pgfkeyscurrentpath/.code=\expandafter\def\csname#1\endcsname{##1}}%
}

\pgfkeysdef{/handlers/.show path}
{%
    \edef\path{\pgfkeyscurrentpath}%
    \pgfkeysgetvalue{\pgfkeyscurrentpath}{\val}%
    \show\path%
}

\makeatletter

\def\meide@keys{\pgfqkeys{/meide}}

\newcommand\meide@setup[3]{%
    % #1 = name
    % #2 = number of levels
    % #3 = further key/value pairs
    \meide@keys{
        #1/.cd,
        levels/.store in cs=meide@#1@levels,
        levels=#2,
    }%
    \foreach \level in {0,...,\csuse{meide@#1@levels}}%
    {%
        \meide@setup@level{#1}{\level}%
    }%
    \meide@keys{#1/.cd,#3}%
}

\newcommand\meide@setup@level[2]{
    % #1 = name
    % #2 = level to create
    \begingroup\edef\x{\endgroup\noexpand%
        \meide@keys{
            #1/level #2/.cd,
            % uncomment the '.show path' handler to see the current keypaths. I see them as expected:
            % /meide/name/level 0/myvals
            % /meide/name/level 1/myvals
            %myvals/.show path,
            myvals/.code 2 args={%
                % #1 = first
                % #2 = second
                \csxdef{meide@#1@myvals@level #2@first}{\unexpanded{##1}}%
                \csxdef{meide@#1@myvals@level #2@second}{\unexpanded{##2}}%
            }
        }%
    }\x%
}

% setting up one of the levels manually to show how it should work
\meide@keys{
    name/level 0/myvals/.code 2 args={%
        % #1 = first
        % #2 = second
        \csxdef{meide@name@myvals@level 0@first}{#1}%
        \csxdef{meide@name@myvals@level 0@second}{#2}%
    },
}

\meide@setup{name}{1}{
    level 0/myvals={a}{b}, % works because it was created manually
    level 1/myvals={c}{d}, % Package pgfkeys Error: I do not know the key '/meide/name/level 1/myvals', to which you passed '{c}{d}'
}

\makeatother

\begin{document}

\csuse{meide@name@myvals@level 0@first} % displays 'a'

\csuse{meide@name@myvals@level 1@first} % displays nothing

\end{document}

答案1

这不起作用,因为您的myvals/.code 2 args={...}是一个本地分配,但它是在 TeX 组内执行的。事实上,\foreach循环\meide@setup在 TeX 组内执行循环代码。一旦该组完成,其中执行的所有本地定义都会自动消失。为了解决这个问题,我简单地用的宏替换了\foreach循环,它不会在循环代码周围创建一个组。expl3\int_step_inline:nnn

我还删除了\edef和相关技巧,因为我不明白为什么这里需要它们。通过这两项更改,一切似乎都按预期工作。

\documentclass{article}
\usepackage{pgfkeys}
\usepackage{expl3}
\usepackage{etoolbox}

\ExplSyntaxOn
% Borrow \int_step_inline:nnn from expl3
\cs_new_eq:NN \intstepinline \int_step_inline:nnn
\ExplSyntaxOff

\pgfkeys{/handlers/.store in cs/.code=\pgfkeysalso{%
    \pgfkeyscurrentpath/.code=\expandafter\def\csname#1\endcsname{##1}}%
}

\pgfkeysdef{/handlers/.show path}
{%
    \edef\path{\pgfkeyscurrentpath}%
    \pgfkeysgetvalue{\pgfkeyscurrentpath}{\val}%
    \show\path
}

\makeatletter

\newcommand\meide@keys{\pgfqkeys{/meide}}

\newcommand\meide@setup[3]{%
    % #1 = name
    % #2 = number of levels
    % #3 = further key/value pairs
    \meide@keys{
        #1/.cd,
        levels/.store in cs=meide@#1@levels,
        levels=#2,
    }%
    \intstepinline{0}{\csuse{meide@#1@levels}}
      {%
        \meide@setup@level{#1}{##1}%
      }%
    \meide@keys{#1/.cd,#3}%
}

\newcommand\meide@setup@level[2]{%
    \meide@keys{
        #1/level #2/.cd,
        % uncomment the '.show path' handler to see the current keypaths. I see them as expected:
        % /meide/name/level 0/myvals
        % /meide/name/level 1/myvals
        %myvals/.show path,
        myvals/.code 2 args={%
            % #1 = first
            % #2 = second
            \csxdef{meide@#1@myvals@level #2@first}{##1}%
            \csxdef{meide@#1@myvals@level #2@second}{##2}%
        },
    }%
}

\meide@setup{name}{1}{
    level 0/myvals={a}{b}, % works
    level 1/myvals={c}{d}, % now also works
}

\makeatother

\begin{document}

\csuse{meide@name@myvals@level 0@first}  % displays 'a'
\csuse{meide@name@myvals@level 0@second} % displays 'b'

\csuse{meide@name@myvals@level 1@first}  % displays 'c'
\csuse{meide@name@myvals@level 1@second} % displays 'd'

\end{document}

在此处输入图片描述

下次请尽量提供一个最简洁的例子:阅读和分析这个例子会花费太多时间。你也许可以减少代码量,尽管我知道你可能没能非常准确地找到问题所在。

相关内容