% \iffalse meta-comment % %% File: latex-lab-sec-template.dtx % % Copyright (C) 2026 The LaTeX Project % % It may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this % license or (at your option) any later version. The latest version % of this license is in the file % % https://www.latex-project.org/lppl.txt % % % The latex-lab bundle is developed in the LaTeX2e GitHub. % Issues may be reported at % % https://github.com/latex3/latex2e/issues % \def\ltlabsecIIdate{2026-01-14} \def\ltlabsecIIversion{0.9a} %<*driver> \DocumentMetadata{tagging=on,pdfstandard=ua-2,testphase=sec-template} \documentclass[kernel]{l3in2edoc} \usepackage{amstext} \usepackage{xcolor} \EnableCrossrefs \CodelineIndex \usepackage{todonotes} \begin{document} \DocInput{latex-lab-sec-template.dtx} \end{document} % % % \fi % % % \newcommand\key[1]{\texttt{#1}} % % % \NewDocumentCommand\fmi{sO{}m} % {\IfBooleanTF{#1}{\todo[inline,#2]{#3}}^^A % {\todo[#2]{#3}}} % % \NewDocumentCommand\ufi{sO{}m} % {\IfBooleanTF{#1}{\todo[inline,#2]{UFi:#3}}^^A % {\todo[#2]{UFi:#3}}} % % % \title{Reimplementation of \LaTeXe{}'s heading commands using templates} % \author{\LaTeX{} Project\thanks{Initial implementation by Frank Mittelbach.}} % \date{v\ltlabsecIIversion\ \ltlabsecIIdate} % % \maketitle % % % % \begin{abstract} % \end{abstract} % % % \tableofcontents % \medskip % % % \begin{documentation} % % % % \section{Introduction} % This module reimplements tagging aware heading commands with templates. % The new implementation is used automatically if \cs{DocumentMetadata} is used % and replaces patches and redefinitions done in the \texttt{latex-lab-sec}. % In a later step both modules will be merged. % % Most of the documentation is of interest only for class and package authors % who want to setup their own heading commands but the new implementation changes % also the user interface. This is documented first. % % \section{Changes to the user interface} % % \subsection{New user commands} % \DescribeMacro\theheading % This command expands inside a heading to the current number. % % \DescribeMacro\partmark % This replaces the fix \verb+\markboth{}{}+ or similar in the standard \cs{part} % definition. % % % \subsection{The optional argument} % The standard heading commands (re)defined by this module use the standard 2e syntax, e.g., % \begin{verbatim} % \section[toc]{title} % \end{verbatim} % The star-form \verb+\section*{Title}+ % stops the numbering, toc, bookmark and running header % as it was the way for the last 30-odd years. % New is that the optional argument is handled as a key/val list if an equal sign at the outer level % is detected, otherwise the argument is taken to be the value of the \key{shorttitle} % and passed to the table of contents, the running headers, the bookmarks and used % with \cs{nameref}. Note that this means, that % \begin{verbatim} % \section*[Title]{Title} % \end{verbatim} % will create a toc entry and a bookmark! % % The following keys can be used % \begin{description} % \item[\key{toc}] This sets the text for the table of contents. It also forces % that the entry is created. So % \begin{verbatim} % \section*[toc=Introduction]{Introduction to this document} % \end{verbatim} % will create an unnumbered entry \enquote{Introduction} in the table of contents. % An empty value (i.e., \texttt{toc=}) will suppress the toc entry. % % \item[\key{running}] This sets the text for the running header and forces the % use of the mark command, so even with a starred section the header will be updated. % An empty value will suppress the call of the mark commands, so a header from a % previous section will prevail. % % \item[\key{bookmark}] This sets the text for the bookmarks (the PDF outline) % if, e.g., hyperref is loaded. As with the previous keys and empty value suppresses % the bookmark entry. % % \item[\key{nameref}] This allows to set the text used for a crossreference % with \cs{nameref}. % % \item[\key{label}] This sets a label, so is an alternative to using a % \cs{label} command. % % \item[\key{subtitle}, \key{quote}] Theses keys will allow to pass a subtitle and % a quote to the underlying code, but currently they are not yet used % by the implementations of the standard \LaTeX{} heading commands. % % \item[\key{shorttitle}] There is the key which is used if the % optional argument is not of key/val form. So, % \begin{verbatim} % \section[short]{long title} % \end{verbatim} % is the same as % \begin{verbatim} % \section[shortitle=short]{long title} % \end{verbatim} % The key sets the toc, running, bookmark and nameref text. % % \item[\key{numbered}, \key{unnumbered}] This allow to control % the numbering without stopping toc, running head or bookmarks as it would happen % with the starred version of the heading command. % % \item[template keys] Any other key present is assumed to be a key that should % be passed to the heading instance to overwrite some of its % settings. So, e.g., % \begin{verbatim} % \section[placement=top,number-format=\fbox{\theheading}]{Title} % \end{verbatim} % will force the section to start a new page and put the number into an \cs{fbox}. % For a list of supported keys, check the following parts of the documentation. % \end{description} % % \subsection{Class support} % % The module redefines all heading commands of the three standard classes, \pkg{article}, % \pkg{report} and \pkg{book} to use the new implementation. % % Heading commands of other classes that are defined with \cs{@startsection} are % supported (with some restrictions) through a compatibility layer described in the next section. % % The heading commands \cs{part} and \cs{chapter} are typically defined with % \cs{secdef} and the internal command \cs{@part} and \cs{@chapter}. The module % redefines \cs{secdef} to use the standard instances for these commands---this adds tagging support % but \emph{changes the layout} until the class provides its own instances. % % For the ams-classes, \texttt{latex-lab-firstaid} contains instances for % \cs{part} and \cs{chapter}. They comes near to the original layout but not exactly. % % Other heading commands defined with \cs{secdef} will error % as the code has no real chance to know how to handle such a heading. % % Heading commands which uses neither \cs{@startsection} or \cs{secdef} (e.g, the % \cs{chapter} command of \pkg{memoir}, or the heading commands of \pkg{KOMA} classes) % are not changed by this module and so will not be tagged correctly unless they add % explicit tagging support. % % \subsection{Changing heading commands}\label{sec:startsection} % % It is possible to change heading commands by editing the instance they use. % E.g., in the standard classes one could frame every heading number with % \begin{verbatim} % \EditInstance{heading}{section} % {number-format=\fbox{\theheading}} % \end{verbatim} % The name of the instance is the same as the heading command. % % To support other classes which still setup their heading commands with % \cs{@startsection} the code has a legacy compatibility layer: the % \cs{@startsection} command has been redefined to setup instances on-the-fly % at the first use of a heading command. These instances have names using the % the first argument of \cs{@startsection} with an attached \texttt{-@startsection}. % As they are created on-the-fly these internal instances can be only edited % \emph{after} the first use of the heading command. Also as the names of the instances % are built from the first argument of \cs{@startsection} % it is not possible to define two different heading commands % of the same level with \cs{@startsection} as that would require two instances with % different names. The next section describes how to lift this restrictions by converting % such sectioning commands to use the new interfaces. % % \subsection[label=sec:convert]{Converting heading commands defined with \cs{@startsection}} % % To convert a heading command defined with \cs{@startsection} to the new interface suitable % instances must be declared. The same needs to happen if one wants to alter % the layout of a heading that was defined with \cs{@startsection} in the document preamble. % How this can be done is demonstrated here with the \cs{section} % command of the \pkg{ltugboat} class. % % \subsubsection{Step 1: Getting the template name and the instance values} % % The sectioning commands use two template \emph{types}, \texttt{heading} and \texttt{headformat}. % Compile the following document % % \begin{verbatim} % \DocumentMetadata{} % \documentclass{ltugboat} % % \begin{document} % % \section{test} % <--- needed so that the instances get defined % \ShowInstanceValues{heading}{section-@startsection} % \ShowInstanceValues{headformat}{section-@startsection} % % \end{document} % \end{verbatim} % % This will show the instance values in the log-file: % \begin{verbatim} % The instance 'section-@startsection' of type 'heading' has values: % > level => 1 % > placement => normal % > mark-cmd => \sectionmark {##1} % > para-indent => false % > before-sep => 8.0pt plus 2.0pt minus 2.0pt % > penalty => \c_max_int % > after-penalty-sep => 0pt % > after-sep => 4.0pt % > start-code => % > final-code => % > decls => \tubsecfmt % > number-decls => % > title-decls => % > subtitle-decls => % > quote-decls => % > headformat-instance => section-@startsection % > number-format => \theheading % > contents-extra => % > name => section % > from template => display. % % % The instance 'section-@startsection' of type 'headformat' has values: % > indent => 0pt % > before-code => \tubsecfmt % > after-code => % > number-title-sep => 1em % > from template => hang. % \end{verbatim} % % \subsubsection{Step 2: Get the default template values} % % The last line in both lists show after the \texttt{from template} the names of the % templates of each type. That can be used to get the default values of these templates. % Compile the following document:% % \begin{verbatim} % \DocumentMetadata{} % \documentclass{ltugboat} % % \begin{document} % \ShowTemplateDefaults{heading}{display} % \ShowTemplateDefaults{headformat}{hang} % \end{document} % \end{verbatim} % % This gives in the log and terminal: % \begin{verbatim} % The template 'display' of type 'heading' has default values: % > level => 0 % > placement => normal % > mark-cmd => % > para-indent => false % > before-sep => 0pt % > penalty => \c_max_int % > after-penalty-sep => 0pt % > after-sep => 0pt % > start-code => % > final-code => % > decls => \normalfont % > number-decls => % > title-decls => % > subtitle-decls => % > quote-decls => % > headformat-instance => hang % > number-format => \theheading % > contents-extra => . % % The template 'hang' of type 'headformat' has default values: % > indent => 0pt % > before-code => % > after-code => % > number-title-sep => 1em. % \end{verbatim} % % \subsection{Step 3: Declare the instances} % By comparing the instance values with the default values one can see which values % should be changed in the instance. The names of the new instances can be % freely chosen best practice is to use the name % of the heading command (without a backslash). % % This leads then to these declarations: % \begin{verbatim} % \DeclareInstance{heading}{section}{display} %#1=heading, #2=name, #3=template name % { % level = 1, % mark-cmd = \sectionmark{#1}, % remove second hash % before-sep = 8.0pt plus 2.0pt minus 2.0pt, % after-sep = 4.0pt, % decls = \tubsecfmt, % headformat-instance = section, % new name % } % \DeclareInstance{headformat}{section}{hang} %#1=heading, #2=name, #3=template name % { % before-code = \tubsecfmt % } % \end{verbatim} % % \subsubsection{Step 4 Redefine the \cs{section} command} % % At last the heading should be defined to use the new interface. % \begin{verbatim} % \DeclareDocumentCommand \section {s ={shorttitle}o m} % { \ParseLaTeXeHeading {section} {#1} {#2} {#3} } % \end{verbatim} % % \section{Setting up \LaTeXe{} heading commands in classes} % % Heading commands are managed by defining an instance of the % \texttt{heading} template and then using through \cs{ParseLaTeXeHeading}, e.g., % \begin{verbatim} % \DeclareDocumentCommand \part {s ={shorttitle}o m} % { \ParseLaTeXeHeading {part} {#1} {#2} {#3} } % \end{verbatim} % The name of the \texttt{heading} instance is given in the first argument % of \cs{ParseLaTeXeHeading} and it is recommended that classes use the % same name as the heading command, to make it easier for users to identify the % instance to edit if they want to adapt the command. Examples of instances % that mimic the behavior of the heading commands in the standard classes can be found % below. Section~\ref{label=sec:convert} shows how to get instances from commands % previously defined with \cs{@startsection}. % % Legacy setup using \cs{@startsection} remains supported albeit % not that performant and with some restrictions for the users, % see section \ref{sec:startsection} above and in the documentation below. % % In contrast \cs{secdef} is only rudimentarly supported. It delegates the % layout to two commands which can contain arbitrary code (usually % hardwired) so that there is no realistic chance to take this % apart and figure out what values should be used for what template % parameters. We therefore redefine \cs{secdef} and % map the standard commands \cs{part} % and \cs{chapter} to the standard instance and error if other uses are detected. % Classes using \cs{secdef} should setup suitable instances that % mimic their current layout, an example can be found for the % ams-classes in \texttt{latex-lab-firstaid.dtx}. % % % \section{Open points} % % \begin{itemize} % \item There is no good interface yet to change e.g. the font family of all heading % commands in one go. % \item Support for \texttt{titlesec}, see section \ref{label=sec:titlesec}. % \item Decide if \texttt{before-code} and \texttt{after-code} is combined into a % format command. % \end{itemize} % % \section{Template types and templates for headings} % % The template(s) for headings expect(s) a large number of % positional arguments containing document user data. The % document-level command, e.g., \cs{section} may not offer all of % them directly, but may do so via a key value interface or not at % all. If no interface is provided then the template is passed % \cs{NoNalue} . If it is offered via a key value interface, % the template receives whatever is set by the user (and % \cs{NoNalue} otherwise). % % In my initial implementation I had only the main data as % positional arguments, but I came to the conclusion that this % scheme here is better going forward. % % \subsection{Template types} % % The template type \texttt{heading} has 10 data arguments, which is % more than can be specified as positional arguments. For that % reason argument \#9 holds 2 brace groups. The alternative would % be to specify such arguments as keys, but for a number of reasons % I think the approach to put seldom necessary data arguments all % in the last positional argument is actually better (besides being faster). % % \begin{TemplateInterfaceDescription}{heading} % \TemplateArgument{1}{key/value list to alter the default heading parameters} % \TemplateArgument{2}{unnumbered heading?} % \TemplateArgument{3}{main title of the heading} % \TemplateArgument{4}{toc title} % \TemplateArgument{5}{running title} % \TemplateArgument{6}{bookmark title} % \TemplateArgument{7}{nameref text} % \TemplateArgument{8}{label for the heading in the form \cs{label}\{\meta{string}\}} % \TemplateArgument{9}{\{ sub title \} \{ quotation \}} % \TemplateSemantics % Handles the layout and processing aspects of a heading. % % Whether or not the heading is numbered is governed through a % boolean, expecting the result of an \texttt{s} specification of % \cs{NewDocumentCommand} or equivalent, i.e., expects % \cs{BooleanTrue} or \cs{BooleanFalse}. % % If the title data is also used for bookmarks, toc, running % header, and cross references then it has to be given several times which % can be arranged for by the parsing interface command that calls % the template instance. % % If the bookmark, toc, or running argument is set to % \enquote{empty} then the bookmark, toc or running header should % be suppressed by the template. This enables the user on document % level to explicitly specify, for example, \texttt{[bookmark=]} to % suppress the bookmark. % % The \texttt{nameref} argument is not expected to be empty. Its value % should always be used as given if named references are to be % generated. % % The label argument either holds a \cs{label} command as provided % by the user (or several, see implementation of % \cs{ParseLaTeXeHeading}) or it is empty. I.e., it can be directly % executed by a template at the right point where the reference % counter (if any) has been set up without the need to check its % content. % % Argument \#9 holds further user data (in brace groups) which are % seldom implemented, but if they are the data is available in a % positional argument, which then needs to be taken apart using % \cs{@firstoftwo} (for subtitle) or \cs{@secondoftwo} (for a % quotation). If no data is provided \cs{NoValue} is used to % indicate that. % % \end{TemplateInterfaceDescription} % % % \begin{TemplateInterfaceDescription}{headformat} % \TemplateArgument{1}{key/value list to alter the default headformat parameters} % \TemplateArgument{2}{formatted heading number} % \TemplateArgument{3}{main title of the heading} % \TemplateArgument{4}{subtitle} % \TemplateArgument{5}{quotation} % \TemplateSemantics % Handles the layout of just the label, main title, subtitle, and % quotation but not the spatial relation to previous and following text. % % Whether or not the heading is numbered is governed through a % boolean, e.g., result of an \texttt{s} specification in % \cs{NewDocumentCommand} or equivalent. % % If there is no subtitle or quotation then this is indicated % with \cs{NoValue}. % % Note: instead of unnumbered + counter we could just have a single % argument containing the number representation (or \cs{NoValue} if % not used). The reason that there are two is that this allows us to % continue to support \cs{@seccntformat}, but I'm not sure this is a % good enough reason. % % \end{TemplateInterfaceDescription} % % % % \subsection{Templates} % % % There are a number of keys that are expected to be recognized by % all heading templates (though they may choose not to make use of % them). These are listed below instead of being repeated on the % actual templates. % % All other keys are either attached to the \texttt{heading} or to % the \texttt{headformat} templates. Those that typically vary % from heading instance to the next (e.g., \key{decls}) are % all declared in the % \texttt{heading} templates even if they are actually only used % within \texttt{headformat} templates. In other words, % \texttt{headformat} templates have a number of implicit % variables that they expect to be set.\footnote{Maybe questionable} % % % \begin{TemplateDescription}{heading}{\meta{all}} % % \TemplateKey{name}{tokenlist} % {Referencable name of the heading instance. String that % is acceptable in csnames for use in building counter % names, etc.}{} % \TemplateKey{parent-name}{tokenlist} % {Name of the next higher heading instance. If not % given, then the internal heading level of the heading % instance is set to \texttt{0}}{} % \TemplateKey{reset-counter}{tokenlist} % {Name of the heading instance that should reset the % numbering of this heading level (if any)}{} % \TemplateKey{level}{integer} % {Sets the internal heading-level rather than deducing % it from \key{parent-name}. Can be used to specify the % top-level heading if not \texttt{0}, or all headings % in legacy implementations, e.g., through \cs{@startsection}}{} % % \TemplateKey{placement}{choice} % {Set the heading placement, i.e., the behavior of the % heading with respect to page breaks. Allowed values % are % \texttt{page} (heading forms a page if its own), % \texttt{top} (heading starts a new page), % \texttt{normal} (heading can appear anywhere on the % page). Further possibilities might be % \texttt{rectopage} and \texttt{rectotop} if we % implement that.}{\texttt{normal}} % % \TemplateKey{start-code}{tokenlist} % {Default value is set by the \key{placement} % key. Executed before the heading starts, so can issue, for % example, a \cs{clearpage}} % {} % % \TemplateKey{final-code}{tokenlist} % {Default value is set by the \key{placement} % key. Executed after the heading is typeset. Can set up code for % putting the heading on a page by its own, or arrange for % paragraph handling of a following paragraph, etc.} % {} % % \TemplateKey{mark-cmd}{function(1)} % {Function that receives the \meta{running} argument and % creates a suitable mark insertion} % {\texttt\textbackslash\meta{name}\texttt{mark}} % % \TemplateSemantics % % The above keys should be implemented by all heading templates. % % At the moment I have retained the \LaTeXe{} interfaces for marks, % e.g., one has to set up \cs{chaptermark}, \cs{sectionmark}, % etc.\ but I'm not sure this should stay (even though it is is % certainly simpler from a compatibility perspective. % % All templates should set up \cs{theheading} to correspond to % \cs{the\meta{name}}. % \end{TemplateDescription} % % % \begin{TemplateDescription}{heading}{display} % % \TemplateKey{para-indent}{boolean} % {Should the paragraph after the heading be indented?} % {false} % % \TemplateKey{before-sep}{skip} % {Vertical space before the heading if there is no page % or column break. If there is one it vanishes. % In particular this means it will not be used in the % heading \texttt{placement}s \texttt{page} or \texttt{top}} % {0pt} % % \TemplateKey{penalty}{integer} % {Penalty to break before the heading. The default % (\TeX's largest integer) indicates that no penalty was set in % which case \cs{@secpenalty} is used.} % {\number\maxdimen} % % \TemplateKey{after-penalty-sep}{skip} % {Vertical space before the heading but after the % penalty for the heading. If the penalty results in a page or % column break, this space remains at the top of the page} % {0pt} % % \TemplateKey{after-sep}{skip} % {Vertical space after the heading} % {0pt} % % \TemplateKey{decls}{tokenlist} % {Declarations (such as font or color settings) applied % to all heading elements, i.e., number, title, % subtitle, and quotation, if present.} % {\cs{normalfont}} % % \TemplateKey{number-decls}{tokenlist} % {Declarations (such as font or color settings) applied % to the heading number, overwriting the setting % of \key{decls}.} % {\meta{empty}} % % \TemplateKey{title-decls}{tokenlist} % {Declarations (such as font or color settings) applied % to the heading title, overwriting the setting % of \key{decls}.} % {\meta{empty}} % % \TemplateKey{subtitle-decls}{tokenlist} % {Declarations (such as font or color settings) applied % to the heading subtitle, overwriting the setting % of \key{decls}.} % {\meta{empty}} % % \TemplateKey{quote-decls}{tokenlist} % {Declarations (such as font or color settings) applied % to the heading quote, overwriting the setting % of \key{decls}.} % {\meta{empty}} % % \TemplateKey{number-format}{function(1)} % {Code that produces a formatted version of the % heading number % including any ornamentations. Its argument is the % counter name for the head. However, instead of using % a specific counter representations, e.g., % \cs{thesection}, it % can refer to the counter representation for the % current heading counter via \cs{theheading} and ignore % the argument.} % {\cs{theheading}} % % \TemplateKey{contents-extra}{tokenlist} % {Code containing \cs{addcontents} calls to write to % files like \texttt{.lot} or \texttt{.lot}} % {\meta{empty}} % % % \TemplateKey{headformat-instance}{instance} % {Template instances of type \texttt{headformat}} % {hang} % % \TemplateSemantics % % Several of the key names are simply bad and need revision! % \end{TemplateDescription} % % % % % \begin{TemplateDescription}{heading}{runin} % % \TemplateKey{before-sep}{skip} % {Vertical space before the heading if there is no page % or column break. If there is one it vanishes.} % {0pt} % % \TemplateKey{penalty}{integer} % {Penalty to break before the heading. The default % (\TeX's largest integer) indicates that no penalty was set in % which case \cs{@secpenalty} is used.} % {\number\maxdimen} % % \TemplateKey{after-penalty-sep}{skip} % {Vertical space before the heading but after the % penalty for the heading. If the penalty results in a page or % column break, this space remains at the top of the page. It is % also applied if the heading is a \texttt{page} or \texttt{top} heading.} % {0pt} % % \TemplateKey{after-sep}{skip} % {Vertical space after the heading} % {0pt} % % \TemplateKey{decls}{tokenlist} % {Declarations (such as font or color settings) applied % to all heading elements, i.e., number, title, % subtitle, and quotation, if present.} % {\cs{normalfont}} % % \TemplateKey{number-decls}{tokenlist} % {Declarations (such as font or color settings) applied % to the heading number, overwriting the setting % of \key{decls}.} % {\meta{empty}} % % \TemplateKey{title-decls}{tokenlist} % {Declarations (such as font or color settings) applied % to the heading title, overwriting the setting % of \key{decls}.} % {\meta{empty}} % % \TemplateKey{subtitle-decls}{tokenlist} % {Declarations (such as font or color settings) applied % to the heading subtitle, overwriting the setting % of \key{decls}.} % {\meta{empty}} % % \TemplateKey{quote-decls}{tokenlist} % {Declarations (such as font or color settings) applied % to the heading quote, overwriting the setting % of \key{decls}.} % {\meta{empty}} % % \TemplateKey{number-format}{function(1)} % {Code that produces a formatted version of the % heading number % including any ornamentations. Its argument is the % counter name for the head. However, instead of using % a specific counter representations, e.g., % \cs{thesection}, it % can refer to the counter representation for the % current heading counter via \cs{theheading} and ignore % the argument.} % {\cs{theheading}} % % \TemplateKey{headformat-instance}{instance} % {Template instances of type \texttt{headformat}} % {hang} % % \TemplateSemantics % % Several of the key names are simply bad and need revision! % \end{TemplateDescription} % % % \begin{TemplateDescription}{headformat}{hang} % % \TemplateKey{indent}{dimen} % {Horizontal space before the heading (shifting it to % the right in a LR typesetting context)} % {0pt} % % \TemplateKey{before-code}{tokenlist} % {Code executed directly before the heading is typeset % and after the vertical spacing is done. The code can take an argument, % e.g., \cs{MakeUppercase}} % {\meta{empty}} % % \TemplateKey{after-code}{tokenlist} % {Code executed directly at the end of the main title text} % {\meta{empty}} % % \TemplateKey{number-title-sep}{tokenlist} % {Token list that can be used in the assignment to a % \TeX{} dimension (can contain \texttt{em} or % \texttt{ex} values) specifying the separation between % title number and title text. Evaluated after fonts for % title text have been set up, i.e., the \texttt{em} will be based % on the then current font.} % {1em} % % \TemplateSemantics % % Implements a heading layout where number and title start on the % same line and the title is hanging off from that if the title % has more than one line. It is what \LaTeX{} always used by % default for \cs{section}, \cs{subsection}, and % \cs{subsubsection}. % % Several of the key names are simply bad and need a revision! % \end{TemplateDescription} % % % \begin{TemplateDescription}{headformat}{runin} % % \TemplateKey{indent}{dimen} % {Horizontal space before the heading (shifting it to % the right in a LR typesetting context)} % {0pt} % % \TemplateKey{before-code}{tokenlist} % {Code executed directly before the heading is typeset % and after the vertical spacing is done.} % {\meta{empty}} % % \TemplateKey{after-code}{tokenlist} % {Code executed directly at the end of the main title text} % {\meta{empty}} % % \TemplateKey{number-title-sep}{tokenlist} % {Token list that can be used in the assignment to a % \TeX{} dimension (can contain \texttt{em} or % \texttt{ex} values) specifying the separation between % title number and title text. Evaluated after fonts for % title text have been set up, i.e., the \texttt{em} will be based % on the then current font. % % In the hang template it is a horizontal dimension!} % {1em} % % \TemplateSemantics % % Implements a heading layout where number and title start on the % same line but then continue with the following paragraph on the % same line (or the next if the title overflows, i.e., the title is % run-in. It is what \LaTeX{} always used by default for % \cs{paragraph} and \cs{subparagraph}. % % Several of the key names are simply bad and need a revision! % \end{TemplateDescription} % % % \begin{TemplateDescription}{headformat}{display} % % \TemplateKey{indent}{dimen} % {Horizontal space before the heading (shifting it to % the right in a LR typesetting context)} % {0pt} % % \TemplateKey{before-code}{tokenlist} % {Code executed directly before the heading is typeset % and after the vertical spacing is done.} % {\meta{empty}} % % \TemplateKey{after-code}{tokenlist} % {Code executed directly at the end of the main title text} % {\meta{empty}} % % \TemplateKey{number-title-sep}{tokenlist} % {Token list that can be used in the assignment to a % \TeX{} dimension (can contain \texttt{em} or % \texttt{ex} values) specifying the separation between % title number and title text. Evaluated after fonts for % title text have been set up, i.e., the \texttt{em} will be based % on the then current font. % \endgraf % In the display template it is a vertical dimension!} % {20 pt} % % \TemplateSemantics % % Implements a heading layout where number and title are vertically % separated. It is what \LaTeX{} always used by default for % \cs{chapter} and \cs{part}. % % Several of the key names are simply bad and need a revision! % \end{TemplateDescription} % % % % % \subsection{Default instances} % % These instances are set up to mimic the design of the standard % \LaTeX{} classes. For other classes they could be adjusted by % changing the instance values and/or by basing them on a different % template. % % \subsubsection{Instances of \texttt{heading} templates} % % \begin{description} % % \item[\texttt{part} (instance of \texttt{display} template)] Used for the % \cs{part} command. % % \item[\texttt{chapter} (instance of \texttt{display} template)] Used for the % \cs{chapter} command. % % \item[\texttt{section} (instance of \texttt{display} template)] Used for the % \cs{section} command. % % \item[\texttt{subsection} (instance of \texttt{display} template)] Used for % the \cs{subsection} command. % % \item[\texttt{subsubsection} (instance of \texttt{display} template)] Used for % the \cs{subsubsection} command. % % \item[\texttt{paragraph} (instance of \texttt{runin} template)] Used for the % \cs{paragraph} command. % % \item[\texttt{subparagraph} (instance of \texttt{runin} template)] Used for % the \cs{subparagraph} command. % % \end{description} % % % \subsubsection{Instances of \texttt{headformat} templates} % % \begin{description} % % \item[\texttt{display} (instance of \texttt{display} template)] Used in % \texttt{heading} instance for \cs{part} and \cs{chapter}. % % \item[\texttt{hang} (instance of \texttt{hang} template)] Used in % \texttt{heading} instance for \cs{section}, \cs{subsection}, and % \cs{subsubsection}. % % \item[\texttt{paragraph} (instance of \texttt{runin} template)] Used in % \texttt{heading} instance for \cs{paragraph} % % \item[\texttt{subparagraph} (instance of \texttt{runin} template)] Used in % \texttt{heading} instance for \cs{subparagraph} % % \end{description} % % % % % \section{Support for legacy classes and packages} % % \subsection{Support classes based on legacy \LaTeXe{} interfaces} % % \DescribeMacro\@startsection % The \cs{@startsection} command has the following syntax: % \begin{verbatim} % \@startsection{name}{level}{indent}{beforeskip}{afterskip}{style} % \end{verbatim} % with a special logic that the sign of \meta{beforeskip} determines % display or runin heading and that of \meta{afterskip} whether or % not the next paragraph is indented. % % All arguments can be cleanly mapped to \texttt{heading} and % \texttt{headformat} templates. Thus, if encountered suitable % instances are declared unless already existing. % % % % \DescribeMacro\secdef % In contrast \cs{secdef} only does the parsing and delegates the % layout to two commands which can contain arbitrary code (usually % hardwired) so that there is no realistic chance to take this % apart and figure out what values should be used for what template % parameters. % % We therefore do not attempt to model this, but instead just use % the standard layout from \LaTeX's standard classes for % \cs{chapter} and \cs{part} if we can identify that the \cs{secdef} % is used to define one of these. % % Maybe we can try at some stage to get some static analysis tool % going. % % % \subsection[label=sec:titlesec]{Support for the \pkg{titlesec} package interfaces} % TODO % % \noindent % \DescribeMacro\titleformat % The \cs{titleformat} declaration has the following syntax: % \begin{verbatim} % \titleformat{cmd}[shape]{format}{label}{sep}{before-code}[after-code] % \end{verbatim} % % \noindent % \DescribeMacro\titlespacing % The \cs{titlespacing} declaration has the following syntax: % \begin{verbatim} % \titlespacing*{cmd}{left-sep}{before-sep}{after-sep}[right-sep] % \end{verbatim} % % \section{Support for links} % % All heading commands (numbered and unnumbered) should contain support for % active links directly. hyperref does not patch the new heading commands! % As \cs{refstepcounter} is not used there is not automatic target. % % This means that all definitions should contain at an appropriate place % a \cs{MakeLinkTarget} command. Typically numbered heading commands will use % \verb+\MakeLinkTarget{+\meta{counter}\verb+}+ while unnumbered heading commands % use \verb+\MakeLinkTarget[+\meta{counter}\verb+]{}+. % % The definition must take care that the target is not separated from the heading % by a page break. It also should not affect spacing. % The target should be placed so that a jump to the target gives % a satisfying user experience, in most cases the best places is at the left margin % a bit above the heading. % % The targets create also structure destinations that % are used by the tagging code. It is therefore important that the targets % are in the right place in relation to the tagging commands. % % \section{Bookmarks} % % Bookmarks are created by the \cs{addcontentsline} command, more precisely in the % new latex-lab toc code a hook with arguments is inserted at the begin of the command % which contains the command that creates the bookmark. The arguments of \cs{addcontentsline} % and so also of the hook are the type of the toc, % the level name and the (short-)title of the heading. To pass a differing % bookmark text the code uses \cs{texorpdfstring} in the \cs{addcontentsline}. % % \section{Tagging support} % % Tagging of heading commands has to do two tasks: % \begin{itemize} % \item surround the whole section (heading and text) with a \texttt{Sect} structure % \item tag the heading with an Hn structure. % \end{itemize} % This is done with tagging sockets which are documented in the code and in \texttt{latex-lab-sec}. % % \section{Debugging support} % % \begin{function}{\DebugHeadingsOn,\DebugHeadingsOff, \head_debug_on:, \head_debug_off:} % % These commands enable/disable debugging messages. % % \end{function} % % % % \end{documentation} % % \StopEventually{\setlength\IndexMin{200pt} \PrintIndex } % % % % \begin{implementation} % % \section{The Implementation} % % % \begin{macrocode} %<*package> %<@@=head> % \end{macrocode} % % % \begin{macrocode} \ProvidesExplPackage {latex-lab-testphase-sec-template} {\ltlabsecIIdate} {\ltlabsecIIversion} {heading implementation} % \end{macrocode} % % \bigskip % % \subsection{Debugging} % % \begin{variable}{\g_@@_debug_bool} % % \begin{macrocode} \bool_new:N \g_@@_debug_bool % \end{macrocode} % \end{variable} % % % \begin{macro}{\@@_debug:n,\@@_debug_typeout:n} % % \begin{macrocode} \cs_new_eq:NN \@@_debug:n \use_none:n \cs_new_eq:NN \@@_debug_typeout:n \use_none:n % \end{macrocode} % \end{macro} % % \begin{macro}{\head_debug_on:,\head_debug_off:, % \@@_debug_gset:} % \begin{macrocode} \cs_new_protected:Npn \head_debug_on: { \bool_gset_true:N \g_@@_debug_bool \@@_debug_gset: } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \head_debug_off: { \bool_gset_false:N \g_@@_debug_bool \@@_debug_gset: } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_debug_gset: { \cs_gset_protected:Npx \@@_debug:n ##1 { \bool_if:NT \g_@@_debug_bool {##1} } \cs_gset_protected:Npx \@@_debug_typeout:n ##1 { \bool_if:NT \g_@@_debug_bool { \typeout{[head]~ ##1} } } } % \end{macrocode} % \end{macro} % % % \begin{macro}{\DebugHeadingsOn,\DebugHeadingsOff} % % \begin{macrocode} \cs_new_protected:Npn \DebugHeadingsOn { \head_debug_on: } \cs_new_protected:Npn \DebugHeadingsOff { \head_debug_off: } % \end{macrocode} % % \begin{macrocode} \DebugHeadingsOff % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_show_arguments:nnnnnn} % Some debug data \ldots % \begin{macrocode} \cs_new:Npn \@@_show_arguments:nnnnn #1#2#3#4#5 { \@@_debug_typeout:n{---------~ Headformat~ instance~ arguments:} \@@_debug_typeout:n{1:~ keys~ =~ \exp_not:n{#1}} \@@_debug_typeout:n{2:~ number~ =~ \exp_not:n{#2}} \@@_debug_typeout:n{3:~ title~ =~ \exp_not:n{#3}} \@@_debug_typeout:n{4:~ subtitle~ =~ \exp_not:n{#4}} \@@_debug_typeout:n{5:~ quotation~ =~ \exp_not:n{#5}} } % \end{macrocode} % \end{macro} % \begin{macro}{\@@_show_arguments:nnnnnnnnn} % Some debug data \ldots % \begin{macrocode} \cs_new:Npn \@@_show_arguments:nnnnnnnnn #1#2#3#4#5#6#7#8#9 { \@@_debug_typeout:n{---------~ Heading~ instance~ arguments:} \@@_debug_typeout:n{1:~ keys~ =~ \exp_not:n{#1}} \@@_debug_typeout:n{2:~ unnumbered~ =~ \exp_not:n{#2}} \@@_debug_typeout:n{3:~ title~ =~ \exp_not:n{#3}} \@@_debug_typeout:n{4:~ toc~ =~ \exp_not:n{#4}} \@@_debug_typeout:n{5:~ running~ =~ \exp_not:n{#5}} \@@_debug_typeout:n{6:~ bookmark~ =~ \exp_not:n{#6}} \@@_debug_typeout:n{7:~ nameref~ =~ \exp_not:n{#7}} \@@_debug_typeout:n{8:~ label~ =~ \exp_not:n{#8}} \@@_debug_typeout:n{9:~ subtitle | quote ~ =~ \exp_not:n{#9}} } % \end{macrocode} % \end{macro} % % \subsection{Temp variable(s)} % \begin{variable}{\l_@@_tmpa_tl} % \begin{macrocode} \tl_new:N\l_@@_tmpa_tl % \end{macrocode} % \end{variable} % % \subsection{variable(s)} % These token lists are automatically declared by the key machinery. % \begin{macrocode} %\tl_new:N \l_@@_bookmark_tl %\tl_new:N \l_@@_running_tl %\tl_new:N \l_@@_toc_tl %\tl_new:N \l_@@_nameref_tl %\tl_new:N \l_@@_subtitle_tl %\tl_new:N \l_@@_quote_tl %\bool_new:N l_@@_unnumbered_bool % \end{macrocode} % % \begin{variable}{ % \l_@@_label_tl, % \l_@@_instance_keys_tl, % \l_@@_typeset_number_tl, % \l_@@_saved_secnumdepth_tl, % \l_@@_title_tl, % \l_@@_placement_tl} % % But this token lists needs a declaration: % % \begin{macrocode} \tl_new:N\l_@@_label_tl \tl_new:N\l_@@_instance_keys_tl \tl_new:N\l_@@_typeset_number_tl \tl_new:N\l_@@_saved_secnumdepth_tl \tl_new:N \l_@@_title_tl \tl_new:N \l_@@_placement_tl % \end{macrocode} % \end{variable} % % \subsection{New user commands} % % \begin{macro}{\theheading} % This command expands to \cs{thechapter}, \cs{thesection} etc % in every heading command. % \begin{macrocode} \tl_new:N\theheading % \end{macrocode} % \end{macro} % % \begin{macro}{\partmark} % This replaces the fix \verb+\markboth{}{}+ or similar in the standard \cs{part} % definition. As the command is already defined in some classes (like \pkg{memoir}), % we provide it through a hook. % \begin{macrocode} \AddToHook{class/after}{\providecommand*\partmark[1]{\markboth{}{}}} % \end{macrocode} % \end{macro} % % \subsection{The \LaTeXe{} parsing interface} % % \LaTeXe{} provides heading commands with a starred form % (unnumbered) and one optional argument (to specify an alternative % toc/running head). We augment this slightly by supporting a key % value interface in the optional argument. This is handled by % defining the commands through \cs{ParseLaTeXeHeading}. This % should happen in the document class. % % % \begin{macro}{\ParseLaTeXeHeading} % % \cs{ParseLaTeXeHeading} arguments: % \begin{itemize} % \item[1:] instance name to use (of type \enquote{heading}) % \item[2:] numbered? boolean % \item[3:] shorttitle or key/val for layout adjustments and individual % title settings % \item[4:] main title % \end{itemize} % % This command handles the document input that may be hidden in the % optional argument, i.e., special data for toc, running (header), % bookmark, label, and for more specialized headings subtitle and % quote. It also handles the legacy case that the optional argument is just % an alternate title to be used for toc, running, and bookmark % (through the key shorttitle to which it gets converted). % % \begin{macrocode} \cs_new_protected:Npn \ParseLaTeXeHeading #1 #2 #3 #4 { % \end{macrocode} % % \begin{macrocode} \@@_debug_typeout:n{==================================} \@@_debug_typeout:n{#1:~ \IfBooleanT{#2}{*} \IfValueT{#3}{[\exp_not:n{#3}]} {\exp_not:n{#4}}} % \end{macrocode} % We first check if the title argument contains a \cs{label} % command. If yes, we remove it and add it to \cs{l_@@_label_tl} % (and if more than one all of them) and the rest of the main title in % \cs{l_@@_title_tl} for later use. If there was no \cs{label} % command then \cs{l_@@_title_tl} is set to \texttt{\#4}. % \begin{macrocode} \@@_find_label:w #4 \label\q_no_value \@@_find_label:w % \end{macrocode} % By default toc, running, and bookmark use the data provided by % the main title. However, if the second argument is true (i.e., a % star was given) they are all suppressed (because this is the \LaTeXe{} logic). % \begin{macrocode} \IfBooleanTF{#2} { \tl_clear:N \l_@@_toc_tl \tl_clear:N \l_@@_running_tl \tl_clear:N \l_@@_bookmark_tl \bool_set_true:N \l_@@_unnumbered_bool } { \tl_set_eq:NN \l_@@_toc_tl \l_@@_title_tl \tl_set_eq:NN \l_@@_running_tl \l_@@_title_tl \tl_set_eq:NN \l_@@_bookmark_tl \l_@@_title_tl \bool_set_false:N \l_@@_unnumbered_bool } % \end{macrocode} % The nameref always starts out matching the main title. % \begin{macrocode} \tl_set_eq:NN \l_@@_nameref_tl \l_@@_title_tl % \end{macrocode} % Normally we don't have a subtitle or quote unless they are % explicitly given through keys, so we start with \cs{c_novalue_tl} % \begin{macrocode} \tl_set_eq:NN \l_@@_subtitle_tl \c_novalue_tl \tl_set_eq:NN \l_@@_quote_tl \c_novalue_tl % \end{macrocode} % If the optional argument is empty we set the % \cs{l_@@_instance_keys_tl} to empty, otherwise process the % key/val list setting the keys defined in the module \enquote{head}. This % overwrites the defaults specified above if keys like \enquote{toc} are in % the list. All the key/vals unknown by that module are put into % \cs{l_@@_instance_keys_tl} which may or may not make this token % list non-empty. % % If the user has a \key{label} key and also a \cs{label} in the % main title argument then the latter is ignored (no error checking % for that). We could alternatively set all labels we find, % perhaps that is the better approach? % \begin{macrocode} \IfNoValueTF { #3 } { \tl_clear:N \l_@@_instance_keys_tl } { \keys_set_known:nnN {heading} { #3 } \l_@@_instance_keys_tl } % \end{macrocode} % % Finally we call the heading instance using the collected % mandatory arguments. To simplify downstream processing we pass % the values not the container tokenlists resulting from the above % processing.\footnote {I think this is a common requirement and % perhaps \cs{UseInstance} should really o-expand all arguments it % receives.} % \begin{macrocode} \@@_debug_typeout:n{use~ 'heading'~ instance:~ #1 } \use:e { \exp_not:N \UseInstance{heading}{#1} { \exp_not:o \l_@@_instance_keys_tl } { \bool_if:NTF \l_@@_unnumbered_bool \BooleanTrue \BooleanFalse } { \exp_not:o \l_@@_title_tl} { \exp_not:o \l_@@_toc_tl } { \exp_not:o \l_@@_running_tl } { \exp_not:o \l_@@_bookmark_tl } { \exp_not:o \l_@@_nameref_tl } { \exp_not:o \l_@@_label_tl } { { \exp_not:o \l_@@_subtitle_tl } { \exp_not:o \l_@@_quote_tl } } } } % \end{macrocode} % % Syntax keys that can appear in the optional argument of headings % parsed by \cs{ParseLaTeXeHeading}. All other keys used there are % passed to the heading instance to overwrite instance setting. % % \begin{macrocode} \keys_define:nn {heading} { , shorttitle .meta:n = {toc = {#1} , running = {#1} , bookmark = {#1} , nameref= {#1} } , bookmark .tl_set:N = \l_@@_bookmark_tl , running .tl_set:N = \l_@@_running_tl , toc .tl_set:N = \l_@@_toc_tl , nameref .tl_set:N = \l_@@_nameref_tl % , numbered .bool_set_inverse:N = \l_@@_unnumbered_bool , numbered .default:n = true , unnumbered .bool_set:N = \l_@@_unnumbered_bool , unnumbered .default:n = true % , subtitle .tl_set:N = \l_@@_subtitle_tl , quote .tl_set:N = \l_@@_quote_tl % \end{macrocode} % We collect labels together with their \cs{label} command in case % there is more than one. This way we can later simply execute % \cs{l_@@_label_tl} without any status checks. % \begin{macrocode} , label .code:n = \tl_put_right:Nn \l_@@_label_tl { \label{#1} } } % \end{macrocode} % % % \end{macro} % % \begin{macro}{\@@_find_label:w} % A simple-minded check for an existing \cs{label} command in the % main title (could be done better I guess). We add % \cs{label}\cs{q_no_value} at the end of the argument, so that we % can be sure to find something. % % As currently implemented the spaces on both sides of a \cs{label} % command survive if it is removed. This may be an issue in which % case this may need some adjustments. % \begin{macrocode} \cs_new:Npn \@@_find_label:w #1 \label #2#3 \@@_find_label:w { % \end{macrocode} % If the token after \cs{label} is \cs{q_no_value} then the title % had no label and we set the two variables accordingly. % \begin{macrocode} \quark_if_no_value:nTF {#2} { \@@_debug_typeout:n{---~no~label } \tl_clear:N \l_@@_label_tl \tl_set:Nn\l_@@_title_tl {#1#3} } % \end{macrocode} % Otherwise, there was a real \cs{label} command and \texttt{\#2} % holds the label string. % \begin{macrocode} { \@@_debug_typeout:n{---~label~found~#2} \tl_set:Nn\l_@@_label_tl { \label{#2} } % \end{macrocode} % To construct the value for \cs{l_@@_title_tl} we have to get rid % of the two tokens we added at its end, this is done with % \cs{@@_find_label_aux:w}. % \begin{macrocode} \tl_set:Nn\l_@@_title_tl {#1} \@@_find_label_aux:w #3\@@_find_label_aux:w } \@@_debug_typeout:n{---~return:~ '\exp_not:o \l_@@_title_tl' } } % \end{macrocode} % There is at least one more \cs{label} now and the token after it % should be our \cs{q_no_value}. If not then the title argument had % at least 2 labels and we collect the newly found one and recurse. % \begin{macrocode} \cs_new:Npn \@@_find_label_aux:w #1 \label #2#3 \@@_find_label_aux:w { % \end{macrocode} % The \texttt{\#1} may not be everything we have to pick up but we % know for sure that it belongs to the title. % \begin{macrocode} \tl_put_right:Nn \l_@@_title_tl { #1 } % \end{macrocode} % Now let's see if we are at the end of the argument. If not pick % up the newly found \cs{label} and recurse on the remaining material. % \begin{macrocode} \quark_if_no_value:nF {#2} { \@@_debug_typeout:n{---~ extra~ label~ '#2'~ found } \tl_put_right:Nn \l_@@_label_tl { \label{#2} } \@@_find_label_aux:w #3\@@_find_label_aux:w } } % \end{macrocode} % \end{macro} % % \subsection{Templates} % % \subsubsection{Template types} % % \begin{templatetype}{heading} % Templates of type \texttt{heading} are used to produce headings. The % positional arguments are: % \begin{verbatim} % 1: key/val list % 2: unnumbered? % 3: title % 4: toc % 5: running % 6: bookmark % 7: nameref % 8: label(s) % 9: { subtitle } { quote } % \end{verbatim} % \begin{macrocode} \NewTemplateType{heading}{9} % \end{macrocode} % \end{templatetype} % % \begin{templatetype}{headformat} % Templates of type \texttt{headformat} are used to produce heading % layout from the formatted heading number (if any), the heading title, % subtitle and quotation. The % positional arguments are: % \begin{verbatim} % 1: key/val list for document-level customizations % 2: formatted heading number % 3: title % 4: subtitle % 5: quote % \end{verbatim} % \begin{macrocode} \NewTemplateType{headformat}{5} % \end{macrocode} % \end{templatetype} % % \subsubsection{heading templates interfaces} % % We have two heading templates: display and runin. % % \begin{template}{heading display} % The \texttt{display} template produces a display heading, i.e., % one that has vertical space before and after it. % \begin{macrocode} \DeclareTemplateInterface{heading}{display}{9} { , name : tokenlist , parent-name : tokenlist , reset-counter : tokenlist , level : integer = 0 % \end{macrocode} % The \key{placement} key sets default values for the keys % \key{start-code} and \key{final-code}. % \begin{macrocode} , placement : choice {page , top , normal } = normal , mark-cmd : function(1) = % % many more keys for layout settings are missing for now , para-indent : choice { true , false } = false % \end{macrocode} % We use \cs{c_max_int} as a fake penalty to indicate that no % penalty was given in a key. % \begin{macrocode} , before-sep : skip = 0pt , penalty : integer = \c_max_int , after-penalty-sep : skip = 0pt , after-sep : skip = 0pt % \end{macrocode} % The next two keys are only there to overwrite the \key{placement} % settings with explicit code. Thus, their default value is set up % by the \key{placement} key (which has a default). % \begin{macrocode} , start-code : tokenlist = % no default values! , final-code : tokenlist = % no default values! % \end{macrocode} % % \begin{macrocode} , decls : tokenlist = \normalfont , number-decls : tokenlist = , title-decls : tokenlist = , subtitle-decls : tokenlist = , quote-decls : tokenlist = % \end{macrocode} % % \begin{macrocode} , headformat-instance : tokenlist = hang , number-format : function(1) = \theheading , contents-extra : tokenlist = } % \end{macrocode} % \end{template} % % % \begin{template}{heading runin} % This template is similar to the \texttt{display} template but % implements a runin heading, i.e., one where the paragraph text % continues on the same line. % % Unfortunately, we can't really use \cs{DeclareTemplateCopy} to % set it up because with \cs{EditTemplateDefaults} we are not able % to alter the setup for the \key{placement} and \key{para-indent} keys % as that involves changing the implementation code. Thus with % \cs{DeclareTemplateCopy} we can copy the interface setup but the % code setup still needs to be done using \cs{DeclareTemplateCode}. % % \begin{macrocode} \DeclareTemplateCopy{heading}{runin}{display} % \end{macrocode} % \end{template} % % % \subsubsection{headformat templates interfaces} % We have three template: display, hang and runin. % % \begin{template}{headformat display} % The \texttt{display} template produces % \begin{macrocode} \DeclareTemplateInterface{headformat}{display}{5} { , indent : length = 0pt , before-code : tokenlist = , after-code : tokenlist = , number-title-sep : tokenlist = 20pt } % \end{macrocode} % \end{template} % % \begin{template}{headformat hang} % The \texttt{hang} template produces % \begin{macrocode} \DeclareTemplateInterface{headformat}{hang}{5} { , indent : length = 0pt , before-code : tokenlist = , after-code : tokenlist = , number-title-sep : tokenlist = 1em } % \end{macrocode} % \end{template} % % % \begin{template}{headformat runin} % The \texttt{runin} template produces % \begin{macrocode} \DeclareTemplateInterface{headformat}{runin}{5} { , indent : length = 0pt , before-code : tokenlist = , after-code : tokenlist = , number-title-sep : tokenlist = 1em } % \end{macrocode} % \end{template} % % \subsubsection{heading templates code} % % \begin{template}{heading display} % % \begin{macrocode} \DeclareTemplateCode{heading}{display}{9} { , name = \l_@@_name_tl , level = \l_@@_level_int % next two not yet used , parent-name = \l_@@_pname_tl , reset-counter = \l_@@_reset_cnt_tl % \end{macrocode} % The \key{placement} key determines whether the heading can appear % anywhere (\texttt{normal}), automatically starts a new page or % column (\texttt{top}), or is on a page of its own (\texttt{page}. % % It is implemented by setting \cs{l_@@_start_code_tl} and % \cs{l_@@_final_code_tl}. These settings can be fine-tuned or % overwritten with the keys \key{start-code} and % \key{final-code}, if necessary. % \begin{macrocode} , placement = { page = \@@_debug_typeout:n{ A~ page~ heading } \tl_set:Nn \l_@@_placement_tl { page } ,top = \@@_debug_typeout:n{ A~ top~ heading } \tl_set:Nn \l_@@_placement_tl { top } ,normal = \@@_debug_typeout:n{ A~ normal~ heading } \tl_set:Nn \l_@@_placement_tl { normal } } , mark-cmd = \@@_mark_cmd:n % \end{macrocode} % For now we make use of the legacy coding for indentation of % the following paragraph. % \begin{macrocode} , para-indent = { true = \@afterindenttrue ,false = \@afterindentfalse } , before-sep = \l_@@_before_skip , penalty = \l_@@_penalty_int , after-penalty-sep = \l_@@_after_penalty_skip , after-sep = \l_@@_after_skip , start-code = \l_@@_start_code_tl , final-code = \l_@@_final_code_tl % \end{macrocode} % % \begin{macrocode} , headformat-instance = \l_@@_headformat_instance_tl % \end{macrocode} % % \begin{macrocode} , decls = \l_@@_decls_tl , number-decls = \l_@@_number_decls_tl , title-decls = \l_@@_title_decls_tl , subtitle-decls = \l_@@_subtitle_decls_tl , quote-decls = \l_@@_quote_decls_tl , number-format = \@@_number_format:n , contents-extra = \l_@@_contents_extra_tl } % \end{macrocode} % % \begin{macrocode} { % \end{macrocode} % % \begin{macrocode} \tl_set_eq:Nc \theheading { the \l_@@_name_tl } % \end{macrocode} % We store the value of \texttt{secnumdepth} so that we can change it locally. % \begin{macrocode} \tl_set:Ne\l_@@_saved_secnumdepth_tl{\int_use:N\c@secnumdepth} % \end{macrocode} % % \begin{macrocode} \@@_show_arguments:nnnnnnnnn {#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9} % \end{macrocode} % First evaluate any key setting done by the user in the % optional first argument. % \fmi{It would be nice if there is a variant of % \cs{SetTemplateKey} in which the template type and name are % implicit, e.g., \cs{SetCurrentTemplateKeys} because this is % usually what I need.} % \begin{macrocode} \tl_if_empty:oF {#1} { \SetTemplateKeys{heading}{display}{#1} } % \end{macrocode} % Based on the \key{placement} key we set up \cs{l_@@_start_code_tl} % and \cs{l_@@_final_code_tl}. These two variables can also be set % with the keys \key{start-code} and \key{final-code} in which case % we don't alter the definition. % \begin{macrocode} \tl_if_empty:oT \l_@@_start_code_tl { \str_case:VnF \l_@@_placement_tl { { page } { \tl_set:Nn \l_@@_start_code_tl % \end{macrocode} % Straight from the placement definition of \cs{part}.\fmi{Clearly not % \cs{@tempswa} and the page styles should be adjustable.} % \begin{macrocode} { \if@openright \cleardoublepage \else \clearpage \fi \thispagestyle{plain}% \if@twocolumn \onecolumn \@tempswatrue \else \@tempswafalse \fi \null\vfil } } { top } { \tl_set:Nn \l_@@_start_code_tl { \if@openright\cleardoublepage\else\clearpage\fi \thispagestyle{plain}% \global\@topnum\z@ } } } { \tl_clear:N \l_@@_start_code_tl } } % \tl_if_empty:oT \l_@@_final_code_tl { \str_case:VnF \l_@@_placement_tl { { page } { \tl_set:Nn \l_@@_final_code_tl { \vfil\newpage \if@twoside \if@openright \null \thispagestyle{empty}% \newpage \fi \fi \if@tempswa \twocolumn \fi } } } { \tl_set:Nn \l_@@_final_code_tl { \@afterheading } } } % \end{macrocode} % Then we set up the penalty to use (might be given as a key value). % \begin{macrocode} \@@_determine_penalty: % \end{macrocode} % % \begin{macrocode} \@@_determine_number_typesetting:N #2 % \end{macrocode} % Next comes the vertical spacing and penalty before the heading. This includes % running \cs{l_@@_start_code_tl} if it contains any code, e.g., to % start a new page. % \begin{macrocode} \@@_vertical_before_spacing: % \end{macrocode} % We are in vmode now and here is the point where we (with tagging) can close a previous Sect % structure and open the new one. % \begin{macrocode} \UseTaggingSocket{sec/end}{\int_use:N\l_@@_level_int} \UseTaggingSocket{sec/begin} {{\int_use:N\l_@@_level_int}{tag=\UseStructureName{sec/\int_use:N\l_@@_level_int}}} % \end{macrocode} % Up to this point everything is identical for both display and % runin headings. But from now on they have their own code. % We have dealt with argument \#1 and \#2 so now we can unbundle % argument \#9 so that it is easier to process downstream % \begin{macrocode} \@@_debug_typeout:n{use~ 'headformat'~instance:~ \l_@@_headformat_instance_tl } \use:e { \UseInstance{headformat} { \l_@@_headformat_instance_tl } { \exp_not:o \UnusedTemplateKeys } { \exp_not:o { \l_@@_typeset_number_tl } } { \exp_not:n { #3 } } { \exp_not:o { \use_i:nn #9 } } { \exp_not:o { \use_ii:nn #9 } } } % % --- handle marks, toc-entry, bookmark, nameref, and label % \@@_handle_marks_etc:nnnnn {#4}{#5}{#6}{#7}{#8} % % --- post-heading handling (vertical) % \end{macrocode} % Restore \texttt{secnumdepth} % \begin{macrocode} \int_gset:Nn\c@secnumdepth{\l_@@_saved_secnumdepth_tl} \par \nobreak \skip_vertical:N \l_@@_after_skip % --- prepare next paragraph (defaults to \cs{@afterheading} % \l_@@_final_code_tl % \ignorespaces } % \end{macrocode} % \end{template} % % % % \begin{macro}{} % % \begin{macrocode} \AddToHook{begindocument}{ \ifcsname if@openright\endcsname \else % \end{macrocode} % Need to hide this a little if it is in fact already defined! % UFI: why not simply \cs{newif}?? % \begin{macrocode} \expandafter\newif\csname if@openright\endcsname \fi } % \end{macrocode} % \end{macro} % % \begin{template}{heading runin} % The \texttt{runin} template is very similar to the % \texttt{display} one. % \begin{macrocode} \DeclareTemplateCode{heading}{runin}{9} { , name = \l_@@_name_tl , level = \l_@@_level_int % next two not yet used , parent-name = \l_@@_pname_tl , reset-counter = \l_@@_reset_cnt_tl % \end{macrocode} % % It wouldn't make sense to have page placement with a runin heading since % there would be nothing to run into. % \begin{macrocode} , placement = { page = \typeout{ ^^JA~ runin~ page~ placement~ heading~makes~no~sense (top~used)} \tl_set:Nn \l_@@_placement_tl { top } ,top = \@@_debug_typeout:n{ A~ top~ heading } \tl_set:Nn \l_@@_placement_tl { top } ,normal = \@@_debug_typeout:n{ A~ normal~ heading } \tl_set:Nn \l_@@_placement_tl { normal } } , mark-cmd = \@@_mark_cmd:n % \end{macrocode} % In a runin heading you can't set up paragraph indentation of the % following paragraph (since that one is \enquote{run in}. But we % accept the key and just spit out a warning. % \ufi{this types out messages for all run-in headers! Therefore disabled for now} % \begin{macrocode} , para-indent = { true = %\typeout{para-indent~ setting~ ignored} ,false = %\typeout{para-indent~ setting~ ignored} } , before-sep = \l_@@_before_skip , penalty = \l_@@_penalty_int , after-penalty-sep = \l_@@_after_penalty_skip , after-sep = \l_@@_after_skip , start-code = \l_@@_start_code_tl , final-code = \l_@@_final_code_tl % \end{macrocode} % % \begin{macrocode} , headformat-instance = \l_@@_headformat_instance_tl % \end{macrocode} % % \begin{macrocode} , decls = \l_@@_decls_tl , number-decls = \l_@@_number_decls_tl , title-decls = \l_@@_title_decls_tl , subtitle-decls = \l_@@_subtitle_decls_tl , quote-decls = \l_@@_quote_decls_tl % \end{macrocode} % % \begin{macrocode} , number-format = \@@_number_format:n , contents-extra = \l_@@_contents_extra_tl } { \@@_show_arguments:nnnnnnnnn {#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9} % \end{macrocode} % store the value of \texttt{secnumdepth} so that we can change it locally. % \begin{macrocode} \tl_set:Ne\l_@@_saved_secnumdepth_tl{\int_use:N\c@secnumdepth} % \end{macrocode} % define \cs{theheading} % \begin{macrocode} \tl_set_eq:Nc \theheading { the \l_@@_name_tl } \tl_if_empty:oF {#1} { \SetTemplateKeys{heading}{runin}{#1} } % \end{macrocode} % % \begin{macrocode} \tl_if_empty:oT \l_@@_start_code_tl { \str_case:Vn \l_@@_placement_tl { { top } { \tl_set:Nn \l_@@_start_code_tl {\clearpage } } } % \end{macrocode} % All other cases want an empty \cs{l_@@_start_code_tl} so nothing % to do. % \begin{macrocode} % { \tl_clear:N \l_@@_start_code_tl } } % % \end{macrocode} % Nothing at all to do (for now) for \cs{l_@@_final_code_tl}, it % should by default be empty in all heading placement. But maybe % we end up supporting further placements, so~\ldots % \begin{macrocode} % \tl_if_empty:oT \l_@@_final_code_tl % { \str_case:VnF \l_@@_placement_tl % { % { top } { \tl_clear:N \l_@@_final_code_tl } % } % { \tl_clear:N \l_@@_final_code_tl } % } % \end{macrocode} % % \begin{macrocode} \@@_determine_penalty: \@@_determine_number_typesetting:N #2 \@@_vertical_before_spacing: % \end{macrocode} % We are in vmode now and here is the point where we (with tagging) can close a previous Sect % structure and open the new one. We also have to initialize the change in the paratagging here % as run-in titles typeset the heading in everypar. % \begin{macrocode} \UseTaggingSocket{sec/end}{\int_use:N\l_@@_level_int} \UseTaggingSocket{sec/begin} {{\int_use:N\l_@@_level_int}{tag=\UseStructureName{sec/\int_use:N\l_@@_level_int}}} \UseTaggingSocket{sec/title/init}{\int_use:N\l_@@_level_int} \def \@svsechd { \@@_debug_typeout:n{use~ 'headformat'~instance:~ \l_@@_headformat_instance_tl } \use:e { \UseInstance{headformat} { \l_@@_headformat_instance_tl } { \exp_not:o \UnusedTemplateKeys } { \exp_not:o { \l_@@_typeset_number_tl } } { \exp_not:n { #3 } } { \exp_not:o { \use_i:nn #9 } } { \exp_not:o { \use_ii:nn #9 } } } \@@_handle_marks_etc:nnnnn {#4}{#5}{#6}{#7}{#8} % \end{macrocode} % Restore \texttt{secnumdepth} % \begin{macrocode} \int_gset:Nn\c@secnumdepth{\l_@@_saved_secnumdepth_tl} } % \@nobreakfalse \global\@noskipsectrue \everypar{% \if@noskipsec \global\@noskipsecfalse {\setbox\z@\lastbox} \clubpenalty\@M %FMi group in headformat % \begingroup \@svsechd % \endgroup \unskip % \end{macrocode} % This tagging socket starts the \enquote{paragraph} after the run-in heading % \begin{macrocode} \UseTaggingSocket{sec/title/split} \skip_horizontal:N \l_@@_after_skip \else \clubpenalty \@clubpenalty \everypar{}% \fi } % \end{macrocode} % --- prepare next paragraph (does nothing by default) % \begin{macrocode} \l_@@_final_code_tl % \ignorespaces } % \end{macrocode} % \end{template} % % \subsubsection{headformat templates code} % % \begin{template}{headformat display} % This template creates a headformat where the number is on a line on its own. % \begin{macrocode} \DeclareTemplateCode{headformat}{display}{5} { , indent = \l_@@_indent_dim , before-code = \l_@@_before_code_tl , after-code = \l_@@_after_code_tl , number-title-sep = \l_@@_number_title_sep_tl } { \@@_show_arguments:nnnnn {#1}{#2}{#3}{#4}{#5} % \end{macrocode} % First evaluate any key setting done by the user (normally % supplied from the main heading isntance. % \begin{macrocode} \tl_if_empty:oF {#1} { \SetTemplateKeys{headformat}{display}{#1} } % \end{macrocode} % % \begin{macrocode} \group_begin: \UseTaggingSocket{sec/title/begin}{{\int_use:N\l_@@_level_int}{#3}} % \end{macrocode} % % \begin{macrocode} \normalfont \normalcolor \interlinepenalty \@M \l_@@_decls_tl{} % \end{macrocode} % If there is a number and so a prefix, the link target should be before the number. % We use for now the same place in the unnumbered case. % TODO: If we put the target here we do not know the height of the line and the % target is perhaps not high enough. And for unnumbered chapter it is perhaps too high. % Check! % \begin{macrocode} \bool_if:NTF \l_@@_unnumbered_bool { \dim_compare:nNnTF \l_@@_indent_dim < \c_zero_skip { \skip_horizontal:N \l_@@_indent_dim \MakeLinkTarget[\l_@@_name_tl]{} } { \MakeLinkTarget[\l_@@_name_tl]{}\skip_horizontal:N \l_@@_indent_dim } } { \dim_compare:nNnTF \l_@@_indent_dim < \c_zero_skip { \skip_horizontal:N \l_@@_indent_dim \MakeLinkTarget{\l_@@_name_tl} } { \MakeLinkTarget{\l_@@_name_tl}\skip_horizontal:N \l_@@_indent_dim } \l_@@_number_decls_tl #2 \par\nobreak \skip_vertical:n { \l_@@_number_title_sep_tl } } \l_@@_title_decls_tl % \end{macrocode} % \fmi{probably better to use a format:n and drop these two code % variables even though they are used by titlesec} % \begin{macrocode} \l_@@_before_code_tl {#3} \l_@@_after_code_tl \par \UseTaggingSocket{sec/title/end} \group_end: } % \end{macrocode} % \end{template} % % \begin{template}{headformat hang} % This template creates a heading with a hanging number. % \begin{macrocode} \DeclareTemplateCode{headformat}{hang}{5} { , indent = \l_@@_indent_dim , before-code = \l_@@_before_code_tl , after-code = \l_@@_after_code_tl , number-title-sep = \l_@@_number_title_sep_tl } { \@@_show_arguments:nnnnn {#1}{#2}{#3}{#4}{#5} % \end{macrocode} % First evaluate any key setting done by the user (normally % supplied from the main heading isntance. % \begin{macrocode} \tl_if_empty:oF {#1} { \SetTemplateKeys{headformat}{hang}{#1} } % \end{macrocode} % % \begin{macrocode} \group_begin: \UseTaggingSocket{sec/title/init}{\int_use:N\l_@@_level_int} % \end{macrocode} % % \begin{macrocode} \normalfont \normalcolor \interlinepenalty \@M \l_@@_decls_tl{} % \end{macrocode} % The link target should be at the left text margin, or, if the section % is moved into the margin, at the left of the number. % \begin{macrocode} \bool_if:NTF \l_@@_unnumbered_bool { \tl_set:Nn\l_@@_tmpa_tl { \dim_compare:nNnTF \l_@@_indent_dim < \c_zero_skip { \skip_horizontal:N \l_@@_indent_dim \MakeLinkTarget[\l_@@_name_tl]{} } { \MakeLinkTarget[\l_@@_name_tl]{} \skip_horizontal:N \l_@@_indent_dim } } } { \tl_set:Nn \l_@@_tmpa_tl { \dim_compare:nNnTF \l_@@_indent_dim < \c_zero_skip { \skip_horizontal:N \l_@@_indent_dim \MakeLinkTarget{\l_@@_name_tl} } { \MakeLinkTarget{\l_@@_name_tl}\skip_horizontal:N \l_@@_indent_dim } { \l_@@_number_decls_tl #2 } \skip_horizontal:n { \l_@@_number_title_sep_tl } } } \UseTaggingSocket{sec/title/hang} {{\int_use:N\l_@@_level_int}\l_@@_unnumbered_bool{\l_@@_tmpa_tl}{#3}} { \@hangfrom { \l_@@_tmpa_tl } } \l_@@_title_decls_tl % \end{macrocode} % \fmi{probably better to use a format:n and drop these two code % variables even though they are used by titlesec} % \begin{macrocode} \l_@@_before_code_tl {#3} \l_@@_after_code_tl \par \group_end: } % \end{macrocode} % \end{template} % % % \begin{template}{headformat runin} % This template creates a heading with a run-in title. % Arguments are key-value, number, title, subtitle, quotation. % \begin{macrocode} \DeclareTemplateCode{headformat}{runin}{5} { , indent = \l_@@_indent_dim , before-code = \l_@@_before_code_tl , after-code = \l_@@_after_code_tl , number-title-sep = \l_@@_number_title_sep_tl } { \@@_show_arguments:nnnnn {#1}{#2}{#3}{#4}{#5} % \end{macrocode} % First evaluate any key setting done by the user (normally % supplied from the main heading isntance. % \begin{macrocode} \tl_if_empty:oF {#1} { \SetTemplateKeys{headformat}{hang}{#1} } % \end{macrocode} % % \begin{macrocode} \group_begin: % \end{macrocode} % % % \begin{macrocode} \normalfont \normalcolor % \end{macrocode} % \fmi{Setting \cs{interlinepenalty} makes little sense I think % (but that's the way it was in \LaTeXe)} % \begin{macrocode} \interlinepenalty \@M \l_@@_decls_tl{} % \end{macrocode} % We must avoid that the sep between number and title is used in the unnumbered case. % So we test with the boolean. % \begin{macrocode} \bool_if:NTF \l_@@_unnumbered_bool { \dim_compare:nNnTF \l_@@_indent_dim < \c_zero_skip { \skip_horizontal:N \l_@@_indent_dim \MakeLinkTarget[\l_@@_name_tl]{} } { \MakeLinkTarget[\l_@@_name_tl]{}\skip_horizontal:N \l_@@_indent_dim } } { \dim_compare:nNnTF \l_@@_indent_dim < \c_zero_skip { \skip_horizontal:N \l_@@_indent_dim \MakeLinkTarget{\l_@@_name_tl} } { \MakeLinkTarget{\l_@@_name_tl}\skip_horizontal:N \l_@@_indent_dim } { \l_@@_number_decls_tl \UseTaggingSocket{sec/title/number}{\int_use:N\l_@@_level_int}{#2} } \skip_horizontal:n { \l_@@_number_title_sep_tl } } \l_@@_title_decls_tl % \end{macrocode} % \ufi{this should probably be a format command.} % \begin{macrocode} \l_@@_before_code_tl {#3} \l_@@_after_code_tl \group_end: } % \end{macrocode} % \end{template} % % \subsubsection{Internal commands used by the template code} % % \begin{macro}{\@@_determine_penalty:} % % \begin{macrocode} \cs_new:Npn \@@_determine_penalty: { % \end{macrocode} % If a penalty was specified use it, otherwise use \cs{@secpenalty}. % \begin{macrocode} \int_compare:nNnT \l_@@_penalty_int = \c_max_int { \int_set:Nn \l_@@_penalty_int \@secpenalty } } % \end{macrocode} % \end{macro} % \begin{macro}{\@@_determine_number_typesetting:N} % % \begin{macrocode} \cs_new:Npn \@@_determine_number_typesetting:N #1 { % \end{macrocode} % % Using or suppressing a heading number depends on the heading level % compared to the document value of \cs{c@secnumdepth}. If that % doesn't suppress the number then an explicit key or a star form % might still have suppressed it. % \begin{macrocode} \bool_set:Nn \l_@@_unnumbered_bool { \bool_lazy_or_p:nn { \int_compare_p:nNn \l_@@_level_int > \c@secnumdepth } { \bool_if_p:N #1 } } % \end{macrocode} % If we aren't producing a heading with a number we set % \cs{c@secnumdepth} to a low number (it is reset at the end of the template % code) % \begin{macrocode} \bool_if:NTF \l_@@_unnumbered_bool { \int_gset:Nn\c@secnumdepth{-99} % \end{macrocode} % and we set \cs{l_@@_typeset_number_tl} to do nothing. % \begin{macrocode} \tl_clear:N \l_@@_typeset_number_tl } % \end{macrocode} % Otherwise the heading counter is incremented and a formatted % version of the number plus any following (or preceding) space is % stored in \cs{l_@@_typeset_number_tl}. % We use the kernel version of \cs{refstepcounter} as anchors are handled elsewhere. % \begin{macrocode} { \@kernel@refstepcounter{ \l_@@_name_tl } \protected@edef \l_@@_typeset_number_tl { \@@_number_format:n { \l_@@_name_tl } } } } % \end{macrocode} % \end{macro} % \begin{macro}{\@@_vertical_before_spacing:} % % \begin{macrocode} \cs_new:Npn \@@_vertical_before_spacing: { \tl_if_blank:VTF \l_@@_start_code_tl { \if@noskipsec \leavevmode \fi \par \if@nobreak \everypar{} \else \addpenalty \l_@@_penalty_int \addvspace \l_@@_before_skip % \end{macrocode} % The \cs{vspace*} inserts a rule, we insert therefore the % skip only if it is different to zero. % \begin{macrocode} \dim_compare:nNnF{\l_@@_after_penalty_skip}={0pt} { \vspace* \l_@@_after_penalty_skip } \fi } { \l_@@_start_code_tl % \end{macrocode} % If \cs{l_@@_start_code_tl} holds code, we assume that it handles % pagination, e.g., a \cs{clearpage}, etc. We therefore only add % the skip that would follow the penalty. % \begin{macrocode} \dim_compare:nNnF{\l_@@_after_penalty_skip}={0pt} { \vspace* \l_@@_after_penalty_skip } } } % \end{macrocode} % \end{macro} % % \begin{macro}{\addcontentslinebookmark,\addcontentslinebookmarkOff, % \addcontentslinebookmarkOn} % We want to be able to control bookmarks independently from the toc entries, % and also want to disable a bookmark by setting it to empty. For this we need % some command to handle the bookmark command. % \begin{macrocode} \newcommand\addcontentslinebookmark[3]{} \newcommand\addcontentslinebookmarkOff{} \newcommand\addcontentslinebookmarkReset{} \providecommand\texorpdfstring[2]{#1} \AddToHook{package/hyperref/after} { \RenewCommandCopy\addcontentslinebookmark\Hy@addcontentsline@addbookmark \renewcommand\addcontentslinebookmarkOff { \ifHy@bookmarks \let\addcontentslinebookmarkReset\Hy@bookmarkstrue \else \let\addcontentslinebookmarkReset\relax \fi \Hy@bookmarksfalse } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_handle_marks_etc:nnnnn} % Arg 1: toc entry, arg 2: mark, arg 3: bookmark, arg 4: nameref, arg 5: label code % \begin{macrocode} \cs_new:Npn \@@_handle_marks_etc:nnnnn #1#2#3#4#5 { % \tl_set:Nn\@currentlabelname{#4} \IfBlankF {#2} { \@@_mark_cmd:n { #2 } } \IfBlankTF {#1} % \end{macrocode} % If the toc entry is empty the bookmarks must be set without \cs{addcontentsline} % \begin{macrocode} { \IfBlankF{#3} { \addcontentslinebookmark{toc}{\l__head_name_tl} { \bool_if:NF \l_@@_unnumbered_bool { \protect\numberline{ \use:c{ the \l_@@_name_tl } } } #3 } } } { % \end{macrocode} % If the bookmark entry is empty we must disable the bookmarks locally % before the \cs{addcontentsline} and reenable afterwards. We do not % check if they are already disabled, perhaps later. % \begin{macrocode} \IfBlankT{#3}{\addcontentslinebookmarkOff} \addcontentsline{toc}{ \l_@@_name_tl } { \bool_if:NF \l_@@_unnumbered_bool { \protect\numberline{ \use:c{ the \l_@@_name_tl } } } % \end{macrocode} % We use \cs{texorpdfstring} to separate toc and bookmark text. % \begin{macrocode} \texorpdfstring{#1}{#3} } \addcontentslinebookmarkReset } % \end{macrocode} % Some headings (like \cs{chapter}) also want to write stuff to % other contents files like \texttt{.lot} or % \texttt{.lof}.\fmi{perhaps this should have a hook for packages} % \begin{macrocode} \l_@@_contents_extra_tl % \end{macrocode} % We can always run the label code (it might be empty) % \begin{macrocode} \@@_debug_typeout:n{--->~label(s):~ \exp_not:n{#5}} #5 } % \end{macrocode} % \end{macro} % % % % % \subsection{Support for legacy classes and packages} % % If we define heading commands in the kernel (or in the tagging % code) using % \begin{verbatim} % \DeclareDocumentCommand \section {s ={shorttitle}o m} % { \ParseLaTeXeHeading {section} {#1} {#2} {#3} } % \end{verbatim} % then this gets overwritten by every class right now. % % If we redeclare them after the class was loaded then % we overwrite the layout of legacy classes (done, for example, with % \cs{@startsection}). New classes that use the above interface % would be fine though, as long as we have declared the instances % before the class is loaded. % % So to make legacy classes work with their existing layout, we % should not (ever) overwrite \cs{section} but let the class % definition call % \cs{@startsection} which would then set up suitable instances and % only after that call \cs{ParseLaTeXeHeading}. % % However, that would mean a \enquote{new} class like ltx-article % would need to add the above definition and declare or edit the % corresponding instances, instead of just declaring or adding the % instances. % % A perhaps better alternative could be to delay the definition of % \cs{section} and friends until after the class got loaded and % then take a peak at \cs{section} as defined by the class and if % it contains a \cs{@startsection} call, leave it alone and % otherwise overwrite it. And if the class hasn't defined % \cs{section} (because it is a new class) declare it. Of course % that means \cs{section} would then be available with every class % even if it was never meant to contain headings. % % But while writing this up, I start to think it is best if a new % class defines both the document interface (i.e., the above % command) as well as the layout (declare the instances) and the % kernel does neither. It has been this way before and it is % consistent, so why change. % % The situation with headings defined via \cs{secdef} is worse: we % don't have a nice handle as with \cs{@startsection} so there is % no real way other than through static analysis to set up such % a heading in the new template style. So all that is possible (I % think) is that after the class has been loaded, we look if the % usual candidates (\cs{part} and \cs{chapter}) have been defined % and overwrite them with a standard layout. That would make the % class tagging aware but, of course, would likely change the % layout. % % The current implementation % \begin{itemize} % \item provides instance for the heading commands of the standard classes; % \item declares the heading commands for the standard classes with % the new interfaces through class hooks; % \item other classes call the adapted \cs{@startsection}; other headings % command like \cs{part} or \cs{chapter} are not handled and must be setup % individually. % \end{itemize} % % \subsubsection{Instances (sample/default definitions)} % % \begin{instance}{heading part} % An instance suitable for \cls{book} and \cls{report}. An instance suitable % for \cls{article} is above in the hook. % \begin{macrocode} \DeclareInstance{heading}{part}{display} { , name = part , level = -1 , placement = page , after-penalty-sep = 0pt , number-format = \partname\nobreakspace\thepart , decls = \centering\bfseries , number-decls = \huge , title-decls = \Huge , headformat-instance = display , mark-cmd = \partmark {#1} } % \end{macrocode} % \end{instance} % % \begin{instance}{heading chapter} % % \begin{macrocode} \DeclareInstance{heading}{chapter}{display} { , name = chapter , level = 0 , placement = top , after-penalty-sep = 50pt % , number-title-sep = 20pt % currently in headformat , after-sep = 40pt , number-format = \@chapapp\space \thechapter , decls = \raggedright \parindent0pt \bfseries , number-decls = \huge , title-decls = \Huge , headformat-instance = display , mark-cmd = \chaptermark {#1} , contents-extra= \addtocontents{lof}{\protect\addvspace{10\p@}}% \addtocontents{lot}{\protect\addvspace{10\p@}}% } % \end{macrocode} % \end{instance} % % % \begin{instance}{heading section} % % \begin{macrocode} \DeclareInstance{heading}{section}{display} { , name = section , level = 1 , mark-cmd = \sectionmark {#1} , before-sep = 3.5ex plus 1ex minus .2ex , after-sep = 2.3ex plus .2ex , decls = \normalfont\Large\bfseries } % \end{macrocode} % \end{instance} % % % \begin{instance}{heading subsection} % % \begin{macrocode} \DeclareInstance{heading}{subsection}{display} { , name = subsection , parent-name = section , level = 2 , mark-cmd = \subsectionmark {#1} , before-sep = 3.25ex plus 1ex minus .2ex , after-sep = 1.5ex plus .2ex , decls = \normalfont\large\bfseries } % \end{macrocode} % \end{instance} % % % \begin{instance}{heading subsubsection} % % \begin{macrocode} \DeclareInstance{heading}{subsubsection}{display} { , name = subsubsection , parent-name = subsection , level = 3 , before-sep = 3.25ex plus 1ex minus .2ex , after-sep = 1.5ex plus .2ex , decls = \normalfont\normalsize\bfseries } % \end{macrocode} % \end{instance} % % \begin{instance}{heading paragraph} % % \begin{macrocode} \DeclareInstance{heading}{paragraph}{runin} { , name = paragraph , parent-name = subsubsection , level = 4 , before-sep = 3.25ex \@plus1ex \@minus.2ex , after-sep = 1em , decls = \normalfont\normalsize\bfseries , mark-cmd = \paragraphmark {#1} , headformat-instance = paragraph } % \end{macrocode} % \end{instance} % % \begin{instance}{heading subparagraph} % % \begin{macrocode} \DeclareInstance{heading}{subparagraph}{runin} { , name = subparagraph , parent-name = paragraph , level = 5 , before-sep = 3.25ex \@plus1ex \@minus .2ex , after-sep = 1em , decls = \normalfont\normalsize\bfseries , mark-cmd = \subparagraphmark {#1} , headformat-instance = subparagraph } % \end{macrocode} % \end{instance} % % \begin{instance}{headformat display} % % \begin{macrocode} \DeclareInstance{headformat}{display}{display} { , indent = 0pt , before-code = , after-code = } % \end{macrocode} % \end{instance} % % \begin{instance}{headformat hang} % % \begin{macrocode} \DeclareInstance{headformat}{hang}{hang} { , indent = 0pt , before-code = , after-code = } % \end{macrocode} % \end{instance} % % \begin{instance}{headformat paragraph} % % \begin{macrocode} \DeclareInstance{headformat}{paragraph}{runin} { , indent = 0pt , before-code = , after-code = } % \end{macrocode} % \end{instance} % % \begin{instance}{headformat subparagraph} % \begin{macrocode} \DeclareInstance{headformat}{subparagraph}{runin} { , indent = \parindent , before-code = , after-code = } % \end{macrocode} % \end{instance} % % \begin{instance}{headformat section-special} % A special headformat instance for testing. It can be used with % \verb+\section[headformat-instance=section-special]{bla}+ % \begin{macrocode} \DeclareInstance{headformat}{section-special}{hang} { , indent = 4em , after-code = ! } % \end{macrocode} % \end{instance} % % \subsubsection{New \cs{@startsection}} % % \begin{macro}{\@startsection} % To support legacy classes that implement headings through a call % to \cs{@startsection} we redefine this command to generate a % \text{heading} instance from the arguments of \cs{@startsection} if % it doesn't yet exist and then use this instance to typeset the % heading. % % NOTE: To handle legacy definition like % \verb+{\normalfont\Large\bfseries\MakeUppercase}+ in the last argument % it copies this argument both to % \texttt{decls} and to \texttt{before-code}. % % \begin{macrocode} \DeclareDocumentCommand \@startsection {mmmmmm s ={shorttitle}o m}{ % \end{macrocode} % If there already exists an instance \texttt{\#1-@startsection} then arguments % 2--6 are ignored and we simply call that instance. Otherwise we % go through the process to set it up. This allows classes, packages % and authors to create and overwrite definitions with \cs{@startsection}. % But after a call to a command using the \cs{@startsection} % the instances are created. It is therefore not possible to redefine the command % after a first use or to create two commands using the same level, e.g. \cs{section} % and \cs{specialsection}. Such setups should use the new interfaces to declare % heading commands. % \begin{macrocode} \IfInstanceExistsF{heading}{#1-@startsection}{ % \end{macrocode} % % \begin{macrocode} \@@_debug_typeout:n{Info:~ setting~ up~ instances~ for~ legacy~ \string\@startsection} % \end{macrocode} % In the \LaTeXe{} logic a negative \#4 means we do not indent the % following paragraph \ldots % % It is okay to change any \texttt{em} or \texttt{ex} % specifications to real \texttt{pt} values here, because this code % is executed in the same place where \cs{@startsection} is % normally executed and inside the original definitions such % assignments happen as well, before there is any font change % happening for \#4 and \#5. % \begin{macrocode} \@tempskipa #4\relax \@afterindenttrue \ifdim \@tempskipa <\z@ \@tempskipa -\@tempskipa \@afterindentfalse \fi % \end{macrocode} % \ldots\ and a negative \#5 means we should produce a runin heading. % \begin{macrocode} \@tempskipb #5\relax \ifdim \@tempskipb>\z@ \use:e { \DeclareInstance{heading}{#1-@startsection}{display}{ , name = #1 , level = #2 , mark-cmd = \exp_not:c{#1mark} {##1} , before-sep = \the\@tempskipa , after-sep = \the\@tempskipb , para-indent = \if@afterindent true \else false\fi , decls = \exp_not:n{#6} % \end{macrocode} % we also do the declarations in \texttt{before-code} to handle % settings which ends, e.g., with \cs{MakeUppercase}, % \begin{macrocode} , headformat-instance = #1-@startsection }} % \end{macrocode} % We can expect that the instance \texttt{\#1-@startsection} is not % set up by the user if \texttt{\#1-@startsection} isn't, so no check. % \begin{macrocode} \DeclareInstance{headformat}{#1-@startsection}{hang}{indent = #3,before-code={#6}} \else \@tempskipb=-\@tempskipb \use:e { \DeclareInstance{heading}{#1-@startsection}{runin}{ , name = #1 , level = #2 , mark-cmd = \exp_not:c{#1mark} {##1} , before-sep = \the\@tempskipa , after-sep = \the\@tempskipb , decls = \exp_not:n{#6} , headformat-instance = #1-@startsection }} \DeclareInstance{headformat}{#1-@startsection}{runin}{indent = #3,before-code={#6}} \fi } \ParseLaTeXeHeading {#1-@startsection}{#7}{#8}{#9} } % \end{macrocode} % \end{macro} % % Some classes redefine \cs{@startsection} and then our redefinition is lost. So we % reinstate it % \begin{macrocode} \NewCommandCopy\kernel@startsection\@startsection \AddToHook{class/after}[head/@startsection] {\RenewCommandCopy\@startsection\kernel@startsection} % \end{macrocode} % % % \subsubsection{New \cs{secdef}} % The command maps standard \cs{secdef} definition of \cs{part} and \cs{chapter} to % the new interface. Unknown heading commands warn (or error if tagging is active) and % then call the old commands. % \begin{macro}{\secdef} % \begin{macrocode} \RenewDocumentCommand\secdef{mmsO{#5}m} { \str_case:enF {\cs_to_str:N#1} { {@part} { \IfNoValueTF{#4} {\ParseLaTeXeHeading{part}{#3} {start-code=\relax} {#5}} { \@@_process_shorttitle:nN{#4}\l_@@_tmpa_tl \ExpandArgs{nne}\ParseLaTeXeHeading{part}{#3}{start-code=\relax,\exp_not:o{\l_@@_tmpa_tl}} {#5} } \@latex@warning{\noexpand\secdef~detected~in~\noexpand\part~command.\MessageBreak \noexpand\part~will~be~redefined~to~use~templates.\MessageBreak This~may~change~the~layout!} \DeclareDocumentCommand \part {s ={shorttitle}o m} { \ParseLaTeXeHeading {part} {##1} {##2} {##3} } } {@chapter} { \IfNoValueTF{#4} { \ParseLaTeXeHeading{chapter}{#3} {#4} {#5} } { \@@_process_shorttitle:nN{#4}\l_@@_tmpa_tl \ExpandArgs{nno}\ParseLaTeXeHeading{chapter}{#3}{\l_@@_tmpa_tl} {#5} } \@latex@warning{\noexpand\secdef~detected~in~\noexpand\chapter~command.\MessageBreak \noexpand\chapter~will~be~redefined~to~use~templates.\MessageBreak This~may~change~the~layout!} \DeclareDocumentCommand \chapter {s ={shorttitle}o m} { \ParseLaTeXeHeading {chapter} {##1} {##2} {##3} } } } { \tag_if_active:TF\@latex@error\@latex@warning {\noexpand\secdef~with~unknown~argument~\noexpand#1 found.\MessageBreak The~command~can~not~be~adapted~on~the~fly~to~support~tagging.\MessageBreak The~heading~command~using~this~\noexpand\secdef~should~be~ reimplemented\MessageBreak with~templates}{} \IfBooleanTF{#3}{#2{#5}}{#1[#4]{#5}} } } % \end{macrocode} % A helper command to reprocess the argument as key-val % \begin{macrocode} \NewDocumentCommand\@@_process_shorttitle:nN{={shorttitle}mm} { \tl_set:Nn#2{#1} } % \end{macrocode} % \end{macro} % \subsubsection{Core \LaTeX{}} % We define here as an example the heading commands with the new % interfaces for the three standard classes. % % \begin{macrocode} \AddToHook{class/article/after}[head/example] { \DeclareInstance{heading}{part}{display} { , name = part , level = -1 , before-sep = 4ex , after-sep = 3ex , number-format = \partname\nobreakspace\thepart , decls = \raggedright\bfseries , number-decls = \Large , title-decls = \huge , headformat-instance = part , mark-cmd = \partmark {#1} } \DeclareInstance{headformat}{part}{display} { , indent = 0pt , before-code = , after-code = , number-title-sep = 0pt } \DeclareDocumentCommand \part {s ={shorttitle}o m} { \ParseLaTeXeHeading {part} {#1} {#2} {#3} } \@@_setup_default_heading: } \AddToHook{class/report/after}[head/example] { \DeclareDocumentCommand \part {s ={shorttitle}o m} { \ParseLaTeXeHeading {part} {#1} {#2} {#3} } \DeclareDocumentCommand \chapter {s ={shorttitle}o m} { \if@mainmatter \ParseLaTeXeHeading {chapter}{#1} {#2} {#3} \else \IfBooleanTF{#1} {% starred: \ParseLaTeXeHeading {chapter}{\BooleanTrue} {#2} {#3} } {\IfNoValueTF{#2} {\ParseLaTeXeHeading {chapter}{\BooleanTrue} {shorttitle={#3}} {#3}} {\ParseLaTeXeHeading {chapter}{\BooleanTrue} {#2} {#3}} } \fi } \@@_setup_default_heading: } \AddToHook{class/book/after}[head/example] { \DeclareDocumentCommand \part {s ={shorttitle}o m} { \ParseLaTeXeHeading {part} {#1} {#2} {#3} } \DeclareDocumentCommand \chapter {s ={shorttitle}o m} { \if@mainmatter \ParseLaTeXeHeading {chapter}{#1} {#2} {#3} \else \IfBooleanTF{#1} {% starred: \ParseLaTeXeHeading {chapter}{\BooleanTrue} {#2} {#3} } {\IfNoValueTF{#2} {\ParseLaTeXeHeading {chapter}{\BooleanTrue} {shorttitle={#3}} {#3}} {\ParseLaTeXeHeading {chapter}{\BooleanTrue} {#2} {#3}} } \fi } \@@_setup_default_heading: } % \end{macrocode} % % % % \begin{macrocode} \cs_new_protected:Npn \@@_setup_default_heading: { % \end{macrocode} % \begin{macro}{\section} % % \begin{macrocode} \DeclareDocumentCommand \section {s ={shorttitle}o m} { \ParseLaTeXeHeading {section} {##1} {##2} {##3} } % \end{macrocode} % \end{macro} % % \begin{macro}{\subsection} % % \begin{macrocode} \DeclareDocumentCommand \subsection {s ={shorttitle}o m} { \ParseLaTeXeHeading {subsection} {##1} {##2} {##3} } % \end{macrocode} % \end{macro} % % \begin{macro}{\subsubsection} % % \begin{macrocode} \DeclareDocumentCommand \subsubsection {s ={shorttitle}o m} { \ParseLaTeXeHeading {subsubsection} {##1} {##2} {##3} } % \end{macrocode} % \end{macro} % % \begin{macro}{\paragraph} % % \begin{macrocode} \DeclareDocumentCommand \paragraph {s ={shorttitle}o m} { \ParseLaTeXeHeading {paragraph} {##1} {##2} {##3} } % \end{macrocode} % \end{macro} % % \begin{macro}{\subparagraph} % % \begin{macrocode} \DeclareDocumentCommand \subparagraph {s ={shorttitle}o m} { \ParseLaTeXeHeading {subparagraph} {##1} {##2} {##3} } } %end of command % \end{macrocode} % \end{macro} % \begin{macrocode} % % \end{macrocode} % % \section{Issues and problems noticed along the way} % % \subsection{Local \cs{DeclareInstance}} % % \cs{DeclareInstance} does its declaration locally. That might be the % right decision (or not) but we need to make sure that it in that % case all of the declaration is local. % % One potential problem with that is that it might allocate \TeX{} % registers. % % The problem showed up in the redefinition of \cs{@startsection}, % because in the current document some headings are local to an % environment, so things get redeclared over and over again. % % \subsection{\cs{SetCurrentTemplateKeys}} % % Furthermore, I think I would like to have some % \cs{SetCurrentTemplateKeys} where one does not have to specify % the type nor the template name, because that is how it is always % used (by me). % % \subsection{O-expansion of \cs{UseInstance} arguments} % % Whenever a template code calls a sub-instance and that % sub-instance takes arguments, then the values for these arguments % are typically inside tokenlists or registers so that for % efficiency (and sometimes as a total must) one has to o-expand % all arguments. While that can be coded somehow, e.g., % \begin{verbatim} % \use:e { % \UseInstance{headformat} { \l_@@_headformat_instance_tl } % { \exp_not:o \UnusedTemplateKeys } % { \exp_not:o { \l_@@_typeset_number_tl } } % { \exp_not:n { #3 } } % { \exp_not:o { \use_i:nn #9 } } % { \exp_not:o { \use_ii:nn #9 } } % } % \end{verbatim} % % it would be better to have a version of \cs{UseInstance} that % does this automatically. No suggestion for a name. % % % % \subsection{Switch \cs{openright} is not defined by core} % % I think this should change and it might be enough to just define % it in the kernel (I think \cs{newif} no longer complains if it % acts on an existing \cs{if...} % % \subsection{Indexheading at least for l3doc is wrong now} % % Needs checking. % % \begin{macrocode} %<*latex-lab> \ProvidesFile{sec-template-latex-lab-testphase.ltx} [\ltlabsecIIdate\space v\ltlabsecIIversion\space latex-lab wrapper sec-template] \RequirePackage{latex-lab-testphase-sec-template} % % \end{macrocode} % \end{implementation} % % % % \Finale % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \endinput