当我手动写入 .toc 文件时,\contentsline 的第四个参数应该是什么?

当我手动写入 .toc 文件时,\contentsline 的第四个参数应该是什么?

我想手动更改目录。原因是我的文档不是由“章节”组成,而是由“练习”组成。我编写了一个自定义命令来执行此操作,它几乎可以正常工作。以下命令放在自定义文件中.sty,在之后加载hyperref

\def\numberline@exer#1{%
\makebox[50pt][l]{\bf Ex. #1\hspace*{1em}}
}

\def\exercise#1{%
\section*{#1}\refstepcounter{exercise}\phantomsection%
\write\@auxout{%
    \protect\@writefile{toc}{%
        \protect\contentsline {section}{\numberline@exer{\theexercise}Title}{\thepage}%
{????}% This is the fourth argument, defined by hyperref
        }%
    }%
}

这基本上就是我想要的,除了它不创建书签。这可能是由于第四个参数。我试图找到如何hyperref重新定义\contentsline,但我发现hyperref.sty无法理解。

所以我的问题是:我的定义中的第四个参数应该是什么? 我也想知道这个第四个参数是如何工作的,但这是低优先级的。

注意:我对安装任何可以自定义目录的软件包不感兴趣。我这样做是为了练习,所以我非常想.sty为此使用我自己的文件。

答案1

通常,\contentsline对等的任何更改都应在加载之前完成hyperref,之后必须考虑由添加4th的参数。\contentslinehyperref

4th参数是超锚点,即类似于section.1或 的东西east.17

超锚点可以插入\@currentHref,它应该提供正确的锚点,因为\phantomsection已经被使用。

为了添加书签,请使用\Hy@writebookmark,因为\contentsline它本身不会添加书签,这是在包装器命令中完成的\addcontentsline,在这里被“绕过”。

\documentclass{article}


\usepackage[bookmarksopen]{hyperref}


\newcounter{exercise}


\makeatletter

\def\numberline@exer#1{%
\makebox[50pt][l]{\bfseries Ex. #1\hspace*{1em}}
}

\def\exercise#1{%
  \phantomsection
  \refstepcounter{exercise}
  \section*{#1}%
  \Hy@writebookmark{\csname theexercise\endcsname}{#1}{\@currentHref}{\toclevel@section}{toc}
  \write\@auxout{%
    \protect\@writefile{toc}{%
      \protect\contentsline {section}{\numberline@exer{\theexercise}#1}{\thepage}{\@currentHref}%
    }%
  }%

}
\makeatother

\usepackage{blindtext}

\begin{document}
\tableofcontents

\section{First section}\label{foosection}

\clearpage

\blindtext[3]
\exercise{Foo}
\blindtext[2]


\end{document}

在此处输入图片描述

更新通常的版本\addcontentsline

\documentclass{article}


\usepackage[bookmarksopen]{hyperref}


\newcounter{exercise}


\makeatletter

\newcommand*\l@exercise[2]{%
  \ifnum \c@tocdepth >\z@
    \addpenalty\@secpenalty
    \addvspace{1.0em \@plus\p@}%
    \setlength\@tempdima{3.8em}%
    \begingroup
      \parindent \z@ \rightskip \@pnumwidth
      \parfillskip -\@pnumwidth
      \leavevmode \bfseries
      \advance\leftskip\@tempdima
      \hskip -\leftskip
      #1\nobreak\hfil \nobreak\hb@xt@\@pnumwidth{\hss #2}\par
    \endgroup
  \fi}



\let\toclevel@exercise\toclevel@section

\newcommand{\exercisebetter}[1]{%
  \refstepcounter{exercise}
  \section*{#1}%
  \addcontentsline{toc}{exercise}{\protect\numberline{Ex: \theexercise}#1}
}


\makeatother

\usepackage{blindtext}

\begin{document}
\tableofcontents

\section{First section}\label{foosection}

\clearpage

\blindtext[3]

\exercisebetter{Foobar}
\blindtext[2]


\end{document}

答案2

我建议不要\write\@auxout直接使用,而是使用\addcontentsline\addcontentsline它会自动尊重\nofile和使用\protected@write,因此您可以使用它\protect来保护脆弱的命令。hyperref如果您使用,它会自动处理书签等\addcontentsline。因此,您不需要知道如何设置\contents由添加的第 4 个参数。一个非常简单的解决方案,它可以独立于使用与否(以及独立于在附加代码之前或之后加载)hyperref工作:hyperrefhyperref

\documentclass{article}
\usepackage[bookmarksopen]{hyperref}

\providecommand*{\texorpdfstring}[2]{#1}% Needed if `hyperref` is not used.
\newcounter{exercise}
\makeatletter
\def\numberline@exer#1{%
  \texorpdfstring{\makebox[50pt][l]{\bfseries Ex. #1\hspace*{1em}}}{Ex. #1}
}

\newcommand\l@exercise{\l@section}
\newcommand*{\exercise}{%
  \@dblarg\@exercise
}
\newcommand*{\@exercise}[2][]{%
  \refstepcounter{exercise}%
  \section*{#2}%
  \addcontentsline{toc}{exercise}{\protect\numberline@exer{\theexercise}#1}%
}
\let\toclevel@exercise\toclevel@section
\makeatother

\usepackage{blindtext}

\begin{document}
\tableofcontents

\section{First section}\label{foosection}

\clearpage

\blindtext[3]
\exercise{Foo}
\blindtext[2]
\exercise[Bar]{Foo-Bar}
\blindtext

\end{document}

使用此解决方案\exercise\section还可以设置可选参数,并为目录设置不同的文本。请参阅\exercise[Bar]{Foo-Bar}示例。

相关内容