概念证明

概念证明

我想知道我是否可以l3keys像 pgfoption 那样使用它来处理多个子模块?

下面是一个 MWE 来说明我的问题:

  • 一个包文件mypkg.sty(注释中包含了我尝试编译 LaTeX 文件时遇到的错误):
\ProvidesExplPackage{mypkg}{2024/01/01}{v0.0.0}{mypkg test}

\keys_define:nn { mypkg / title }
{
    title .choice:,
    title .usage:n = { general },
    title .default:n = { regular },
    title / regular .code:n = 
    {
        \PackageWarning {mypkg} {We~use~regular~title!}
    },
    title / smallcaps .code:n = 
    {
        \PackageWarning {mypkg} {We~use~smallcaps~title!}
    },
    title / unknown .code:n = { \PackageWarning {mypkg} {unknown~title~option!} },
}

\keys_define:nn { mypkg / font }
{
    font .choice:,
    font .usage:n = { general },
    font .default:n = { regular },
    font / regular .code:n = 
    {
        \PackageWarning {mypkg} {We~use~regular~font!}
    },
    font / bold .code:n = 
    {
        \PackageWarning {mypkg} {We~use~bold~font!}
    },
    font / unknown .code:n = { \PackageWarning {mypkg} {unknown~font~option!} },
}

% \ProcessKeyOptions % -> ! LaTeX Error: Unknown option 'title' for package mypkg.
\ProcessKeyOptions[mypkg/title, mypkg/font] % -> ! LaTeX Error: Unknown option 'title' for package mypkg.
% \ProcessKeyOptions[mypkg/title] % -> ! LaTeX Error: Unknown option 'font' for package mypkg.
% \ProcessKeyOptions[mypkg/font] % -> ! LaTeX Error: Unknown option 'title' for package mypkg.
  • LaTeX 文件test.tex
\documentclass{article}
\usepackage[title=smallcaps, font=regular]{mypkg}

\begin{document}
TEST
\end{document}

答案1

下面使用另一个子模块的未知处理程序来加载子模块的键。这会破坏全局键(因此会破坏赋予的选项\documentclass),但除此之外,效果还不错。

\ProvidesExplPackage{mypkg}{2024/01/01}{v0.0.0}{mypkg test}

\seq_const_from_clist:Nn \c__mypkg_load_submodules_seq { title, font }
\keys_define:nn { mypkg / load }
  {
    unknown .code:n =
      \__mypkg_keymodules:Vn \l_keys_key_str {#1}
  }
\cs_new_protected:Npn \__mypkg_keymodules:nn #1#2
  {
    \seq_map_inline:Nn \c__mypkg_load_submodules_seq
      {
        \keys_if_exist:nnT { mypkg / ##1 } {#1}
          {
            % missing feature in l3keys, we have no better way to detect an
            % omitted value, so we have to guess that all empty values are in
            % fact omitted values.
            \tl_if_empty:nTF {#2}
              { \keys_set:nn { mypkg / ##1 } { #1 } }
              { \keys_set:nn { mypkg / ##1 } { #1 = {#2} } }
            \prg_break:
          }
      }
    \msg_error:nnn { mypkg } { unknown-key } {#1}
    \prg_break_point:
  }
\cs_generate_variant:Nn \__mypkg_keymodules:nn { Vn }
\msg_new:nnn { mypkg } { unknown-key } { Unknown~ key~ #1~ encountered. }

\keys_define:nn { mypkg / title }
{
    title .choice:,
    title .usage:n = { general },
    title .default:n = { regular },
    title / regular .code:n = 
    {
        \PackageWarning {mypkg} {We~use~regular~title!}
    },
    title / smallcaps .code:n = 
    {
        \PackageWarning {mypkg} {We~use~smallcaps~title!}
    },
    title / unknown .code:n = { \PackageWarning {mypkg} {unknown~title~option!} },
}

\keys_define:nn { mypkg / font }
{
    font .choice:,
    font .usage:n = { general },
    font .default:n = { regular },
    font / regular .code:n = 
    {
        \PackageWarning {mypkg} {We~use~regular~font!}
    },
    font / bold .code:n = 
    {
        \PackageWarning {mypkg} {We~use~bold~font!}
    },
    font / unknown .code:n = { \PackageWarning {mypkg} {unknown~font~option!} },
}

\ProcessKeyOptions[mypkg/load] % -> ! LaTeX Error: Unknown option 'title' for package mypkg.

概念证明

这是一个 PoC,用于通过子模块解析初始选项(以便全局选项可以工作),但任何未来的选项都通过我们的load子模块与未知键处理程序一起起作用,所有这些都只解析每个选项一次。

不可否认,这确实有点复杂。

\ProvidesExplPackage{mypkg}{2024/01/01}{v0.0.0}{mypkg test}

\seq_const_from_clist:Nn \c__mypkg_load_submodules_seq { title, font }
\cs_new_protected:Npn \__mypkg_keymodules:nn #1#2
  {
    \seq_map_inline:Nn \c__mypkg_load_submodules_seq
      {
        \keys_if_exist:nnT { mypkg / ##1 } {#1}
          {
            % missing feature in l3keys, we have no better way to detect an
            % omitted value, so we have to guess that all empty values are in
            % fact omitted values.
            \tl_if_empty:nTF {#2}
              { \keys_set:nn { mypkg / ##1 } { #1 } }
              { \keys_set:nn { mypkg / ##1 } { #1 = {#2} } }
            \prg_break:
          }
      }
    \msg_error:nnn { mypkg } { unknown-key } {#1}
    \prg_break_point:
  }
\cs_generate_variant:Nn \__mypkg_keymodules:nn { Vn }
\msg_new:nnn { mypkg } { unknown-key } { Unknown~ key~ #1~ encountered. }

\keys_define:nn { mypkg / title }
{
    title .choice:,
    title .usage:n = { general },
    title .default:n = { regular },
    title / regular .code:n = 
    {
        \PackageWarning {mypkg} {We~use~regular~title!}
    },
    title / smallcaps .code:n = 
    {
        \PackageWarning {mypkg} {We~use~smallcaps~title!}
    },
    title / unknown .code:n = { \PackageWarning {mypkg} {unknown~title~option!} },
    unknown .code:n = {}
}

\keys_define:nn { mypkg / font }
{
    font .choice:,
    font .usage:n = { general },
    font .default:n = { regular },
    font / regular .code:n = 
    {
        \PackageWarning {mypkg} {We~use~regular~font!}
    },
    font / bold .code:n = 
    {
        \PackageWarning {mypkg} {We~use~bold~font!}
    },
    font / unknown .code:n = { \PackageWarning {mypkg} {unknown~font~option!} },
    unknown .code:n = {}
}

\ProcessKeyOptions[mypkg/title]
\ProcessKeyOptions[mypkg/font]

\keys_define:nn { mypkg / load }
  {
    unknown .code:n = {}
  }
\ProcessKeyOptions[mypkg/load] % -> ! LaTeX Error: Unknown option 'title' for package mypkg.

\keys_define:nn { mypkg / load }
  {
     unknown .code:n =
      \__mypkg_keymodules:Vn \l_keys_key_str {#1}
  }
\clist_map_inline:nn { title, font }
  {
    \keys_define:nn { mypkg / #1 }
      {
        \unknown .code:n =
          \msg_error:nne { mypkg } { unknown-key } \l_keys_key_str
      }
  }

答案2

我不确定你为什么要这样定义密钥。但你可以简单地在每个模块中添加对未知密钥的管理。

\ProvidesExplPackage{mypkg}{2024/01/01}{v0.0.0}{mypkg test}

\keys_define:nn { mypkg/title }
{
    title .choice:,
    title .usage:n = { general },
    title .default:n = { regular },
    title / regular .code:n = 
    {
        \PackageWarning {mypkg} {We~use~regular~title!}
    },
    title / smallcaps .code:n = 
    {
        \PackageWarning {mypkg} {We~use~smallcaps~title!}
    },
    title / unknown .code:n = { \PackageWarning {mypkg} {unknown~title~option!} },
    unknown .code:n = {},
}
\keys_define:nn { mypkg/font }
{
    font .choice:,
    font .usage:n = { general },
    font .default:n = { regular },
    font / regular .code:n = 
    {
        \PackageWarning {mypkg} {We~use~regular~font!}
    },
    font / bold .code:n = 
    {
        \PackageWarning {mypkg} {We~use~bold~font!}
    },
    font / unknown .code:n = { \PackageWarning {mypkg} {unknown~font~option!} },
    unknown .code:n = {},
}

\ProcessKeyOptions[mypkg/title]
\ProcessKeyOptions[mypkg/font]

相关内容