将剩余选项传递给另一个类的好方法是什么?
\begin{filecontents}{main.cls}
\ExplSyntaxOn
\newcommand{ \selectedoptions } { color }
\keys_define:nn { class / options } {
theme .choices:nn = {
bw,
color,
dark,
draft
} {
\renewcommand{ \selectedoptions } {
\tl_use:N \l_keys_choice_tl
}
}
}
\ProcessKeyOptions[class / options]
\LoadClassWithOptions{ article } % How to pass all options
% except the theme one?
\ExplSyntaxOff
\end{filecontents}
\documentclass[12pt, a4paper, theme=bw]{main}
%\documentclass[12pt, a4paper]{article}
\usepackage{blindtext}
\begin{document}
\blinddocument
\end{document}
笔记
选择的选项永远不会与其他类同名,因为其他类所做的设置永远不会被主类使用。
6
最佳答案
4
我的意思是
\begin{filecontents}[overwrite]{main.cls}
\ExplSyntaxOn
\tl_new:N \l_cookbook_cls_option_tl
\newcommand{ \selectedoptions } { color }
\keys_define:nn { class / options } {
theme .choices:nn = {
bw,
color,
dark,
draft
} {
\renewcommand{ \selectedoptions } {
\tl_use:N \l_keys_choice_tl
}
}
}
\DeclareUnknownKeyHandler[class/options]{%
\PassOptionsToClass{\CurrentOption}{article}%
}
\ProcessKeyOptions[class/options]
\LoadClass{ article } % How to pass all options
% except the theme one?
\ExplSyntaxOff
\end{filecontents}
\documentclass[12pt, a4paper, theme=bw]{main}
%\documentclass[12pt, a4paper]{article}
\usepackage{blindtext}
\begin{document}
\selectedoptions
\blinddocument
\end{document}
运行良好。但是
\DeclareUnknownKeyHandler{%
\PassOptionsToClass{\CurrentOption}{article}%
}
\ProcessKeyOptions
\LoadClass{ article } % How to pass all options
% except the theme one?
不处理main
类选项,而
\DeclareUnknownKeyHandler{%
\PassOptionsToClass{\CurrentOption}{article}%
}
\ProcessKeyOptions[class/options]
\LoadClass{ article } % How to pass all options
% except the theme one?
不会将未知选项传递article
给
\DeclareUnknownKeyHandler[class/options]{%
\PassOptionsToClass{\CurrentOption}{article}%
}
\ProcessKeyOptions
\LoadClass{ article } % How to pass all options
% except the theme one?
不处理其中任何一个。
3
-
[稍后删除]
– -
这是预期的行为:所有 keyval 命令都采用可选参数来指定在选项树中查找的位置 – 因此,如果您要添加未知的处理程序,它必须与您要处理的键位于同一位置。
–
♦ -
@JosephWright 我只是想说,在 OP 的例子上下文中,仅仅发布你发布的内容并不是最具解释性的答案。
–
|
如果您的目标是加载article
所有选项,并且您只是设置这个奇怪的过滤来避免Unused global option(s): [theme]
警告,那么您可以使用以下简单的解决方案。否则,请查看此答案(或其他答案)中的任何其他块。
expkv-opt
具有不同的宏来解析选项,对于未使用的全局选项列表具有不同的行为。特别是在类文件中,使用\ekvoProcessLocalOptions
会将任何未知选项添加到所述列表并从该列表中删除任何已知选项。但是,如果您使用,\ekvoProcessGlobalOptions
您基本上会获得相同的选项(因为全局选项是传递给的选项\documentclass
,并且您的类是主类),但行为不同。\ekvoProcessGlobalOptions
仅从未使用的选项列表中删除,它永远不会添加到其中。
通过此行为,您可以简单地将所有选项转发给article
(这将填充未使用的选项列表),然后解析它们,\ekvoProcessGlobalOptions
这将从未使用的选项列表中删除您的类已知的所有选项。无需过滤。
\begin{filecontents}[overwrite]{main.cls}
\ProvidesExplClass{main}{2024-11-01}{1}{adhoc class for an MWE}
\LoadClassWithOptions { article }
\RequirePackage{expkv-def,expkv-opt}
\newcommand*\selectedfontsize{10}
\ekvdefinekeys { class / options }
{
choice-store~ theme = \selectedoptions {bw, color, dark, draft }
,initial~ theme = color
,protect~ noval~ 12pt = \renewcommand*\selectedfontsize{12}
}
\ekvoProcessGlobalOptions { class / options }
\end{filecontents}
\documentclass[12pt, a4paper, theme=bw, foo]{main} % added foo so we get an unused global options warning
%\documentclass[12pt, a4paper]{article}
\usepackage{blindtext}
\begin{document}
\selectedfontsize
\blinddocument
\end{document}
不幸的是,据我所知,这种方法是不可行的ltkeys
,因为如果您没有指定未知处理程序,它会从未使用的选项列表中删除并向其中添加未知选项,或者如果您提供未知处理程序来忽略未知选项,它不会从未使用的选项列表中删除已知选项。
实现此功能的唯一方法ltkeys
是,如果您的类中没有任何与article
-options 同名的选项,或者您使用 定义所有选项.code:n = <whatever you want to do>\PassOptionsToClass{\CurrentOption}{article}
。最后一种情况是可能的,但您会丢失所有不支持任意用户代码的键处理程序(例如不支持.int_set:N
)。所以它看起来像这样:
\begin{filecontents}[overwrite]{main.cls}
\ProvidesExplClass{main}{2024-11-01}{1}{adhoc class for an MWE}
\newcommand \selectedoptions { color }
\newcommand \selectedfontsize { 10 }
\keys_define:nn { class / options } {
theme .choices:nn = {
bw,
color,
dark,
draft
} {
\exp_args:NNV \renewcommand \selectedoptions \l_keys_choice_tl
}
,12pt .code:n =
\renewcommand\selectedfontsize{12} \PassOptionsToClass{12pt}{article}
}
\DeclareUnknownKeyHandler[class/options]{%
\PassOptionsToClass{\CurrentOption}{article}%
}
\ProcessKeyOptions[class / options]
\LoadClass{ article }
\end{filecontents}
\documentclass[12pt, a4paper, theme=bw, foo]{main}
%\documentclass[12pt, a4paper]{article}
\usepackage{blindtext}
\begin{document}
\selectedoptions\selectedfontsize
\blinddocument
\end{document}
由于您只定义了一个theme
密钥,最简单的解决方案是使用unknown .code:n
来转发所有未知选项。
不幸的l3keys
是没有提供一些接口来区分opt={}
,opt
所以这里的代码假设每个空值都是没有给出值的选项。
\begin{filecontents}[overwrite]{main.cls}
\ProvidesExplClass{main}{2024-11-01}{1}{adhoc class for an MWE}
\newcommand \selectedoptions { color }
\keys_define:nn { class / options } {
theme .choices:nn = {
bw,
color,
dark,
draft
} {
\exp_args:NNV \renewcommand \selectedoptions \l_keys_choice_tl
}
% as noted in Joseph's answer you can (and should) use
% `\PassOptionsToClass{\CurrentOption}{article}` here if you're only using
% this key set in \ProcessKeyOptions.
,unknown .code:n = \exp_args:Ne \PassOptionsToClass
{ \l_keys_key_str \tl_if_empty:nF {#1} { = { \exp_not:n {#1} } } }
{article}
}
\ProcessKeyOptions[class / options]
\LoadClass{ article }
\end{filecontents}
\documentclass[12pt, a4paper, theme=bw]{main}
%\documentclass[12pt, a4paper]{article}
\usepackage{blindtext}
\begin{document}
\blinddocument
\end{document}
如果您有多个密钥,并且其中一部分应该转发,那么您必须以某种方式过滤掉不应转发的密钥。为此,下面定义了一个小辅助宏,它对从输入 key=value 列表中删除的单个密钥名称进行基于字符串的比较。
\begin{filecontents}[overwrite]{main.cls}
\ProvidesExplClass{main}{2024-11-01}{1}{adhoc class for an MWE}
\newcommand \selectedoptions { color }
\newcommand*\selectedfontsize{10}
\keys_define:nn { class / options } {
12pt .code:n = \tl_set:cn { selectedfontsize } { 12 } % just to get a second key
,theme .choices:nn = {
bw,
color,
dark,
draft
} {
\exp_args:NNV \renewcommand \selectedoptions \l_keys_choice_tl
}
}
\ProcessKeyOptions[class / options]
\cs_generate_variant:Nn \__projetmbc_filter_kv:nn { nv }
\cs_new:Npn \__projetmbc_filter_kv:nn #1#2
{
% \keyval_parse:nnn will return each kv-pair in \exp_not:n, we need a step
% more
\use:e
{
\keyval_parse:nnn
{ \__projetmbc_filter_kv_aux:nn {#1} }
{ \__projetmbc_filter_kv_aux:nnn {#1} }
{#2}
}
}
\cs_new:Npn \__projetmbc_filter_kv_aux:nn #1#2
{ \str_if_eq:nnF {#1} {#2} { , \exp_not:n {#2} } }
\cs_new:Npn \__projetmbc_filter_kv_aux:nnn #1#2#3
{ \str_if_eq:nnF {#1} {#2} { , \exp_not:n {#2={#3}} } }
\exp_args:Ne \PassOptionsToClass
{ \__projetmbc_filter_kv:nv { theme } { @raw@opt@\@currname.\@currext } }
{ article }
\LoadClass{ article }
\end{filecontents}
\documentclass[12pt, a4paper, theme=bw]{main}
%\documentclass[12pt, a4paper]{article}
\usepackage{blindtext}
\begin{document}
\selectedfontsize
\blinddocument
\end{document}
expkv-def
这是一个使用和expkv-opt
代替 的示例ltkeys
。
由于expkv-def
具有非常方便的also
机制,允许将任意代码添加到任何预定义代码处理程序,因此将密钥转发添加到密钥列表中相当简单。下面使用\clist_map_inline:nn
密钥循环执行此操作12pt
。
\begin{filecontents}[overwrite]{main.cls}
\ProvidesExplClass{main}{2024-11-01}{1}{adhoc class for an MWE}
\RequirePackage{expkv-def,expkv-opt}
\newcommand*\selectedfontsize{10}
\ekvdefinekeys { class / options }
{
choice-store~ theme = \selectedoptions {bw, color, dark, draft }
,initial~ theme = color
,protect~ noval~ 12pt = \renewcommand*\selectedfontsize{12}
,protect~ unknown~ code = \PassOptionsToClass{#1={#2}}{article}
,protect~ unknown~ noval = \PassOptionsToClass{#1}{article}
}
% specify all defined keys that should be forwarded
\clist_map_inline:nn { 12pt }
{
\ekvifdefined { class / options } { #1 }
{
\ekvdefinekeys { class / options }
{ also~ protect~ code~ #1 = \PassOptionsToClass { #1 = {##1} } { article } }
}
{}
\ekvifdefinedNoVal { class / options } { #1 }
{
\ekvdefinekeys { class / options }
{ also~ protect~ noval~ #1 = \PassOptionsToClass { #1 } { article } }
}
{}
}
\ekvoUseUnknownHandlers*
\ekvoProcessLocalOptions { class / options }
\LoadClass{ article }
\end{filecontents}
\documentclass[12pt, a4paper, theme=bw]{main}
%\documentclass[12pt, a4paper]{article}
\usepackage{blindtext}
\begin{document}
\selectedfontsize
\blinddocument
\end{document}
另一种expkv
方法是定义两个键集,一个是经过过滤的,另一个是未经过滤的。这种方法的优点是,您可以在选项解析之外使用键集(例如在普通\mainsetup
宏或类似宏中)来更改文档中的后续选项。
\begin{filecontents}[overwrite]{main.cls}
\ProvidesExplClass{main}{2024-11-01}{1}{adhoc class for an MWE}
\RequirePackage{expkv-def,expkv-opt}
\newcommand*\selectedfontsize{10}
% if you also want to have a normal set for the options for a `\setup`-macro
% this allows that transparently to the user. If you don't need this the
% following four lines can be removed.
\ekvredirectunknown { class/options }
{ class/options/filtered, class/options/unfiltered }
\ekvredirectunknownNoVal { class/options }
{ class/options/filtered, class/options/unfiltered }
\ekvdefinekeys { class/options/filtered }
{
choice-store~ theme = \selectedoptions {bw, color, dark, draft }
,initial~ theme = color
}
\ekvdefinekeys { class/options/unfiltered }
{
,protect~ noval~ 12pt = \renewcommand*\selectedfontsize{12}
}
% rules to forward an unknown key. Always forward to article, and if the key is
% known in the unfiltered set also use that (via the *documented* low level
% interface of building the key-macros directly, this is just a bit faster than
% using \ekvset{class/options/unfiltered}{#1} -- and since expkv supports
% expansion notation this could in theory make a difference in strange edge
% cases of key names)
\cs_new_protected:Npn \__projetmbc_forward_key:n #1
{
\PassOptionsToClass {#1} { article }
\ekvifdefinedNoVal { class/options/unfiltered } {#1}
{ \use:c { \ekv@name { class/options/unfiltered } {#1} N } }
{}
}
\cs_new_protected:Npn \__projetmbc_forward_key:nn #1#2
{
\PassOptionsToClass {#1={#2}} { article }
\ekvifdefined { class/options/unfiltered } {#1}
{ \use:c { \ekv@name { class/options/unfiltered } {#1} } {#2} }
{}
}
\ekvoUseUnknownHandlers \__projetmbc_forward_key:n \__projetmbc_forward_key:nn
\ekvoProcessLocalOptions { class/options/filtered }
\LoadClass{ article }
\end{filecontents}
\documentclass[12pt, a4paper, theme=bw]{main}
%\documentclass[12pt, a4paper]{article}
\usepackage{blindtext}
\begin{document}
\selectedfontsize
\blinddocument
\end{document}
5
-
我提供了一个基本示例。感谢您的解决方案,但是有没有一种通用方法,可以处理更多选项
l3
?
– -
@projetmbc 也使用非 L3 包(所以要远离
l3keys
)?
–
-
如果这不是一个太
TeX
明智的解决方案,我愿意接受它。:-)
–
-
1@projetmbc 我会尝试同时提供两者。请注意,您的
theme
定义很差,因为 的值\l_keys_choice_tl
可能会在整个文档中发生变化,您需要先将其展开,然后再将新值分配给\selectedoptions
,请参阅我的编辑。
– -
扩展的观点很好。我明天会看看你的建议。感谢分享你的知识。
–
|
正如在中提到的clsguide
,您可以使用内置命令传递未知选项:
\DeclareUnknownKeyHandler{%
\PassOptionsToClass{\CurrentOption}{article}%
}
因此,任何您未申报的东西都可能被传递下去。
1
-
评论已移至;请不要在此继续讨论。在此评论下发表评论之前,请先查看。不要求澄清或建议改进的评论通常属于答案 TeX 或。继续讨论的评论可能会被删除。
–
♦
|
原来使用的选项处理程序article
是为更简单的情况而设计的,您只需在这里给它一点帮助即可。
如您所知,您的类已定义一个选项,您可以简单地将其从归类为未使用的theme
选项列表中删除。每当包处理选项时,LateX 都会使用宏来执行此操作,并且只有在仍有项目时才会发出未使用的全局选项警告。 不幸的是,它不接受要删除哪个选项的参数,它只是使用,因此您需要在本地设置它:article
\@use@ption
\begin{document}
\CurrentOption
\begin{filecontents}{main.cls}
\ExplSyntaxOn
\newcommand{ \selectedoptions } { color }
\keys_define:nn { class / options } {
theme .choices:nn = {
bw,
color,
dark,
draft
} {
\renewcommand{ \selectedoptions } {
\tl_use:N \l_keys_choice_tl
}
}
}
\ProcessKeyOptions[class / options]
\LoadClassWithOptions{ article } % How to pass all options
% except the theme one?
% if theme is in unknown option list remove it
\def\CurrentOption{theme}\@use@ption\let\CurrentOption\@empty
\ExplSyntaxOff
\end{filecontents}
\documentclass[12pt, a4paper, theme=bw]{main}
\begin{document}
\end{document}
|
Unused global option(s): [theme]
警告就使用这个。如果是这样的话,还有更简单(或其他?)的解决方案(虽然我现在找不到相关问题……)。–
–
–
article
。因此,如果您12pt
向类中添加了一个选项,article
的12pt
选项将不再触发。–
–
|