这是使用间接格式的 Soul,其中确定使用\soulregister
允许宏soul
在参数中包含字体切换宏(特别是\ul
在这种情况下)。但是,如果宏有多个参数,我就无法让它工作。
单个参数:\ApplyStyleA
如果宏有一个强制参数,这似乎可以正常工作,如使用间接格式的 Soul。
两个必需参数:\ApplyStyleB
但是,如果宏有两项强制性规定参数,然后我得到:
额外的 },或者被遗忘的 \endgroup
两个参数(一个可选):\ApplyStyleC
或者,对于存在的情况一个可选的参数和一项强制性规定参数,我得到:
TeX 容量超出,抱歉 [输入堆栈大小=5000]
笔记:
- 下面的 MWE 编译正常,因为有问题的两行被注释掉了。因此,需要取消注释其中一行才能重现问题。
代码:
\documentclass{article}
\usepackage{xparse}
\usepackage{xcolor}
\usepackage{soul}
\usepackage{xspace}
%% ----------------------------------------------------------------
%% https://tex.stackexchange.com/questions/36894/
%% underline-omitting-the-descenders
%%
%%
\makeatletter
\ExplSyntaxOn
\cs_new:Npn \white_text:n #1
{
\fp_set:Nn \l_tmpa_fp {.01}
\fp_mul:Nn \l_tmpa_fp {#1}
\llap{\textcolor{white}{\the\SOUL@syllable}\hspace{\fp_to_decimal:N \l_tmpa_fp em}}
\llap{\textcolor{white}{\the\SOUL@syllable}\hspace{-\fp_to_decimal:N \l_tmpa_fp em}}
}
\NewDocumentCommand{\whiten}{ m }
{
\int_step_function:nnnN {1}{1}{#1} \white_text:n
}
\ExplSyntaxOff
\NewDocumentCommand{ \varul }{ D<>{5} O{0.2ex} O{0.1ex} +m } {%
\begingroup
\setul{#2}{#3}%
\def\SOUL@uleverysyllable{%
\setbox0=\hbox{\the\SOUL@syllable}%
\ifdim\dp0>\z@
\SOUL@ulunderline{\phantom{\the\SOUL@syllable}}%
\whiten{#1}%
\llap{%
\the\SOUL@syllable
\SOUL@setkern\SOUL@charkern
}%
\else
\SOUL@ulunderline{%
\the\SOUL@syllable
\SOUL@setkern\SOUL@charkern
}%
\fi}%
\ul{#4}%
\endgroup
}%
\makeatother
%% ----------------------------------------------------------------
\newcommand{\ApplyStyleA}[1]{\textit{#1}}
\soulregister\ApplyStyleA{1}
\newcommand{\ApplyStyleB}[2]{\textit{#1}}
\soulregister\ApplyStyleB{2}
\newcommand{\ApplyStyleC}[2][]{\textit{#2}}
\soulregister\ApplyStyleC{2}
\begin{document}
This one works just fine:
\varul{\ApplyStyleA{special text}\xspace}%
\medskip
These one leads to ``Extra \}, or forgotten \verb|\endgroup|."
%\varul{\ApplyStyleB{special text}{second paramater}\xspace}%
\medskip
This one leads to ``TeX capacity exceeded, sorry [input stack size=5000]"
%\varul{\ApplyStyleC[first optional paramater]{special text}\xspace}%
\end{document}
答案1
所使用的数字\soulregister
本身并不指定参数的数量。
它用作标识符。数字7
、8
和分别9
用于\textsuperscript
(“和类似”)\footnote
和重音符号。
根据两个参数的作用\ApplyStyleB
(它们都是需要排版的内容还是其中一个用于其他目的),有多种可能的解决方案。
对于宏来说也是如此,\ApplyStyleC
尽管这更难修复,因为默认值#1
是隐藏的。
\ApplyStyleBa
请注意简单扩展(type ) 与扩展内容之间的区别3
,简单扩展会将下划线应用于所有内容\ApplyStyleBa
。\ApplyStyleBb
宏使用正确的宏方式1
,并将soul
ing 仅应用于其参数 (type 2
)。
类型4
包括一个可选参数。如果您希望soul
的效果也影响默认可选参数(在您的情况下为空字符串,在我的情况下为I'm the default!
),则应提取所述默认文本并将其用于 的重新定义\SOUL@@
。
但是,如果您使用可选参数不是为了排版,而是为了在其他地方使用,则需要采用不同的方法。一些宏(\minipage
或\parbox
)将其第一个强制参数用作维度,将可选参数用作对齐。对于这两者,都不应应用下划线。
代码
\documentclass{article}
\usepackage{xparse}
\usepackage{xcolor}
\usepackage{soul}
\usepackage{xspace}
%% ----------------------------------------------------------------
%% http://tex.stackexchange.com/questions/36894/
%% underline-omitting-the-descenders
%%
%%
\makeatletter
\ExplSyntaxOn
\cs_new:Npn \white_text:n #1
{
\fp_set:Nn \l_tmpa_fp {.01}
\fp_mul:Nn \l_tmpa_fp {#1}
\llap{\textcolor{white}{\the\SOUL@syllable}\hspace{\fp_to_decimal:N \l_tmpa_fp em}}
\llap{\textcolor{white}{\the\SOUL@syllable}\hspace{-\fp_to_decimal:N \l_tmpa_fp em}}
}
\NewDocumentCommand{\whiten}{ m }
{
\int_step_function:nnnN {1}{1}{#1} \white_text:n
}
\ExplSyntaxOff
\NewDocumentCommand{ \varul }{ D<>{5} O{0.2ex} O{0.1ex} +m } {%
\begingroup
\setul{#2}{#3}%
\def\SOUL@uleverysyllable{%
\setbox0=\hbox{\the\SOUL@syllable}%
\ifdim\dp0>\z@
\SOUL@ulunderline{\phantom{\the\SOUL@syllable}}%
\whiten{#1}%
\llap{%
\the\SOUL@syllable
\SOUL@setkern\SOUL@charkern
}%
\else
\SOUL@ulunderline{%
\the\SOUL@syllable
\SOUL@setkern\SOUL@charkern
}%
\fi}%
\ul{#4}%
\endgroup
}%
\def\SOUL@docmd#1#2{%
\ifx9#1%
\def\SOUL@@{\SOUL@addgroup{#2}}%
\else\ifx8#1%
\SOUL@doword
\def\SOUL@@##1{%
\SOUL@token={\footnotemark}%
\SOUL@everytoken
\SOUL@syllable={\footnotemark}%
\SOUL@everysyllable
\footnotetext{##1}%
\SOUL@doword
\SOUL@scan
}%
\else\ifx7#1%
\SOUL@doword
\def\SOUL@@##1{%
\SOUL@token={#2{##1}}%
\SOUL@everytoken
\SOUL@syllable={#2{##1}}%
\SOUL@everysyllable
\SOUL@doword
\SOUL@scan
}%
\else\ifx1#1%
\SOUL@doword
\def\SOUL@@##1{%
#2{\protect\SOUL@do{##1}}%
\SOUL@scan
}%
\else\ifx2#1%
\SOUL@doword
\def\SOUL@@##1##2{%
#2{\protect\SOUL@do{##1}}{\protect\SOUL@do{##2}}%
\SOUL@scan
}%
\else\ifx3#1%
\SOUL@doword
\def\SOUL@@{\expandafter\SOUL@scan#2}%
\else\ifx4#1
\SOUL@doword
\def\@tempa{\renewcommand\SOUL@@[2][}%
\expandafter\expandafter\expandafter\@tempa\expandafter\SOUL@get@optional@argument#2]{#2[\protect\SOUL@do{##1}]{\protect\SOUL@do{##2}}}%
\else
\SOUL@doword
#2%
\let\SOUL@@\SOUL@scan
\fi\fi\fi\fi\fi\fi\fi
\SOUL@@
}
\def\SOUL@get@optional@argument#1#2#3#4{#4}%
\makeatother
%% ----------------------------------------------------------------
\newcommand{\ApplyStyleA}[1]{\textit{#1}}
\soulregister\ApplyStyleA{1}
\newcommand{\ApplyStyleBa}[2]{\textit{#1} affected? (#2)}
\soulregister\ApplyStyleBa{2}
\newcommand{\ApplyStyleBb}[2]{\textit{#1} affected? (#2)}
\soulregister\ApplyStyleBb{3}
\newcommand{\ApplyStyleC}[2][I'm the default!]{\textit{#2} (I'm not affected again) [#1]}
\soulregister\ApplyStyleC{4}
\begin{document}
\varul{\ApplyStyleA{special text}\xspace}%
\medskip
\varul{\ApplyStyleBa{special text}{second paramater}\xspace}\par %
\varul{\ApplyStyleBb{special text}{second paramater}\xspace}% only expansion
\medskip
\varul{\ApplyStyleC[first optional paramater]{special text}\xspace}\par
\varul{\ApplyStyleC{special text}\xspace}%
\end{document}