% \iffalse meta-comment %% File: latex-lab-block.dtx (C) Copyright 2021-2026 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 % \def\ltlabenumdate{2026-01-16} \def\ltlabenumversion{0.80b} %<*driver> \DocumentMetadata{tagging=on,pdfstandard=ua-2} \documentclass[kernel]{l3in2edoc} \usepackage{longtable,tikz} \EnableCrossrefs \CodelineIndex \begin{document} \DocInput{latex-lab-enumitem.dtx} \end{document} % % % \fi % % % \title{The \textsf{latex-lab-enumitem} package\\ % Emulating enumitem} % \author{\LaTeX{} Project\thanks{Initial implementation done by Ulrike Fischer}} % \date{v\ltlabenumversion\ \ltlabenumdate} % % \maketitle % % \newcommand{\xt}[1]{\textsl{\textsf{#1}}} % \newcommand{\TODO}[1]{\textbf{[TODO:} #1\textbf{]}} % \newcommand{\docclass}{document class \marginpar{\raggedright document class % customizations}} % % \newcommand\insttype[1]{\texttt{#1}} % % % \providecommand\hook[1]{\texttt{#1}} % % \begin{abstract} % The following code implements an emulation of \pkg{enumitem} usable with the Tagging Support Code. % It does \emph{not} emulate every key and command of enumitem. Also syntax and behaviour % can differ in place. % \end{abstract} % % % \section{Introduction} % % The \pkg{enumitem} package offers customizable and enhanced list environments % but is not compatible with the Tagging Support Code where lists are % reimplemented with templates. % % The following code partly emulates \pkg{enumitem} and should be loaded % instead of the package. % % \section{Key emulation} % % A large part of the \pkg{enumitem} functionality is provided through keys. Such keys % can be set in the optional argument of single lists and globally for some or all % lists in the \cs{setlist} command. Some keys are simple interfaces to list parameters, % other have quite complicated effects, e.g. if they force recalculations of dependant % parameters. % % With the new \LaTeX implementation lists do have an optional argument too % which process a key-value list. % The key names differ to the one of \pkg{enumitem} but in a number of cases a % simple mapping is possible. The \LaTeX{} key names are noted in the following % tabular in the second column. % They can be used instead of the \pkg{enumitem} keys (and will be a bit faster). % The third column shows if the \pkg{enumitem} key has been already emulated and is usable % in the optional argument. The fourth column shows if it is usable in \cs{setlist}. % % % \begin{longtable}{>{\ttfamily}l>{\ttfamily}lcll} % \caption{List of enumitem keys}\\ % \rmfamily \pkg{enumitem} key & \rmfamily \LaTeX{} key & opt.\ arg. & \cs{setlist} & comment\\ \hline \endhead % label & \rmfamily (related: \texttt{item-label}) & & &see key description\\ % label*\\ % ref \\ % font,format & label-format & yes & & see key description!! \\ % format\\ % align & label-align & yes & & see key description\\ % topsep & begin-vspace & yes & & \\ % partopsep & begin-extra-vspace & yes & & \\ % parsep & para-vspace & yes & & \\ % itemsep & item-vspace & yes & & \\ % labelindent\\ % labelindent*\\ % leftmargin & left-margin & & & see key description\\ % rightmargin & right-margin & & & see key description\\ % listparindent & para-indent & & & see key description\\ % itemindent & item-indent & & & see key description\\ % labelsep & label-sep & & & see key description\\ % labelsep* \\ % labelwidth & label-width & & & see key description \\ % left \\ % widest \\ % widest*\\ % start & start & yes & ? \\ % resume & resume & yes & ? & see key description\\ % resume* \\ % series\\ % beginpenalty & begin-penalty & yes & ?\\ % midpenalty & item-penalty & yes & ? \\ % endpenalty & end-penalty & yes & ?\\ % before \\ % before* \\ % after\\ % after*\\ % first\\ % first*\\ % style\\ % noitemsep & \textit{meta-key} & yes \\ % nosep & \textit{meta-key} & yes \\ % wide & & partly & \\ % itemjoin\\ % itemjoin*\\ % afterlabel\\ % mode\\ % \end{longtable} % % \section{Package options} % % \pkg{enumitem} has a number of package options, but none of them will % be supported by the emulation: adding support for the \pkg{enumerate} syntax % (\texttt{shortlabels}) is not planed; inline lists are not yet implemented % but once they are they will be available always. % % \begin{longtable}{lll} % \caption{List of enumitem package options}\\ % \pkg{enumitem} option \\\hline\endhead % shortlabels & \\ % inline & \\ % ignoredisplayed & \\ % series=override & \\ % sizes & \\ % loadonly & % \end{longtable} % % \section{Commands} % % \begin{longtable}{lll} % \caption{List of enumitem user commands}\\ % name & emulated & comment\\\hline\endhead % \cs{SetLabelAlign}\\ % \cs{DrawEnumitemLabel} \\ % \cs{labelindent}\\ % {\cs{EnumitemId}}\\ % {\cs{SetEnumitemKey}}\\ % {\cs{SetEnumitemValue}}\\ % {\cs{SetEnumerateShortLabel}}\\ % \cs{newlist} & yes \\ % \cs{renewlist}\\ % {\cs{setlist}}\\ % \cs{setlistdepth}\\ % \cs{AddEnumerateCounter}\\ % \cs{restartlist}\\ % \cs{SetEnumitemSize} % \end{longtable} % % \section{Calculating values} % % When setting up the dimension of lists the values related to the left margin and % placement of the label are typically the most challenging as four dimensions are involved % (which can be negative). \pkg{enumitem} introduces a fifth dimension \cs{labelindent}. % % \begin{tikzpicture}[alt=List layout] % \coordinate(leftmargin) at (0,0); % \coordinate(labelleft) at (1,0); % \coordinate(labelright) at (4,14pt); % \draw (labelleft) rectangle (labelright); % \draw [<->] ([yshift=-5pt]labelleft) --++(3,0) node[below,midway]{\texttt{\textbackslash labelwidth}}; % \draw[<->]([yshift=-1cm]leftmargin)--++(6,0)node[below,midway]{\texttt{\textbackslash leftmargin}}; % \draw[<->](labelright)--++(2,0)node[above,midway]{\texttt{\textbackslash labelsep}}; % \draw[<->](5,-5pt)--++(1,0)node[below]{\texttt{\textbackslash itemindent}}; % \draw(5,0)--++(0,-2)--++(5,0)--++(0,2cm+14pt)--++(-4,0)--++(0,-14pt)--cycle; % \draw[<->](0,5pt)--++(1,0)node[above left]{\textit{\textbackslash labelindent}}; % \end{tikzpicture} % % The relation between the five values is set through the following equation: % % \verb!\labelindent + \labelwidth + \labelsep = \leftmargin + \itemindent! % % So obviously one of the dimensions is redundant and can be calculated if the others % are given. By default \pkg{enumitem} calculates the new, \enquote{fake} dimension % \cs{labelindent} but it is possible to give \cs{labelindent} a specific value % and declare that another one is calculated by using \texttt{!} as value. % % % Calculation should happen after all keys are set. The code here therefore executes a % key \texttt{calculate} in the list code which looks which key is currently the dependant % one and calculates its value. % % \pkg{enumitem} also offers an option to calculate \cs{labelwidth} based on the widest % entry (which can be declared with the \texttt{widest} key) by using a star \texttt{*} as % value. % % \section{Alignment} % % % % \begin{macrocode} %<*package> % \end{macrocode} % % \section{Implementation} % \begin{macrocode} \ProvidesExplPackage {latex-lab-enumitem} {\ltlabenumdate} {\ltlabenumversion} {Emulating enumitem} % \end{macrocode} % % % % \subsection{Key emulation} % % \subsubsection{\texttt{label}} % % The key \texttt{item-label} from the new \LaTeX{} list code % changes the label representation from e.g. \cs{labelenumi} % to the key value. Internally the representation of the current list is stored in % \cs{l__block_item_label_tl}. It does not change \cs{labelenumi}, \cs{theenumi} or % \cs{p@enumi} and so also doesn't affect references. % % The key \texttt{label} from \pkg{enumitem} works quite differently: it changes % the label representation command \cs{labelenumi}, the counter representation % \cs{theenumi} and sets \cs{p@enumi} to empty. So by default the reference is identical % to the label representation and if a different reference is wanted it must be set % with the \texttt{ref} key. To allow to use \cs{labelenumi} in nested list to create % chained labels enumitem replaces all \verb+\roman*+ by \verb+\roman{enumi}+ (and similar % for the other counter representations). The replacement code uses expansion and % so enumitem will error if the star is used with an unknown counter representation like % \verb+label=\fnsymbol*+ or \cs{alphalph}. Such unknown % counter representation must first be added with \cs{AddEnumerateCounter}. % % The new code is less fragile. Counter representation must only be declared with \cs{AddEnumerateCounter} % if the star-counter is used outside the current list (e.g. with the \texttt{label*} key. % % \begin{macrocode} %<@@=block> % we might want a different module in the end % \end{macrocode} % % At first a rather crude (slow) method to replace % e.g. \verb+\roman*+ by \verb+\roman{enumi}+ % in the label representation. TODO: speed up. % % \begin{macrocode} \clist_new:N \l_@@_normalize_cnt_clist \clist_set:Nn \l_@@_normalize_cnt_clist {\alph,\Alph,\roman,\Roman,\arabic,\fnsymbol} % \end{macrocode} % This command should only be used if \cs{l_@@_counter_tl} is not empty! % \begin{macrocode} \cs_new:Npn\@@_normalize_label:N #1 { \clist_map_inline:Nn\l_@@_normalize_cnt_clist { \tl_replace_all:Nne#1 {##1*}{\exp_not:N##1{\l_@@_counter_tl}} } } \cs_generate_variant:Nn\@@_normalize_label:N{c} % \end{macrocode} % % \begin{macrocode} \keys_define:nn{template/list/std} { label .code:n = { \tl_if_empty:NTF\l_@@_counter_tl { \tl_if_eq:NnTF\l_@@_inner_instance_tl{itemize} { \tl_set:cn{labelitem\int_to_roman:n{\l_@@_inner_level_counter_tl}}{#1} } { \tl_set:cn{label\l_@@_inner_instance_tl\int_to_roman:n{\l_@@_inner_level_counter_tl}}{#1} } } { \tl_set:cn{label\l_@@_counter_tl}{#1} \@@_normalize_label:c{label\l_@@_counter_tl} \tl_set_eq:cc{the\l_@@_counter_tl}{label\l_@@_counter_tl} \tl_set:cn{p@\l_@@_counter_tl}{} } } } % \end{macrocode} % % % % % \subsubsection{\texttt{label*}} % TODO: % % \subsubsection{\texttt{ref}} % TODO: % % \subsubsection{\texttt{font}, \texttt{format}} % % \begin{macrocode} \keys_define:nn{template/item/std} { font .meta:n = {label-format={#1{##1}}}} \keys_define:nn{template/item/std} { format .meta:n = {label-format={#1{##1}}}} % \end{macrocode} % % \subsubsection{\texttt{align}} % % Note: this also supports the value center but parleft is not implemented yet. % TODO: test for differences in behavior. % \begin{macrocode} \keys_define:nn{template/list/std} { align .meta:n = {label-align=#1}} % \end{macrocode} % % \subsubsection{\texttt{topsep}} % \begin{macrocode} \keys_define:nn{template/block/std} { topsep .meta:n = {begin-vspace=#1}} % \end{macrocode} % % \subsubsection{\texttt{partopsep}} % \begin{macrocode} \keys_define:nn{template/block/std} { partopsep .meta:n = {begin-extra-vspace=#1}} % \end{macrocode} % % \subsubsection{\texttt{parsep}} % \begin{macrocode} \keys_define:nn{template/block/std} { parsep .meta:n = {para-vspace=#1}} % \end{macrocode} % % \subsubsection{\texttt{itemsep}} % \begin{macrocode} \keys_define:nn{template/block/std} { itemsep .meta:n = {item-vspace=#1}} % \end{macrocode} % % \subsubsection{\texttt{leftmargin}} % TODO: handle special values ! and *.\\ % Special values do not work with \LaTeX{} key at the moment as it is a register! % \begin{macrocode} \keys_define:nn{template/block/std} { leftmargin .meta:n = {left-margin=#1}} % \end{macrocode} % % \subsubsection{\texttt{rightmargin}} % TODO: handle special values ! and *.\\ % Special values do not work with \LaTeX{} key! % \begin{macrocode} \keys_define:nn{template/block/std} { rightmargin .meta:n = {right-margin=#1}} % \end{macrocode} % % \subsubsection{\texttt{listparindent}} % TODO: handle special values ! and *.\\ % Special values do not work with \LaTeX{} key! % \begin{macrocode} \keys_define:nn{template/block/std} { listparindent .meta:n = {para-indent=#1}} % \end{macrocode} % % \subsubsection{\texttt{itemindent}} % TODO: handle special values ! and *.\\ % Special values do not work with \LaTeX{} key! % \begin{macrocode} \keys_define:nn{template/list/std} { itemindent .meta:n = {item-indent=#1}} % \end{macrocode} % % \subsubsection{\texttt{labelsep}, \texttt{labelsep*}} % TODO: handle special values ! and *.\\ % Special values do not work with \LaTeX{} key! % \begin{macrocode} \keys_define:nn{template/list/std} { labelsep .meta:n = {label-sep=#1}} % \end{macrocode} % % \subsubsection{\texttt{labelwidth}} % TODO: handle special values ! and *.\\ % Special values do not work with \LaTeX{} key! % \begin{macrocode} \keys_define:nn{template/list/std} { labelwidth .meta:n = {label-width=#1}} % \end{macrocode} % % \subsubsection{\texttt{labelindent}, \texttt{labelindent*}} % TODO:, see also \cs{labelindent}, note special value ! and * % % \subsubsection{\texttt{left}} % TODO: % % \subsubsection{\texttt{widest}, \texttt{widest*}} % TODO: % % \subsubsection{\texttt{start}} % TODO: Test with setlist % % \subsubsection{\texttt{resume}} % TODO: Test with setlist.\\ % The behavior of the key is different to enumitem, % where grouping of the environments matters: in \pkg{enumitem} % a enumerate that is e.g. in quote environment can not be resumed outside of the quote. % With the \LaTeX{} code grouping does not matter. % % \subsubsection{\texttt{resume*}} % TODO: decide if it should be implemented % % \subsubsection{\texttt{series}} % TODO: decide if it should be implemented % % \subsubsection{\texttt{beginpenalty}, \texttt{midpenalty}, \texttt{endpenalty}} % \begin{macrocode} \keys_define:nn{template/block/std} { beginpenalty .meta:n = {begin-penalty=#1}, endpenalty .meta:n = {end-penalty=#1}, midpenalty .meta:n = {item-penalty=#1} } % \end{macrocode} % % \subsubsection{\texttt{before}, \texttt{before*}} % TODO: describe behavior (second argument of list does not make sense) % Implement with hooks? % % \subsubsection{\texttt{after}, \texttt{after*}} % TODO: implement with hooks? % % \subsubsection{\texttt{first}, \texttt{first*}} % TODO: implement with hooks? % % \subsubsection{\texttt{style}} % TODO: values for description lists: standard, unboxed, nextline, sameline, multiline % % \subsubsection{\texttt{noitemsep}, \texttt{nosep}} % \begin{macrocode} \keys_define:nn{template/blockenv/std} { nosep .meta:n = { begin-extra-vspace=0pt, begin-vspace=0pt, item-vspace=0pt, para-vspace=0pt } } \keys_define:nn{template/blockenv/std} { noitemsep .meta:n = { item-vspace=0pt, para-vspace=0pt } } % \end{macrocode} % % % \subsubsection{\texttt{wide}} % TODO: calculated value should be delayed ... % \begin{macrocode} \keys_define:nn{template/blockenv/std} { wide .meta:n = { label-align=left, para-indent=#1, left-margin=0pt, label-width=0pt, item-indent=\dimeval{#1+\labelsep} %should be delayed .... }, wide .default:n = \parindent } % \end{macrocode} % % % \subsubsection{\texttt{itemjoin}, \texttt{itemjoin*}, \texttt{afterlabel}} % TODO % % \subsubsection{\texttt{mode}} % TODO % % % % \subsection{Package options} % % % \subsubsection{\texttt{shortlabels}} % % % \subsubsection{\texttt{inline}} % TODO, creates three environments enumerate*, itemize* and description* % % % \subsubsection{\texttt{sizes}} % % % \subsubsection{\texttt{loadonly}} % % % % %\subsection{Command emulation} % %\subsubsection{\cs{SetLabelAlign}} % % %\subsubsection{\cs{DrawEnumitemLabel}} % % %\subsubsection{\cs{labelindent}} % see also key labelindent % % %\subsubsection{\cs{EnumitemId}} % % %\subsubsection{\cs{SetEnumitemKey}} % % The \cs{SetEnumitemKey} defines shortcuts. We can defines them as % \texttt{.meta:n} on the \insttype{block} level. If they are for % the inner instances, they get passed down as necessary (this is % slightly less efficient than defining them at the right level, % but makes life easier). % \begin{macrocode} \NewDocumentCommand \SetEnumitemKey {mm} { \keys_define:nn { template/block/std } { #1 .meta:n = { #2 } } } % \end{macrocode} % % As an example, something like \texttt{noitemsep} could have been defined as %\begin{verbatim} % \SetEnumitemKey{noitemsep}{ itemsep=0pt, parsep=0pt } %\end{verbatim} % And this can even be done recursively, e.g., %\begin{verbatim} % \SetEnumitemKey{nosep} { noitemsep, topsep=0pt, partopsep=0pt } %\end{verbatim} % % %\subsubsection{\cs{SetEnumitemValue}} % % %\subsubsection{\cs{SetEnumerateShortLabel}} % % %\subsubsection{\cs{newlist}} % % The \cs{newlist} command allows to define new lists which clones the % standard lists. The last number describes the maximum number of levels. % Note that with itemize and description at most 6 levels are allowed. % This could be changed with % \begin{verbatim} % \setcounter{maxblocklevels}{7} % \DeclareInstance{block}{std-list-7}{display}{} % \end{verbatim} % but as enumitem doesn't allow more levels either the code does not force it. % % \begin{macro}{\newlist} % \begin{macrocode} \NewDocumentCommand\newlist{mmm} %name, type, number { \str_case:nnF{#2} { {itemize} {\@@_setup_itemize:nn{#1}{#3}} {enumerate} {\@@_setup_enumerate:nn{#1}{#3}} {description}{\@@_setup_description:nn{#1}{#3}} } % \end{macrocode} % TODO: message % \begin{macrocode} {\typeout{unknown~list~type~#2}} } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_setup_itemize:nn} % \begin{macrocode} \cs_new_protected:Npn \@@_setup_itemize:nn #1#2 %#1 name of new list, #2 max levels { \DeclareInstanceCopy{blockenv}{#1}{itemize} \EditInstance{blockenv}{#1}{inner-instance=#1} \NewDocumentEnvironment{#1}{!O{}} { \SimpleBlockEnv {#1} {max-inner-levels= \int_min:nn{\c@maxblocklevels}{#2},##1} } { \BlockEnvEnd } \int_step_inline:nnn{1}{\int_min:nn{\c@maxblocklevels}{#2}} { \IfInstanceExistsTF{list}{itemize-##1} { \DeclareInstanceCopy{list}{#1-##1}{itemize-##1} } % \end{macrocode} % The default label for lists below 4 is simply \cs{labelitemi}. % \begin{macrocode} { \ExpandArgs{c} \providecommand{labelitem\int_to_roman:n{##1}}{\labelitemi} \DeclareInstance{list}{#1-##1}{std} { item-label = \use:c{labelitem\int_to_roman:n{##1}}} } } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_setup_description:nn} % \begin{macrocode} \cs_new_protected:Npn \@@_setup_description:nn #1#2 { \DeclareInstanceCopy{blockenv}{#1}{description} \EditInstance{blockenv}{#1}{inner-instance=#1} \DeclareInstanceCopy{list}{#1}{description} \NewDocumentEnvironment{#1}{!O{}} { \SimpleBlockEnv{#1} {max-inner-levels= \int_min:nn{\c@maxblocklevels}{#2},##1} } { \BlockEnvEnd } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_setup_enumerate:nn} % \begin{macrocode} \cs_new_protected:Npn \@@_setup_enumerate:nn #1#2 { \DeclareInstanceCopy{blockenv}{#1}{enumerate} \EditInstance{blockenv}{#1}{inner-instance=#1} \NewDocumentEnvironment{#1}{!O{}} { \SimpleBlockEnv {#1} {max-inner-levels= #2,##1} } { \BlockEnvEnd } \int_step_inline:nnn{1}{#2} { \newcounter{#1\int_to_roman:n{##1}} \ExpandArgs{c} \newcommand{label#1\int_to_roman:n{##1}} {\arabic{#1\int_to_roman:n{##1}}.} \DeclareInstance{list}{#1-##1}{std} { item-label = \use:c{label#1\int_to_roman:n{##1}} , counter = {#1\int_to_roman:n{##1}} } } } % \end{macrocode} % \end{macro} % %\subsubsection{\cs{renewlist}} % %\subsubsection{\cs{setlist}} % % \begin{macrocode} \NewDocumentCommand\setlist{O{}m}{} %dummy for now % \end{macrocode} % %\subsubsection{\cs{setlistdepth}} % %\subsubsection{\cs{AddEnumerateCounter}} % %\subsubsection{\cs{SetEnumitemSize}} % %\subsubsection{\cs{restartlist}} % % \begin{macrocode} % % \end{macrocode}