![以宏 + 反馈的方式退出分组](https://linux22.com/image/472264/%E4%BB%A5%E5%AE%8F%20%2B%20%E5%8F%8D%E9%A6%88%E7%9A%84%E6%96%B9%E5%BC%8F%E9%80%80%E5%87%BA%E5%88%86%E7%BB%84.png)
我目前正在尝试 latex3,以便更深入地了解使用 latex 进行编程。为此,我创建了一个简单的设置系统。
其工作原理如下:
- 您可以通过以下方式创建设置
\NewSetting[type = <type>, init = <init-value>]{<Name>}
- 根据其类型,它调用其相应的设置宏:例如,对于字符串设置,它将调用
\NewStringSetting[<init-value>]{<Name>}
。 \NewStringSetting
将创建字符串,设置字符串的初始值并创建使用该字符串所需的所有宏,例如Clear<Name>
和。Set<Name>
Get<Name>
示例 |作者的字符串设置:
- 我通过调用创建一个设置
\NewSetting[type = string, init = Dave]{Author}
- 内部的:
\NewSetting
调用\NewStringSetting[Dave]{Author}
- 内部的:
\NewStringSetting
创建一个 expl3 字符串(g_my_author_str
),如果需要则设置一个值并创建 3 个宏:\ClearAuthor
,\SetAuthor{<Content>}
和\GetAuthor
。
现在我可以清除、设置和获取字符串作者的内容。
问题:我用于xkeyval
键值对。它们\NewSetting
通过\setkeys
组内设置,因此离开组后会重置(请参阅大卫·卡莱尔的评论)。但是,离开组后,所有创建的宏(\ClearAuthor
、\SetAuthor{<Content>}
和\GetAuthor
)都未定义。一个解决方案是删除该组,但键值对不会按预期重置。所以这不是真正的解决方案。然后我偶然发现了@wipet 的解决方案将宏转发出组;这样保留宏,同时所有键仍然在组末尾重置。看起来是个可行的解决方案。
问题:我对 LaTeX 还不太熟悉,尤其是 latex3。到目前为止,我对结果相当满意(毕竟它有效),但我想知道您的想法。我想知道是否有更简单的方法以及我可以改进什么。
我遇到的最大困难是扩展。 有没有什么好的参考资料(例如 Youtube、论坛帖子等)?(尤其是那些也涉及 latex3 及其原语的参考资料,例如\exp_last_unbraced
...)
概要:
- 代码如何改进(特别是针对我所描述的问题)?
- 有没有什么好的参考资料解释 latex3 (我知道 LaTeX3 的手册)?
- 是否有一些经验法则可以让你无需反复试验就能正确进行扩展
字符串设置代码:
\documentclass{book}
\usepackage{expl3} % Only needed for IDE-autocomplete (aka IntelliSense)
\usepackage{xkeyval}
\makeatletter
\ExplSyntaxOn
% By egreg https://tex.stackexchange.com/a/63233/293060
\NewExpandableDocumentCommand{\IfNoValueOrEmptyTF}{m m m}{%
\IfNoValueTF{#1}{#2}{%
\tl_if_empty:nTF{#1}{#2}{#3}%
}%
}%
% By wipet https://tex.stackexchange.com/a/690710/293060
\def\keepaftergroup#1{%
\global \expandafter\let \csname x:\string#1\endcsname =#1
\aftergroup\let
\aftergroup#1%
\expandafter\aftergroup \csname x:\string#1\endcsname
}
\define@key[DAVE]{settings}{type}{\def\DAVE@Settings@Type{#1}}
\define@key[DAVE]{settings}{init}{\def\DAVE@Settings@Init{#1}}
\NewDocumentCommand{\NewSetting}{o m}{%
\begingroup
\setkeys[DAVE]{settings}{#1}%
\cs_if_exist:NTF\DAVE@Settings@Type{%
\str_case:NnF{\DAVE@Settings@Type}{%
{string}{\begingroup\edef\x{\endgroup\noexpand\NewStringSetting[\cs_if_exist:NT\DAVE@Settings@Init{\DAVE@Settings@Init}]{#2}}\keepaftergroup\x} % <--- Wont work without \keepaftergroup, only if \begingroup + \endgroup removed (but then keys wont reset)
%{bool}{...}
}{%
\ClassError{SETTINGS}{Unknown~settings~type~for~setting~'#2'}{}
}
}{%
\ClassError{SETTINGS}{Cannot~create~setting~'#2'~due~to~missing~setting~type}{}
}
\endgroup
\x % <--- Calling
}
\NewDocumentCommand{\NewStringSetting}{o m}{%
\str_if_exist:cTF{g_DAVE_#2_str}{%
\ClassError{SETTINGS}{String~with~the~name~'#2'~already~exist}{}
}{%
\str_gclear_new:c{g_DAVE_#2_str}
\IfValueT{#1}{%
\str_gset:cn{g_DAVE_#2_str}{#1}
}
\expandafter\NewExpandableDocumentCommand\expandafter{\csname Clear#2\endcsname}{}{%
\str_gclear:c{g_DAVE_#1_str}
}
\expandafter\NewExpandableDocumentCommand\expandafter{\csname Set#2\endcsname}{m}{%
\IfNoValueOrEmptyTF{##1}{%
\ClassWarning{SETTINGS}{Could~not~set~value~for~setting~'#2'~due~to~the~passed~value~being~of~type~'NoValue'~or~empty}%
}{%
\str_gset:cn{g_DAVE_#2_str}{##1}%
}%
}
\expandafter\NewExpandableDocumentCommand\expandafter{\csname Get#2\endcsname}{}{%
\str_use:c{g_DAVE_#2_str}
}
}
}
\ExplSyntaxOff
\makeatother
\NewSetting[type = string]{Forum}
\NewSetting[type = string, init = Dave]{Author}
\SetForum{StackExchange}
\begin{document}
Hello \TeX-\GetForum \space it's \GetAuthor
\end{document}