我一直在尝试学习 L3 编程层,同时编写一个简单的包来设置和使用文本“样式”。
背景是我在我的类中添加了键值参数,这些参数应该像这样工作:
\documentclass[
style/footnote = {small,sans,FF0000},
style/chapter-name = uppercase, % full uppercase
]{desert}
事实是,即使完成了大部分工作,我还是不懂 L3 l3.pdf
。以下是我需要帮助的地方:
- 我显然使用
\cs:w
不正确。 - 我一直无法理解其中的流程,尤其是什么时候LaTeX 扩展了我应该在何处使用
:n
、:x
或:v
。(我要补充一点,TeX 的错误消息并不是很好。) - 我希望我的宏
\txtuppertosc
以及 等\txtuppercase
能够像 或 一样\LARGE
工作\bfseries
,以便开关\TxtStyle
可以与它们配合使用。有什么办法吗?
更新:David Carlisle 指出我错误地将:N
参数包装在 中{}
。原始宏位于底部。
更新代码:
\RequirePackage{xparse}
\RequirePackage{l3keys2e}
\RequirePackage{etoolbox}
\ProvidesExplPackage{txtstyles}{2022-02-02}{0.1}{Text styles}
\RequirePackage[
dvipsnames,svgnames,x11names,
hyperref
]{xcolor}
\RequirePackage{fontsize}
% build up aliases for style commands
\prop_new:N \g_txtstyle_aliases
\prop_set_from_keyval:Nn \g_txtstyle_aliases
{
rm=rmfamily, roman=rmfamily,
upcase=txtuppercase, uppercase=txtuppercase,
mini=footnotesize, minir=footnotesizer%, ...
}
% --- MAIN MACRO FOR A SINGLE CSV:
% converts a single name, like "LARGE", \bf, or "red" to a command
\cs_new:Npn \convert_cmd:n #1
{
\cs_if_exist_use:cTF{#1}
{} % option 1: a command that starts with \
{
% options 2 (named alias) and 3 (color)
\prop_get:NnNTF \g_txtstyle_aliases {#1}
{} { \color{#1} }
}
}
%%% MAIN MACRO FOR DECLARING A STYLE:
% defines a new style as a list of commands (via \convert_cmd)
\NewDocumentCommand{\DeclareTxtStyle}{m >{\SplitList{,}}m}
{
\cs_gset:cpn{g_txtstyle_#1:} ##1
{ \tl_map_inline:Nn #2 { \convert_cmd:n{###1} } }
}
% Sets the text style (similar to \bfseries, etc.)
\NewDocumentEnvironment{TxtStyle}{m+b}
{
\cs_if_exist_use:cTF{g_txtstyle_#1:}
{}
{ \stylemissingerr:n{#1} } % defined elsewhere
}{}
\NewDocumentCommand{\StyleTxt}{m+m}
{ \begin{TxtStyle}{#1} #2 \end{TxtStyle} }
main.tex
\documentclass{article}
\RequirePackage{txtstyles}
\begin{document}
\DeclareTxtStyle{mystyle}{large,red}
\StyleTxt{mystyle}{This is some text.}
\end{document}
作为参考,原始宏是:
% map an alias to its \command-value (e.g. roman becomes rmseries)
\cs_new:Npn \standardize_alias:n #1
{
\prop_item:Nn \g_txtstyle_aliases {#1}
}
% converts a single name, like "LARGE", \bf, or "red" to a command
\cs_new:Npn \convert_cmd:n #1
{
\prop_if_in:NVTF \g_txtstyle_aliases {#1}
{ \cs:w \standardize_alias:n{#1} \cs_end: } % option 1: common name
{
\cs_if_exist_NTF {\cs:w #1 \cs_end:}
{ \cs:w #1 \cs_end: } % option 2: a command name that starts with \
{ \color{#1} } % option 3: a color, or fail
}
}
% just gets the internal command name for a style
\cs_new:Npn \txtstyle_cmd_name:n #1
{ \cs:w g_txtstyle_#1:n \cs_end: }
% defines a new style as a list of commands (via \convert_cmd)
\NewDocumentCommand{\DeclareTxtStyle}{m >{\SplitList{,}}m}
{
\cs_set:Npn { \txtstyle_cmd_name:n{#1} } {}
{ \tl_map_inline:Nn {#2} { \convert_cmd:n{##1} } }
}
答案1
您需要注意 expl3 参数类型。N
并且V
参数应采用单个无括号标记。您几乎永远不需要使用,因为这是应该优先使用的参数类型\cs:w
的实现。c
这里我展示了您的中心命令,它接受一个参数,如果参数是命令名,则执行该命令,否则将其解释为颜色。
\documentclass{article}
\usepackage{color}
\begin{document}
\ExplSyntaxOn
\cs_new:Npn \convert_cmd:n #1
{
\cs_if_exist_use:cTF{#1}
{} % option 2: a command that starts with \
{ \color{#1} } % option 3: a color, or fail
}
abc ~ {\convert_cmd:n{bfseries} abc} ~
abc ~ {\convert_cmd:n{red} abc}
\ExplSyntaxOff
\end{document}
在你的原文中
\cs_if_exist:NTF{\cs:w {#1} \cs_end:}
但这是将括号组传递给N
参数,并且如果#1
是,它会测试是否存在带有名称(包括括号)的bfseries
命令。您有意为之,但如上所述,最好只使用参数并传入{bfseries}
\cs:w #1 \cs_end:
c
{#1}