如何使用 nameref 引用某个部分而不在该部分的标题中包含任何命令的输出?

如何使用 nameref 引用某个部分而不在该部分的标题中包含任何命令的输出?

背景(简化)

我正在使用todonotes 包nameref将待办事项添加到我的文档中的部分。我创建了一个宏来将待办事项添加到部分,以便它们出现在目录中部分条目的旁边。我还使用hyperref 包通过名称引用文档中的各个部分。部分原因是,我的宏还允许为该部分指定标签。以下是我的宏生成的输出的一个略微简化的版本:

\section[{\todo{A todonote about the foo section}}{foo}]{foo}%
\label{sec:foo}

问题

问题在于,当使用\nameref来引用标题中包含 todonote 的部分时(如上所述),todonote 也会附加到引用中。

梅威瑟:

\documentclass{article}

\usepackage{todonotes}
\usepackage[colorlinks,linkcolor=blue]{hyperref}

\begin{document}

\tableofcontents

\section{foo}
\begin{itemize}
    \item A reference to the \nameref{sec:bar} section
\end{itemize}

\section[{\todo{A todonote about the bar section}}{bar}]{bar}
\label{sec:bar}
A section called bar

\section{baz}
A section called baz

\end{document}

其结果(经过三到四次编译/构建后)如下:

MWE 输出的屏幕截图展示了该问题

发生了什么:

因此,对的调用\nameref{sec:bar}可能生成了一个包含{\todo{A todonote about the bar section}}{bar}todonotes 的引用,因此 (正确但不可取) 生成了重复的 todonote。澄清一下,我希望对 bar 部分的引用生成为 just,bar而不生成重复的 todonote。

寻找解决方案的方法

虽然这是我的用例,但我更愿意知道如何nameref忽略部分标题内的任何命令,因为我觉得这可能更普遍有用(而不仅仅是对我而言)。

顺便提一下,忽略命令的另一种解决方案可能是以nameref某种方式为该部分定义一些特定的参考文本。但是,这并不理想,因为它需要一点维护才能使其与部分名称保持相关。

答案1

Stefan Lehmke 解决方案的简化版本:

\documentclass{article}

\usepackage{etoolbox}
\usepackage{todonotes}
\usepackage[colorlinks,linkcolor=blue]{hyperref}

\makeatletter
\newcommand\@namedisablecommands{}
\newcommand{\addnamedisablecommand}[1]{%
  \g@addto@macro\@namedisablecommands{\renewcommand#1{}}%
  \pdfstringdefDisableCommands{\renewcommand#1{}}%
}
\AtBeginDocument{ 
  \patchcmd{\T@nameref}
  {\let\label\@gobble}
  {\let\label\@gobble\@namedisablecommands}
  {}{}
}
\makeatother

\addnamedisablecommand{\todo[2][]}

注意改变的语法;为了保持 Stefan 的写入

\newcommand{\addnamedisablecommand}[2]{%
  \g@addto@macro\@namedisablecommands{\renewcommand#1#2{}}%
  \pdfstringdefDisableCommands{\renewcommand#1#2{}}%
}

反而。

完成此操作后,\@namedisablecommands将扩展为

\renewcommand\todo[2][]{}

这将抵消其扩张。警告

Package hyperref Warning: Token not allowed in a PDF string (PDFDocEncoding):
(hyperref)                removing `\todo' on input line 47.

\todo可以通过在 的禁用命令列表中添加 (或其他类似命令)来避免hyperref

答案2

有趣的是,\nameref似乎知道有些东西应该被禁用(例如\label),但它没有提供用于调整它的界面。

因此,修补似乎是一个解决方案。我重复一下完整的例子:

\documentclass{article}

\usepackage{etoolbox}
\usepackage{todonotes}
\usepackage[colorlinks,linkcolor=blue]{hyperref}

\makeatletter
\newcommand\@namedisablecommands{}%
\newcount\@namedisablegenericmacro
\newcommand\addnamedisablecommand[2]
{%
  \global\advance\@namedisablegenericmacro\@ne
  \expandafter\newcommand
  \csname @namedisablegobble\number\@namedisablegenericmacro\endcsname
  #2{}%
  \global\expandafter\let
  \csname @namedisablegobble\number\@namedisablegenericmacro\expandafter\endcsname
  \csname @namedisablegobble\number\@namedisablegenericmacro\endcsname
  \edef\@namedisablecommands{%
    \unexpanded\expandafter{\@namedisablecommands}%
    \let\noexpand#1\expandafter\noexpand
    \csname @namedisablegobble\number\@namedisablegenericmacro\endcsname
  }%
}
\AtBeginDocument
{%
  \patchcmd{\T@nameref}
  {\let\label\@gobble}
  {\let\label\@gobble\@namedisablecommands}
  {}{}%
}
\addnamedisablecommand{\todo}{[2][]}
\expandafter\pdfstringdefDisableCommands\expandafter
{%
  \@namedisablecommands
}%
\makeatother
\begin{document}

\tableofcontents

\section{foo}
\begin{itemize}
\item A reference to the \nameref{sec:bar} section
\end{itemize}

\section[{\todo{A todonote about the bar section}}{bar}]{bar}
\label{sec:bar}
A section called bar

\section{baz}
A section called baz

\end{document}

在此处输入图片描述

相关内容