是否可以创建一个命令,该命令以命令名称c
作为参数并重新定义c
(例如通过renewcommand
)其自身但添加一些新功能?简而言之,我们是否可以定义一个命令,x(c)
其效果是c := f (c)
进行一些修改f
,例如\textcolor{blue}{...}
。
示例用例:
- 为整个文档中的现有符号添加颜色,可能采用不同的颜色主题:
我要求的\setColor{neg}{blue}
\setColor
命令 在哪里:之后每当使用时,它都会变成蓝色。同样,可以将符号变为粗体或斜体。x
f = \textcolor{blue}{...}
\neg
- 添加后缀或前缀:
其中\newcommand{\hello}{hello} \addSuffix{hello}{ world}
\addSuffix
是搜索的命令x
,并且使用\hello
将写入hello world
。
实现此目的的干净方法可能是仅引入自定义命令来包装每个感兴趣的命令,但这需要调整我的整个(可能)大型文档以用新命令替换前一个命令的所有用法(例如,\neg
-> \coloredneg
)。
这个答案提出了一种基于的解决方案\NewCommandCopy
,当我们必须执行一次此操作时,该解决方案效果很好,但当我们想要重新定义多个命令时就会变得麻烦:
\NewCommandCopy{\oldhello}{\hello}
\renewcommand{\hello}{\hello{} world}
我无法将此模式包装在以要重新定义的命令名称参数化的命令中(\hello
此处)。我所做的一切工作是:
\newcommand{\setColor}[2]{%
%%% Problem: Full inlining via \edef changes behavior. For example, it breaks ensuremath in #1.
\expandafter\edef\csname old#1\endcsname{\csname #1 \endcsname}
\expandafter\renewcommand\csname #1\endcsname{\textcolor{#2}{\csname old#1 \endcsname}}%
}
但这对于某些命令来说会中断(参见评论)。
理想情况下,所讨论的命令x
在应用的修改类型上也是通用的f
。然后x(f, c)
将一个给定的命令f
(它接受一个参数)应用于另一个命令c
以执行c := f(c)
。(也许我们甚至可以允许c
有参数并执行c(a, b, c, ...) := f(c(a, b, c, ...))
?)
从编程语言的意义上讲,我在这里寻找的可能是面向方面编程中的一些轻量级方面或面向特性编程中的特性,其中将一些语法修改应用于现有实现。
答案1
您问了几个不同的问题。
让我们讨论一下无参数宏。添加“前缀”或“后缀”不需要任何特殊代码:
\newcommand{\world}{world}
\AddToHook{cmd/world/before}{Hello }
\AddToHook{cmd/world/after}{!}
\world
假设您想根据配色方案为数学符号着色。
配色方案应该注意将实际的颜色分配给抽象名称:
%%% Color scheme
\colorlet{OP}{<color>}
\colorlet{REL}{<color>}
\colorlet{FENCE}{<color>}
%%%
然后我们可以定义一个\colorize
抽象。
\documentclass{article}
\usepackage{xcolor}
%%% Color scheme
\colorlet{OP}{red!90!green}
\colorlet{REL}{blue!70}
\colorlet{FENCE}{green!70!blue}
%%%
\ExplSyntaxOn
\NewDocumentCommand{\colorize}{mm}{%
\paul_colorize:cNn { __paul_colorize_ \cs_to_str:N #1 : } #1 { #2 }
}
\cs_new_protected:Nn \paul_colorize:NNn
{
\NewCommandCopy{#1}{#2}
\RenewDocumentCommand{#2}{}{\mathcolor{#3}{#1}}
}
\cs_generate_variant:Nn \paul_colorize:NNn { c }
\ExplSyntaxOff
\colorize{\lbrack}{FENCE}
\colorize{\rbrack}{FENCE}
\colorize{\sum}{OP}
\colorize{\leq}{REL}
\begin{document}
\[
\sum_{k=1}^n a_k \leq \lbrack 3+x\rbrack
\]
\end{document}
比如说,的原始含义\lbrack
被保存在,\__paul_colorize_lbrack:
并在重新定义中使用,它被包装为\mathcolor{FENCE}{\__paul_colorize_lbrack:}
现在你可以自己设计一个抽象的抽象了……
答案2
在 OpTeX 中,你的\addSuffix
几乎相当于\addto
:
\def\hello{hello}
\addto\hello{ world}
\hello % prints hello world
控制序列定义的数学对象的颜色可以通过\colorset
宏设置:
\def\colorset#1#2{\slet{ori:\csstring#2}{\csstring#2}% \let\ori:csn=\csn
\def#2{\begingroup#1\cs{ori:\csstring#2}\endgroup}% \def\csn{{\color\ori:csn}}
}
\colorset\Red\sum % each \sum will be in Red color
\colorset\Green\pi % each \pi will be in Green color
$\sum_{i=1}^n a_n = {\pi\over2}$
$$
\sum_{i=1}^n a_n = {\pi\over2}
$$
\bye
使用\begingroup
...\endgroup
代替{
...}
因为我们想保留着色对象的数学类。此外,OpTeX 的颜色不会\pdfliteral
在排版材料中插入任何 s,因为使用了 LuaTeXs 属性。因此,您不必担心像 pdftex 中那样插入的颜色切换器。