Я хочу вручную изменить оглавление. Причина в том, что мой документ не столько состоит из "разделов", сколько из "упражнений". Я написал специальную команду для этого, и она почти работает. Следующие команды помещаются в специальный файл .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
не могу понять.
Итак, мой вопрос: Каким должен быть четвертый аргумент в моем определении? Я бы также хотел узнать, как работает этот четвертый аргумент, но это имеет низкий приоритет.
NB Я не заинтересован в установке каких-либо пакетов, которые могут настраивать ToCs. Я делаю это в качестве практики, поэтому я бы очень хотел использовать .sty
для этого свой собственный файл.
решение1
Обычно любые изменения \contentsline
и т. д. следует вносить до hyperref
загрузки, после этого следует учитывать 4th
аргумент \contentsline
, добавляемый hyperref
.
Аргументом 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
. Поэтому вам не нужно знать, как задать 4-й аргумент \contents
added by hyperref
. Очень простое решение, которое работает независимо от использования hyperref
или нет (и независимо от того, hyperref
загружен ли он до или после дополнительного кода), будет следующим:
\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
like \section
также имеет необязательный аргумент для установки и другого текста для оглавления. Смотрите \exercise[Bar]{Foo-Bar}
в примере.