在宏中嵌入 \soulomit

在宏中嵌入 \soulomit

在下面的 MWE 中,代码:

\MyUl{abd \soulomit{\MyLink{www.google.com}{The Google}} ghi}

完全按照预期工作:

在此处输入图片描述

但是,当我尝试将其包装在宏中并使用时

\MyUl{abd \SoulOmitMyLink{www.google.com}{The Google} ghi}

我得到:

\SoulOmitMyLink 的参数有一个额外的}。

问题:

\SoulOmitMyLink为了使其发挥作用,需要进行哪些改变?

笔记:

  • 以下不是我当前用例的选项:

    \MyUl{abd} \MyLink{www.google.com}{The Google}  \MyUl{ghi}
    

代码:

\documentclass{article}
\usepackage{xcolor}
\usepackage{xparse}
\usepackage{soul}
\setulcolor{red}

\usepackage{hyperref}

\NewDocumentCommand{\MyUl}{%
    s%   #1 = starred variant
    O{}% #2 = options, if any
    m%   #3 = mandatory param
}{%
    \ul{#3}%
}%

\NewDocumentCommand{\MyLink}{%
    s%   #1 = starred variant  (unused as of yet)
    O{}% #2 = options, if any  (unused as of yet)
    m%   #3 = link text
    m%   #4 = link target
}{%
    \href{#3}{#4}%
}%

\NewDocumentCommand{\SoulOmitMyLink}{%
    s%   #1 = starred variant  (unused as of yet)
    O{}% #2 = options, if any  (unused as of yet)
    m%   #3 = link text
    m%   #4 = link target
}{%
    \IfBooleanTF{#1}{%
        \soulomit{\MyLink*[#2]{#3}{#4}}%
    }{%
        \soulomit{\MyLink[#2]{#3}{#4}}%
    }%
}%


\begin{document}
\MyUl{abd \soulomit{\MyLink{www.google.com}{The Google}} ghi}

%\MyUl{abd \SoulOmitMyLink{www.google.com}{The Google} ghi}% I want this
\end{document}

答案1

正如约瑟夫·赖特在他的回答soul不支持任意命令。以下示例显示了如何soul扩展以支持。它挂接到处理数据的\SoulOmitMyLink代码中。针对第二个参数为的情况插入代码。然后还测试第一个参数中的命令,看它是否为,并添加针对这种情况的特殊处理。\SOUL@docmd\soulregister\soulregister8\SoulOmitMyLink

\documentclass{article}
\usepackage{xcolor}
\usepackage{xparse}
\usepackage{soul}
\setulcolor{red}

\usepackage[colorlinks]{hyperref}

\NewDocumentCommand{\MyUl}{%
    s%   #1 = starred variant
    O{}% #2 = options, if any
    m%   #3 = mandatory param
}{%
    \ul{#3}%
}%

\NewDocumentCommand{\MyLink}{%
    s%   #1 = starred variant  (unused as of yet)
    O{}% #2 = options, if any  (unused as of yet)
    m%   #3 = link text 
    m%   #4 = link target
}{%
    \href{#3}{#4}%
}%

\NewDocumentCommand{\SoulOmitMyLink}{%
    s%   #1 = starred variant  (unused as of yet) 
    O{}% #2 = options, if any  (unused as of yet)
    m%   #3 = link text
    m%   #4 = link target
}{%  
    \IfBooleanTF{#1}{%
        \soulomit{\MyLink*[#2]{#3}{#4}}%
    }{%
        \soulomit{\MyLink[#2]{#3}{#4}}%
    }%
}%

%%% Patch begin %%%
\usepackage{etoolbox}
\makeatletter
\patchcmd\SOUL@docmd{\else\ifx7}{%
  \ifx\SoulOmitMyLink#2%
    \SOUL@doword
    \let\SOUL@@\@undefined
    \NewDocumentCommand{\SOUL@@}{sO{}mm}{%
      \IfBooleanTF{##1}{%
        \soulomit{\SoulOmitMyLink*[##2]{##3}{##4}}%
      }{%
        \soulomit{\SoulOmitMyLink[##2]{##3}{##4}}%
      }%
      \SOUL@scan
    }%
  \fi
  \else\ifx7%
}{%
  \soulregister{\SoulOmitMyLink}{8}%
}{}
\makeatother
%%% Patch end %%%

\begin{document}
\MyUl{abd \soulomit{\MyLink{www.google.com}{The Google}} ghi}

\MyUl{abd \SoulOmitMyLink{www.google.com}{The Google} ghi}% I want this
\end{document}

结果

(我已使用选项colorlinkshyperref更清楚地表明您不希望有链接线。)

更新

  • 根据 Peter Grill 的说法评论\SoulOmitMyLink不再需要该宏。
  • 的重定义\SOUL@@扫描 的参数,\MyLink不需要检查参数并调用。如果宏是通过 定义的,\MyLink它可以直接将参数传递给\MyLink␣code,即定义的内部宏。xparse\NewDocumentCommand

更新后的更短的示例文件:

\documentclass{article}
\usepackage{xcolor}
\usepackage{xparse}
\usepackage{soul}
\setulcolor{red}

\usepackage[colorlinks]{hyperref}

\NewDocumentCommand{\MyUl}{%
    s%   #1 = starred variant
    O{}% #2 = options, if any
    m%   #3 = mandatory param
}{%
    \ul{#3}%
}%

\NewDocumentCommand{\MyLink}{%
    s%   #1 = starred variant  (unused as of yet)
    O{}% #2 = options, if any  (unused as of yet)
    m%   #3 = link text
    m%   #4 = link target
}{%
    \href{#3}{#4}%
}%

\usepackage{etoolbox}
\makeatletter
\patchcmd\SOUL@docmd{\else\ifx7}{%
  \ifx\MyLink#2%
    \SOUL@doword
    \let\SOUL@@\@undefined
    \NewDocumentCommand{\SOUL@@}{sO{}mm}{%
      \csname MyLink code\endcsname{##1}{##2}{##3}{##4}%
      \SOUL@scan
    }%
  \fi
  \else\ifx7%
}{%
  \soulregister{\MyLink}{8}%
}{}
\makeatother

\begin{document}
\tracingmacros=1
\MyUl{abd \soulomit{\MyLink{www.google.com}{The Google}} ghi}

\MyUl{abd \MyLink{www.google.com}{The Google} ghi}% I want this
\end{document}

答案2

soul包的工作原理是对输入进行逐个标记的分解,\soulomit如果它出现在要分解的文本中,则可以绕过它。在您的示例中\soulomit不是出现在看到的输入中soul。发生的事情是soul提取\SoulOmitMyLink并尝试在不带参数的情况下使用它,这就是错误出现的地方。底线:你不能隐藏\soulomit在另一个宏中,因为soul它将其视为文字而不是正在使用的内容(它实际上并没有任何事物)。

相关内容