Когда я вручную записываю данные в файл .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не могу понять.

Итак, мой вопрос: Каким должен быть четвертый аргумент в моем определении? Я бы также хотел узнать, как работает этот четвертый аргумент, но это имеет низкий приоритет.

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-й аргумент \contentsadded 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}

С этим решением \exerciselike \sectionтакже имеет необязательный аргумент для установки и другого текста для оглавления. Смотрите \exercise[Bar]{Foo-Bar}в примере.

Связанный контент