% \iffalse meta-comment % arara: lualatex: { branch: developer, draft: true } % arara: lualatex: { branch: developer, draft: true } % arara: lualatex: { branch: developer, interaction: batchmode, shell: false } % arara: clean: { extensions: [ aux, log, out, glo, gls, hd, ind, ilg, idx, toc, atfi ] } % arara: clean: { files: [ userdoc.idx, userdoc.ilg, userdoc.ind ] } % arara: halt % % File: enumext.dtx % % Copyright (C) 2024-2026 by Pablo González L % % This work may be distributed and/or modified under the conditions of the % LaTeX Project Public License, either version 1.3c of this license or (at % your option) any later version. The latest version of this license is in % % https://www.latex-project.org/lppl.txt % % and version 1.3c or later is part of all distributions of LaTeX version % 2005/12/01 or later. % % This work is "maintained" (as per the LPPL maintenance status) % by Pablo González L. % % This work consists of the files enumext.dtx and enumext.sty. % % \fi % % \iffalse %<*driver> \documentclass[full]{l3doc} \usepackage[svgnames]{xcolor} \usepackage[sf,bf,compact,medium,pagestyles]{titlesec} \usepackage{lastpage,microtype,attachfile2,multicol,listings,titletoc,fontawesome5} \usepackage[english]{babel} \usepackage[top=0.5in,bottom=0.3in,left=1.70in,right=0.7in,footskip=0.2in,headheight=1cm,headsep=0.27cm]{geometry} % Set \parindent and \parskip \setlength{\parindent}{0pt} \setlength{\parskip}{\smallskipamount} % Extra stretch before overflowing the line \setlength{\emergencystretch}{2em} % Only for arara... I like arara :) \usepackage[scale=0.85]{comfortaa} \definecolor{araracolor}{rgb}{0, 0.72, 0.28} \newcommand{\araratext}[1]{{\small\normalfont\comfortaa\color{araracolor}\bfseries#1}} \newcommand*\arara{\araratext{ar\kern-.03emar\kern-.03ema}} % Fonts \usepackage[osf,nomath,mono=false,ScaleSF=0.95,ScaleRM=0.95]{libertinus-otf} % Set Monospace font, fix 'quotes' in verbatim \usepackage{sourcecodepro} \defaultfontfeatures[\ttfamily] { Numbers = OldStyle, Scale = 0.84249, Extension = .otf, } \setmonofont[ UprightFont = *-Regular, ItalicFont = *-RegularIt, BoldFont = *-Medium, BoldItalicFont = *-MediumIt, RawFeature = {+zero,+ss01}]{SourceCodePro} \newfontfamily\mysourcecodeprolight{SourceCodePro-Regular.otf}[ Scale = 0.80,FakeStretch =0.75, FontFace = {m}{it}{Font =SourceCodePro-RegularIt.otf,Color=FF0000}] \RenewDocumentCommand{\MacroLongFont}{} { \mysourcecodeprolight\small } % Internal \newfontfamily\mylmrotf{lmroman10-regular.otf}[NFSSFamily=lmrotf,Scale = 0.95] \newfontfamily\mylmmotf{lmmono10-regular.otf}[NFSSFamily=lmmotf,Scale = 0.95] % The character of visible space is now taken from Latin Modern Mono % to prevent fonts in T1. The original definition for xetex/luatex is % \def\verbvisiblespace{\usefont{OT1}{cmtt}{m}{n}\asciispace} \def\verbvisiblespace{{\fontfamily{lmmotf}\fontshape{n}\selectfont\char"2423}} % Math font \usepackage{unicode-math} \setmathfont[Scale = 0.95]{latinmodern-math.otf} \newfontfamily\fetamontotf{ffmw10.otf}[ Scale = 0.95,% RawFeature = {+latn,+rand,+kern,+size},% FontFace = {b}{n}{ffmw10.otf},% fix replace font ] % Remove `"` and `|` for short verbatim defined in l3doc, then set short |...| \AtBeginDocument { \DeleteShortVerb \" \DeleteShortVerb \| \lstMakeShortInline[language=enumext-doc,basicstyle=\ttfamily]\| } % Index \usepackage{imakeidx} \indexsetup{level=\section,firstpagestyle=myheader,othercode=\pagestyle{myheader}} % imakeidx also opens a write stream for the .idx file, and that conflicts % with the one opened by l3doc. Here we close that write stream: \ExplSyntaxOn \iow_close:c { @indexfile } % and later we will copy the write stream opened by imakeidx into \@indexfile % so that entries written to both streams end up in the same file. \makeindex[name=userdoc,options={-q ~ -s ~ gind.ist},columnsep=15pt,title={Index ~ of ~ Documentation}] \makeindex[options={-q ~ -s ~ gind.ist},columnsep=15pt,title={Index ~ of ~ Implementation}] \EnableCrossrefs % \PageIndex, \CodelineIndex undoes what \PageIndex does % \CodelineIndex tries to open another write stream for the index file. We don't % want that, so we temporarily make \makeindex a no-op: \cs_set_eq:NN \l__mydoc_tmp_makeindex_cs \makeindex \cs_set_nopar:Npn \makeindex { } \CodelineIndex \cs_set_eq:NN \makeindex \l__mydoc_tmp_makeindex_cs \DoNotIndex{\ , \1,\^} \exp_args:Ne \DoNotIndex { \tl_to_str:n { \{ } } \exp_args:Ne \DoNotIndex { \tl_to_str:n { \} } } \exp_args:Ne \DoNotIndex { \tl_to_str:n { \begin } } % \StartImplementation \cs_new_protected:Npn \StartImplementation { \bool_set_true:N \l__codedoc_in_implementation_bool } \bool_set_false:N \l__codedoc_in_implementation_bool % Links and index \newcommand{\HP}[1]{\emph{\hyperpage{#1}}\normalsize} \cs_new_protected:Nn \__mydoc_sort_index:nn { \bool_if:NTF \l__codedoc_in_implementation_bool { \index{#1\actualchar#2|HP} } { \index[userdoc]{#1\actualchar#2|HP} } } % The text of the entry in the first language (#2) for the user part and in % the second one (#3) for the implementation, chosen when the command is called. \cs_new_protected:Nn \__mydoc_sort_index:nnn { \bool_if:NTF \l__codedoc_in_implementation_bool { \__mydoc_sort_index:nn {#1} {#3} } { \__mydoc_sort_index:nn {#1} {#2} } } % Now, after imakeidx opens the write stream for the index file, we copy % the reference to \@indexfile: \cs_set_eq:cc { @indexfile } { \c_sys_jobname_str @idxfile } \ExplSyntaxOff % Package documented and packages for the examples \usepackage{tikz,enumext} % main % \usepackage{scontents} % \usepackage{shellesc} % LuaLaTeX syntax highlighter for l3doc (it also defines the color palette) \usepackage{mylhmc} \setmylhmc { module = enumext, provide = { setenumext, setenumextmeta, resetenumext, printkeyans, foreachkeyans, getkeyans, anskey, anspic, miniright, keyans, keyanspic }, key-path = {print, foreach, meta-families, }, } % Colors \definecolor{newlinkcolor}{HTML}{0A602C} \definecolor{rulecolor}{rgb}{0.96,0.96,0.96} % Get file info \GetFileInfo{enumext.sty} % Config hyperref \hypersetup { allcolors = newlinkcolor, colorlinks = true, linktoc = all, pdftitle = {.:: The enumext package --- \fileinfo{} ::.}, pdfauthor = {Pablo González L}, pdfsubject = {Documentation for \fileversion{} [\filedate] }, pdfkeywords = {worksheets, multiple choice, expl3, l3prop, l3seq, list, enumerate, store answers, tagged}, bookmarksopenlevel = 2, } % User level commands \ExplSyntaxOn % Logo \NewDocumentCommand \pkglogo { } { \group_begin: \LibertinusSansOsF { \textcolor { module_name } { enum } \textcolor { OrangeRed } { ext } } \group_end: } % Custom \meta[...]{...}, \marg[...]{...} and \oarg[...]{...} with color \NewDocumentCommand \mymeta { O{} m } { \__mydoc_meta_generic:Nnn \__mydoc_meta:n { #1 } { #2 } } \NewDocumentCommand \mymarg { O{} m } { \__mydoc_meta_generic:Nnn \__mydoc_marg:n { #1 } { #2 } } \NewDocumentCommand \myoarg { O{} m } { \__mydoc_meta_generic:Nnn \__mydoc_oarg:n { #1 } { #2 } } \NewDocumentCommand \myparg { O{} m } { \__mydoc_meta_generic:Nnn \__mydoc_parg:n { #1 } { #2 } } % Variables and keys \tl_new:N \l_userdoc_meta_font_tl \keys_define:nn { userdoc / mymeta } { type .choice:, type / tt .code:n = \tl_set:Nn \l_userdoc_meta_font_tl { \ttfamily }, type / rm .code:n = \tl_set:Nn \l_userdoc_meta_font_tl { \rmfamily }, type .initial:n = tt, cf .tl_set:N = \l_userdoc_meta_color_tl, cf .initial:n = keyname, ac .tl_set:N = \l_userdoc_meta_anglecolor_tl, ac .initial:n = lightgray, sbc .tl_set:N = \l_userdoc_meta_brackcolor_tl, sbc .initial:n = gray, cbc .tl_set:N = \l_userdoc_meta_bracecolor_tl, cbc .initial:n = gray, pbc .tl_set:N = \l_userdoc_meta_parencolor_tl, pbc .initial:n = gray, } % Internal commands \cs_new_protected:Npn \__mydoc_meta_generic:Nnn #1 #2 #3 { \group_begin: \keys_set:nn { userdoc / mymeta } { #2 } \color{ \l_userdoc_meta_color_tl } \l_userdoc_meta_font_tl #1 { #3 } % #1 is \__mydoc_meta:n, \__mydoc_marg:n, \__mydoc_oarg:n or \__mydoc_parg:n \group_end: } \cs_new_protected:Npn \__mydoc_meta:n #1 { \__mydoc_meta_angle:n { \textlangle } \__mydoc_meta_meta:n { #1 } \__mydoc_meta_angle:n { \textrangle } } \cs_new_protected:Npn \__mydoc_marg:n #1 { \__mydoc_meta_brace:n { \textbraceleft } \__mydoc_meta:n { #1 } \__mydoc_meta_brace:n { \textbraceright } } \cs_new_protected:Npn \__mydoc_oarg:n #1 { \__mydoc_meta_brack:n { [ } \__mydoc_meta:n { #1 } \__mydoc_meta_brack:n { ] } } \cs_new_protected:Npn \__mydoc_parg:n #1 { \__mydoc_meta_brace:n { ( } \__mydoc_meta:n { #1 } \__mydoc_meta_brace:n { ) } } \cs_new_protected:Npn \__mydoc_meta_meta:n #1 { \textnormal{\textit{#1}} } \cs_new_protected:Npn \__mydoc_meta_angle:n #1 { \group_begin: \fontfamily{lmrotf}\fontshape{n}\selectfont \textcolor{\l_userdoc_meta_anglecolor_tl}{#1} \group_end: } \cs_new_protected:Npn \__mydoc_meta_brace:n #1 { \group_begin: \color{\l_userdoc_meta_bracecolor_tl} #1 \group_end: } \cs_new_protected:Npn \__mydoc_meta_brack:n #1 { \textcolor{\l_userdoc_meta_brackcolor_tl}{#1} } % Color the characters matched by the regex #2 in the token list #1 with the % palette color #3 (only the first match, or every match) \cs_new_protected:Npn \__mydoc_color_once:Nnn #1 #2 #3 { \regex_replace_once:nnN { ( #2 ) } { \c{textcolor}\cB\{#3\cE\}\cB\{\1\cE\} } #1 } \cs_new_protected:Npn \__mydoc_color_all:Nnn #1 #2 #3 { \regex_replace_all:nnN { ( #2 ) } { \c{textcolor}\cB\{#3\cE\}\cB\{\1\cE\} } #1 } % Rewrite \textborn | textasteriskcentered \DeclareTextSymbol{\textbornstd}{TS1}{98} \UndeclareTextCommand{\textborn}{TS1} \makeatletter \DeclareTextCommandDefault{\textbornstd}{\tc@check@symbol2\textbornstd} \makeatother \DeclareRobustCommand{\textborn}{{\fontfamily{lmr}\selectfont\textbornstd}} \newcommand{\oldtextasteriskcentered}{{\fontfamily{lmr}\selectfont\textasteriskcentered}} % \envexamp{m} \newsavebox{\boxexaenv} \tl_new:N \l_tempc_tl \NewDocumentCommand \envexamp { m } { \tl_set:Nn \l_tempc_tl { #1 } \__mydoc_color_once:Nnn \l_tempc_tl { \* } { star } \begin{lrbox}{\boxexaenv}% \begin{minipage}[t]{3\marginparwidth}% \raggedright\ttfamily\small \textcolor{gray}{\textbackslash begin\{\textcolor{module_name}{{\tl_use:N \l_tempc_tl}}\}\myoarg [type=tt,sbc=gray,ac=lightgray,cf=keyname]{keyval~list}}\par% \hspace{0.25cm}\ics*{item}\space\mymeta[ac=lightgray,cf=gray]{item~content}\par% \hspace{0.25cm}\ics*{item}\space\myoarg[sbc=gray,ac=lightgray,cf=keyname]{custom}\space\mymeta[ac=lightgray,cf=gray]{item~content}\par \hspace{0.25cm}\ics*{item*}\myoarg[sbc=gray,ac=lightgray,cf=keyname]{symbol}\myoarg[sbc=gray,ac=lightgray,cf=keyname]{offset}\space\mymeta[ac=lightgray,cf=gray]{item~content}\par \textcolor{gray}{\textbackslash end\{{\textcolor{module_name}{{\tl_use:N \l_tempc_tl}}}\}}\par \end{minipage}% \end{lrbox}% \usebox{\boxexaenv} } % \cmdexamp{o m o m o} \tl_new:N \l_tempd_tl \NewDocumentCommand \cmdexamp { o m o m o } { \group_begin: \small\ttfamily \textcolor{module_name}{\textbackslash#2} \IfValueT{#1}{ \textcolor{star}{#1} } \IfValueT{#3} { \tl_set:Nn \l_tempd_tl { #3 } \regex_replace_once:nnN { (\*) } { \c{texttt}\cB\{\c{textcolor}\cB\{star\cE\}\cB\{\1\cE\} \cE\} } \l_tempd_tl \myoarg[type=tt,sbc=gray,ac=lightgray,cf=keyname]{\tl_use:N \l_tempd_tl} } \IfValueTF{#5} { \mymeta[ac=gray,type=tt,cf=star]{#5}% \mymeta[type=tt,ac=gray,cf=keyname]{#4} \mymeta[ac=gray,type=tt,cf=star]{#5}% } { \mymarg[type=tt,cbc=gray,ac=lightgray,cf=keyname]{#4} } \par \group_end: } % Index entries for the keys. #1 is the target: 'env' (environments in % general), a name ending in '*' (an environment such as anskey*) or the % name of a command (printed with a backslash). #2 is the key. \tl_new:N \l__mydoc_key_target_tl \cs_new_protected:Npn \__mydoc_key_index:nn #1 #2 { \str_case:nnF {#1} { { env } { \__mydoc_sort_index:nn { Keys } { Keys~for~environments~provided~by~\pkglogo :> \texttt {#2} } } } { \tl_set:Nn \l__mydoc_key_target_tl {#1} \tl_if_in:NnTF \l__mydoc_key_target_tl { * } { \__mydoc_color_once:Nnn \l__mydoc_key_target_tl { \* } { star } \__mydoc_sort_index:nn { Keys } { Keys~for~\texttt { \tl_use:N \l__mydoc_key_target_tl }~ provided~by~\pkglogo :> \texttt {#2} } } { \__mydoc_sort_index:nn { Keys } { Keys~for~\texttt { \textbackslash #1 }~provided~by~\pkglogo :> \texttt {#2} } } } } \cs_new_protected:Npn \__mydoc_key_index_list:nn #1 #2 { \clist_map_inline:nn {#1} { \__mydoc_key_index:nn {##1} {#2} } } % Key line: name hanging in the margin, value, and default % \__mydoc_key_line:Nnnn {boolean} {key} {value} {default} \cs_new_protected:Npn \__mydoc_key_line:Nnnn #1 #2 #3 #4 { \group_begin: \noindent \mode_leave_vertical: \hbox_to_wd:nn { -\marginparsep } { \hss \textcolor { keyname } { \small \ttfamily {#2} } } \IfBooleanTF {#1} { \hphantom { \textcolor { white } { \, \bfseries \texttt{=} } \, {} } \mymeta [ type=tt, cbc=gray, ac=lightgray, cf=lightgray ] { \small {#3} } } { \textcolor { gray } { \, \bfseries \texttt{=} } \, {} \mymarg [ type=tt, cbc=gray, ac=lightgray, cf=keyname ] { \small {#3} } } \hfill \textcolor { gray } { \small \textsf { default } :~ \emph{#4} } \par \group_end: } % \keyexampcmd{s m m m o}, the optional #5 is a clist of targets for the % index (env, anskey*, a command name); without it there is no index entry \NewDocumentCommand \keyexampcmd { s m m m o } { \__mydoc_key_line:Nnnn #1 {#2} {#3} {#4} \IfValueT {#5} { \__mydoc_key_index_list:nn {#5} {#2} } } % \mykey{o m}, the optional #1 is a clist of targets for the index \NewDocumentCommand \mykey { o m } { \group_begin: \tl_set:Nn \l_tmpa_tl { #2 } \__mydoc_color_once:Nnn \l_tmpa_tl { \* } { star } \textcolor { keyname } { \ttfamily \tl_use:N \l_tmpa_tl } \IfValueT {#1} { \__mydoc_key_index_list:nn {#1} { \tl_use:N \l_tmpa_tl } } \group_end: } % \mypkg{s O{} m}, use the optional argument [no-index] to skip the index \NewDocumentCommand \mypkg { s O{} m } { \group_begin: \IfBooleanTF {#1} { \pkglogo } { \textcolor { pkgname } { \textbf { \texttt {#3} } } } \str_if_eq:nnF {#2} { no-index } { \__mydoc_sort_index:nn { packages } { Packages~:>~\texttt {#3} } } \group_end: } % \myclass{m} \NewDocumentCommand \myclass { m } { \mbox { \textcolor { clsname } { \textbf { \texttt {#1} } } } \__mydoc_sort_index:nn { class } { Document~class~:>~\texttt {#1} } } % \myenv{s O{} m}, use the optional argument [no-index] to skip the index \NewDocumentCommand \myenv { s O{} m } { \IfBooleanTF {#1} { \tl_set:Nn \l_tmpa_tl { #3 } \__mydoc_color_once:Nnn \l_tmpa_tl { \* } { star } \textcolor { module_name } { \ttfamily { \tl_use:N \l_tmpa_tl } } \str_if_eq:nnF {#2} { no-index } { \__mydoc_sort_index:nn { environment } { Environments~provided~by~\pkglogo :> \texttt { \tl_use:N \l_tmpa_tl } } } } { \textcolor { pkgname } { \ttfamily {#3} } \str_if_eq:nnF {#2} { no-index } { \__mydoc_sort_index:nn { environment } { Environments~:>~\texttt {#3} } } } } % \ics{s m} \NewDocumentCommand \ics { s m } { \IfBooleanTF {#1} { \tl_set:Nn \l_tmpa_tl { #2 } \__mydoc_color_once:Nnn \l_tmpa_tl { \* } { star } \__mydoc_color_once:Nnn \l_tmpa_tl { ! } { star } \textcolor { module_name } { \ttfamily \textbackslash { \tl_use:N \l_tmpa_tl } } \__mydoc_sort_index:nn { Commands } { Commands~provided~by~\pkglogo :> \texttt { \textbackslash #2 } } } { \textcolor { latex_cmd } { \ttfamily \textbackslash {#2} } \__mydoc_sort_index:nn {#2} { \texttt { \textbackslash #2 } } } } % \icounter{O{} m}, use the optional argument [no-index] to skip the index \NewDocumentCommand \icounter { O{} m } { \textcolor { keyname } { \ttfamily #2 } \str_if_eq:nnF {#1} { no-index } { \__mydoc_sort_index:nn { Counters } { Counters~defined~by~\pkglogo :> \texttt {#2} } } } % \idimen{O{} m}, use the optional argument [no-index] to skip the index \NewDocumentCommand \idimen { O{} m } { \textcolor { module_name } { \ttfamily \textbackslash #2 } \str_if_eq:nnF {#1} { no-index } { \__mydoc_sort_index:nn {#2} { \texttt { \textbackslash #2 } } \__mydoc_sort_index:nn { Dimension } { Dimension~defined~by~\pkglogo :> \texttt { \textbackslash #2 } } } } % \ilabel{s O{} m}, use the optional argument [no-index] to skip the index \NewDocumentCommand \ilabel { s O{} m } { \tl_set:Nn \l_tmpb_tl { #3 } \tl_remove_once:Nn \l_tmpb_tl { . } \tl_remove_once:Nn \l_tmpb_tl { ) } \tl_remove_once:Nn \l_tmpb_tl { ( } \str_if_eq:nnF {#2} { no-index } { \__mydoc_sort_index:nn { Labels } { Labels~provided~by~\pkglogo :> \texttt { \textbackslash \tl_use:N \l_tmpb_tl } } } \tl_set:Nn \l_tmpa_tl { #3 } \__mydoc_color_once:Nnn \l_tmpa_tl { \* } { star } \__mydoc_color_once:Nnn \l_tmpa_tl { \. } { star } \__mydoc_color_once:Nnn \l_tmpa_tl { \( } { star } \__mydoc_color_once:Nnn \l_tmpa_tl { \) } { star } \tl_put_left:Nn \l_tmpa_tl { \textbackslash } \IfBooleanT {#1} { \tl_put_left:Nn \l_tmpa_tl { \textcolor { star } { ( } } } \textcolor { keyname } { \ttfamily \tl_use:N \l_tmpa_tl } } % \mydim{m} \NewDocumentCommand \mydim { m } { \group_begin: \tl_set:Nn \l_tmpa_tl { #1 } \__mydoc_color_all:Nnn \l_tmpa_tl { \d } { number } \__mydoc_color_all:Nnn \l_tmpa_tl { \. } { number } \textcolor { unit } { \ttfamily \tl_use:N \l_tmpa_tl } \group_end: } % \myfile{m} \NewDocumentCommand \myfile { m } { \group_begin: \tl_set:Nn \l_tmpa_tl { #1 } \__mydoc_color_all:Nnn \l_tmpa_tl { \d } { number } \__mydoc_color_all:Nnn \l_tmpa_tl { \. } { star } \textcolor { filename } { \ttfamily \tl_use:N \l_tmpa_tl } \group_end: } % \myattachfile{s m}, the star version attaches only the \texttt{.tex} file \NewDocumentCommand \myattachfile { s m } { \group_begin: \IfBooleanTF { #1 } { \IfFileExists { #2.tex } { Source~file~ \textattachfile[color=newlinkcolor,print=false]{#2.tex}{\faFile*[regular]}. } { } } { \IfFileExists { #2.pdf } { Source~file~ \textattachfile[color=newlinkcolor,print=false]{#2.tex}{\faFile*[regular]}~ and~\emph{tagged}~\texttt{PDF}~ \textattachfile[color=newlinkcolor,print=false]{#2.pdf}{\faFilePdf[regular]}. } { } } \group_end: } % Icons in the margin for the environment important (internal use) \cs_new_protected:Npn \__mydoc_margin_icon:n #1 { \par \mode_leave_vertical: \skip_horizontal:n { -0.5 \marginparsep } \hbox_overlap_left:n { \hbox_to_wd:nn { \marginparsep } { \hss \textcolor { module_at } { #1 } % privatefun } } \skip_horizontal:n { 0.5 \marginparsep } } % Space before the function environment \hook_gput_code:nnn { env/function/before } { mydoc } { \vspace* { -\baselineskip } } % Environment for notes \NewDocumentEnvironment { important } { s } { \par\addvspace { \smallskipamount } \small\sffamily \IfBooleanTF { #1 } { \__mydoc_margin_icon:n { \footnotesize \faIcon { bomb } } } { \__mydoc_margin_icon:n { \scriptsize \reflectbox { \faIcon { tag } } } } \ignorespaces } { } % Parse and format an e-mail address \seq_new:N \l__mydoc_email_seq \cs_new_protected:Npn \__mydoc_format_email:n #1 { \seq_set_split:Nnn \l__mydoc_email_seq { @ } { #1 } \href { mailto:#1 } { \ttfamily \seq_item:Nn \l__mydoc_email_seq { 1 } \textcolor { arroba } { \footnotesize @ } \seq_item:Nn \l__mydoc_email_seq { 2 } } } \NewDocumentCommand \email { m } { \__mydoc_format_email:n { #1 } } % Don't copy numbers in code example \newcommand*{\noaccsupp}[1] { \__mylhmc_luafun_actual_text_begin: #1 \__mylhmc_luafun_actual_text_end: } \ExplSyntaxOff % Create a language for documentation \lstdefinelanguage{enumext-doc}{ texcsstyle = *,% escapechar =`,% extendedchars = true,% keepspaces = true,% stringstyle = {\color{red}},% basicstyle = \small\ttfamily,% \small alsoletter = {-,.},% @, % comments morecomment = [l]{\%},% commentstyle = \ttfamily\small\color{comment},% % Important \documentclass \begin \end \makeatletter \NewDocumentCommand keywordstyle = [1]{\bfseries\color{structure}},% keywords = [1]{begin, end, document, documentclass, makeatletter, makeatother, NewDocumentCommand,% RenewDocumentCommand, NewCommandCopy},% % Other words \usepackage keywordstyle = [2]{\color{pkgstruct}},% keywords = [2]{usepackage},% % Other words 3 tagpdf keywordstyle = [3]{\color{mathtag}},% keywords = [3]{DocumentMetadata, IfDocumentMetadataTF, IfDocumentMetadataF, SuspendTagging, ResumeTagging},% % Other words 4 (LaTeX2e) keywordstyle = [4]{\color{latex_cmd}},% keywords = [4]{section, input, listparindent, linewidth, emph, textbf, makesavenoteenv, makelabel,% columnseprule, footnote, footnotemark, footnotetext, raggedcolumns, hspace, parindent,% removelastskip, subsection, list, endlist, leftmargin, itemindent, bfseries, endminipage,% minipage, parskip, raisebox, strut, smash, labelwidth, labelsep, labelindent, label,% topsep, parsep, includegraphics, itemize, description, multicolsep, leftmargini,% leftmarginii, hfill, small, vspace, par, parbox, value, noindent, makebox, textcolor,% leftmarginiii, leftmarginiv, itemsep, strutbox, raggedright, cs_new_eq, fbox, addvspace,% Alph, alph, arabic, Roman, roman, partopsep, baselineskip, mode_leave_vertical, textborn,% textbullet, textendash, textasteriskcentered, textperiodcentered, raggedleft,% peek_remove_spaces, skip_horizontal, triangleright, diamond, circ, parleft, star,% centering, ast, hyperlink, hypertarget, newtheorem, counterwithin, aux_i, aux_ii, aux_iii,% exp_args, if@noitemarg, if, if@hyper@item, hyper, noitemarg, regex_match, regex_if_match,% skip_vertical, obeyedline, tl_replace_all, mbox, tl_rescan, tl_set_rescan, tex_scantokens,% setcounter, .code, .meta, marginpar, c_zero_skip, tl_retokenize, keys_define, exp_after,% settowidth, dimeval, dimexpr, IfBooleanTF, IfHyperBoolean, newlength, setlength, pagestyle,% definecolor, chapter, columnbreak, columnsep, rightmargin, phantomsection,% check, save, testSE, release},% % Other words 5 (package name) keywordstyle = [5]{\bfseries\color{pkgname}},% keywords = [5]{footnotehyper, l3build},% % Reserved words 6 (document class) keywordstyle = [6]{\bfseries\color{clsname}},% keywords = [6]{article},% % Reserved words 7 (enumext cmd) keywordstyle = [7]{\color{module_name}},% keywords = [7]{enumext, keyans, keyanspic, getkeyans, anskey, anspic, item, anskey*, itemwidth,% enumextmeta, setenumext, printkeyans, miniright, labelbx, mywrap, descitemwd, theenumXi,% theenumXii, theenumXiii, setenumextmeta, foreachkeyans, theenumX, theenumXiv, theenumXv,% theenumXvii, theenumXviii, resetenumext},% % Reserved words 8 (keyname) KEYS and counters keywordstyle = [8]{\color{keyname}},% keywords = [8]{save-ans, wrap-ans, save-ref, show-pos, show-ans, columns, list-offset, enumXi, enumX,% nosep, before, after, start, right, item-sym, item-sep, hyperfootnotes, item-star, scale,% wrap-label, font, first, widest, mini-env, list-indent, no-store, save-key, save-sep, ref,% store-env, print-env, write-out, force-eol, write-env, overwrite, unknown, base-fix,% midsep, wrapper, label-pos, label-sep, layout-sty, layout-sep, layout-top, lang, tagging,% pdfversion, pdfstandard, testphase, alt, mark-sep, wrap-ans*, mark-ans, beginpenalty,% midpenalty, endpenalty, reset, resume, resume*, reset*, item-break},% % Reserved words 9 (values) keywordstyle = [9]{\color{ltcmd_arg}},% keywords = [9]{m, s, M, VIII, viii, v, E, t, l, A, XXIII, true, false, test, sample, above, below, ua-2,% phase-III, en-US, math, title, table, firstaid, on, Verbatim, env, myseq, the, red, blue,% gray, pt, em},% % Reserved words 10 (signature) keywordstyle = [10]{\color{sigargs}},% keywords = [10]{J, D, N, NN, Nee, Nnn, nn, Ne, w, n, wN},% % Reserved words 12 (plain TeX or internal) keywordstyle = [12]{\color{danger}},% keywords = [12]{let, verb, def, prevdepth, glue, if@minipage, splittopskip, showboxdepth, topskip,% showoutput, nointerlineskip, ignorespaces, unskip, unkern, lastnodetype, rightskip,% @rightskip, flushglue, @flushglue, hbadness, hss, scantokens, beginparpenalty, itempenalty,% endparpenalty, lowpenalty, vskip, kern, lineskip, lastskip, lastkern,% parshape, fontcharht, inputlineno},% % literate literate =*{\{}{{{\color{brace}{\char`\{}}}}{1} {\}}{{{\color{brace}{\char`\}}}}}{1} {\|}{{{\color{gray}{\char`\|}}}}{1} {\$}{{{\color{math}{\char`\$}}}}{1} {\#}{{{\color{argument}{\char`\#}}}}{1} {(}{{\textcolor{gray}{(}}}{1} {)}{{\textcolor{gray}{)}}}{1} {[}{{\textcolor{bracket}{[}}}{1} {]}{{\textcolor{bracket}{]}}}{1} {,}{{\textcolor{gray}{,}}}{1} {;}{{\textcolor{gray}{;}}}{1} {.}{{\textcolor{signature}{.}}}{1} {:}{{\textcolor{signature}{:}}}{1} {`}{{\textcolor{backtick}{\textasciigrave}}}{1} {\&}{{\textcolor{gray}{\&}}}{1} {>}{{\textcolor{quote}{\guillemotright}}}{1} {<}{{\textcolor{quote}{\guillemotleft}}}{1} {*}{{\textcolor{star}{*}}}{1} {"}{{\textcolor{quote}{"}}}{1} {!}{{\textcolor{star}{!}}}{1} {@}{{\textcolor{arroba}{@}}}{1}% {\^}{{\textcolor{keyname}{\textasciicircum}}}{1} {0}{{\textcolor{argnum}{0}}}{1} {1}{{\textcolor{argnum}{1}}}{1} {2}{{\textcolor{argnum}{2}}}{1} {3}{{\textcolor{argnum}{3}}}{1} {4}{{\textcolor{argnum}{4}}}{1} {5}{{\textcolor{argnum}{5}}}{1} {6}{{\textcolor{argnum}{6}}}{1} {7}{{\textcolor{argnum}{7}}}{1} {8}{{\textcolor{argnum}{8}}}{1} {9}{{\textcolor{argnum}{9}}}{1} {.0}{{\textcolor{argnum}{.0}}}{2}% Following is to ensure that only periods {.1}{{\textcolor{argnum}{.1}}}{2}% followed by a digit are changed. {.2}{{\textcolor{argnum}{.2}}}{2} {.3}{{\textcolor{argnum}{.3}}}{2} {.4}{{\textcolor{argnum}{.4}}}{2} {.5}{{\textcolor{argnum}{.5}}}{2} {.6}{{\textcolor{argnum}{.6}}}{2} {.7}{{\textcolor{argnum}{.7}}}{2} {.8}{{\textcolor{argnum}{.8}}}{2} {.9}{{\textcolor{argnum}{.9}}}{2} {=}{{\textcolor{compare}{=}}}{1},% }[keywords,tex,comments,strings]% end language % \begin{examplecode}[key=val]...\end{examplecode} \lstnewenvironment{examplecode}[1][]{% \lstset{ language = enumext-doc,% stringstyle = {\color{red}},% basicstyle = \ttfamily\small,% columns = fullflexible,% fontadjust = true,% aboveskip = 8pt,% belowskip = 5pt,% rulecolor = \color{gray!50},% framesep = \fboxsep,% framerule = \fboxrule,% xleftmargin = \dimexpr\fboxsep+\fboxrule\relax,% xrightmargin= \dimexpr\fboxsep+\fboxrule\relax,% #1,% }% close lstset }{\vspace{-\parskip}}% close examplecode % \lstinline[style=inline]|...| \lstdefinestyle{inline} { language = enumext-doc,% upquote = true,% numbersep = 1em,% escapechar =`,% basicstyle =\ttfamily,%\small numberstyle = \tiny\color{lightgray}\noaccsupp,% literate =*{\%}{{\textcolor{percent}{\%}}}{1} {i}{{\textcolor{keyname}{i}}}{1} {ii}{{\textcolor{keyname}{ii}}}{2} {iii}{{\textcolor{keyname}{iii}}}{3} {iv}{{\textcolor{keyname}{iv}}}{2} {v}{{\textcolor{keyname}{v}}}{1} {vi}{{\textcolor{keyname}{vi}}}{1} } % Set default \lstinline style \lstset{style=inline} % Configuration titleps and titlesec \settitlemarks{section} \renewpagestyle{plain}[\color{keyname}\small\sffamily]{% \setfoot{\rlap{\hskip\dimexpr-\oddsidemargin-1in\relax% \parbox{1.93\paperwidth}{\hfil\thepage\,/\,\pageref{LastPage}}}}% {}% {}% } \newpagestyle{myheader}[\color{keyname}\small\sffamily]{% \renewcommand\makeheadrule{% \rlap{\hskip\dimexpr-\oddsidemargin-1in\relax \color{rulecolor}\rule[0.3cm]{\paperwidth}{0.7cm}}\hss } \setfoot{\rlap{\hskip\dimexpr-\oddsidemargin-1in\relax% \parbox{1.93\paperwidth}{\hfil\thepage\,/\,\pageref{LastPage}}}}% {\parbox{\textwidth}{\raggedright \textcolor{gray}{\raisebox{-1pt}{\textcopyright}{}2024--2026 by Pablo González L}}}% {}% \sethead{\llap{\raisebox{0.55cm}{\parbox{\dimexpr\oddsidemargin+1in\relax}{\makebox[0pt][l]{\hspace{15pt}\pkglogo\space\fileversion}}}}} {\raisebox{0.55cm}{\parbox{\textwidth}{\hspace*{-\oddsidemargin}\centering\small\S.\thesection\space\sectiontitle}}}% {}% } \titlecontents{section}[0mm]{}% {\bfseries\contentspush{\makebox[5mm][l]{\thecontentslabel\hfill}}}% {\hspace*{-5mm}}% numberless {\hspace{0.25em}\titlerule*[6pt]{.}\contentspage}% \titlecontents{subsection}[5mm]{}% {\contentspush{\makebox[6mm][l]{\thecontentslabel\hfill}}} {\hspace*{-11mm}}% numberless {\hspace{0.25em}\titlerule*[6pt]{.}\contentspage}% \titlecontents{subsubsection}[11mm]{}% {\contentspush{\makebox[8mm][l]{\thecontentslabel\hfill}}} {\hspace*{-19mm}}% numberless {\hspace{0.25em}\titlerule*[6pt]{.}\contentspage}% % Table of contents \ExplSyntaxOn \cs_new_eq:Nc \__mydoc_mkboth:nn { @mkboth } \cs_new_eq:Nc \__mydoc_starttoc:n { @starttoc } \RenewDocumentCommand \tableofcontents { } { \group_begin: % Restore the l3doc \parskip locally (only for the TOC) \skip_set:Nn \parskip { 0pt~plus~3pt~minus~0pt } \section* { \contentsname \quad { \color { gray } \leaders \hrule height 5pt depth -4.4pt \hfill } } \__mydoc_mkboth:nn { \text_uppercase:n { \contentsname } } { \text_uppercase:n { \contentsname } } \vspace* { -14pt } \dim_set:Nn \columnsep { 10pt } \begin{multicols}{2} \__mydoc_starttoc:n { toc } \end{multicols} \vspace* { -3pt } { \color { gray } \hrule height 0.6pt } \vspace* { 5pt } \group_end: } % \thanks \cs_new:Npn \__mydoc_fnsymbol:n #1 { \ensuremath { \int_case:nnF { #1 } { { 0 } { } { 1 } { \textcolor { module_name } { * } } { 2 } { \textcolor { module_name } { \dagger } } { 3 } { \ddagger } { 4 } { \mathsection } { 5 } { \mathparagraph } { 6 } { \| } { 7 } { ** } { 8 } { \dagger \dagger } { 9 } { \ddagger \ddagger } } { \use:c { @ctrerr } } } } \hook_gput_code:nnn { begindocument } { enumext } { \cs_set_eq:cN { @fnsymbol } \__mydoc_fnsymbol:n } \ExplSyntaxOff % \usepackage{lua-visual-debug} \usepackage[font=small,skip=2pt]{caption} % For input samples \usepackage{tikzducks,siunitx,amssymb} \sisetup{output-decimal-marker={,}} \newcommand*{\myCircled}[1]{% \begin{tikzpicture}[baseline=(number.base)] \node[circle, draw=green!10!gray, inner sep=1pt, fill=blue!30!green!10] (number) {#1}; \end{tikzpicture}% } \usetikzlibrary{shapes.geometric} \newcommand*{\mySquared}[1]{% \begin{tikzpicture}[baseline=(number.base),square/.style={regular polygon,regular polygon sides=4}] \node[square, rounded corners=1pt, inner sep=1pt, draw=none, fill=gray!40] (number) {\makebox[\height]{#1}}; \end{tikzpicture}% } % For SAT sample \newsavebox{\satbox} \sbox\satbox{\small\textbf{67}}% \NewDocumentCommand \stylesat { m } {% \setlength{\fboxsep}{2pt}% \raisebox{2\fboxsep}{% \noindent\colorbox{black}{\textcolor{white}{\makebox[\dimeval{\labelwidth-2\fboxsep}][c]{\small\textbf{\vphantom{67}#1}}}}% \colorbox{lightgray}{\phantom{\rule[-\dp\satbox]{\dimeval{\linewidth-2\fboxsep}}{\dimeval{\dp\satbox+\ht\satbox}}}}}% } % For non-numbered list samples, need ´%´ at end (prevent wrong unwanted spaces) \NewDocumentCommand \labelbx { s +m } {% \IfBooleanTF{#1} {\strut\smash{\parbox[t]{\labelwidth}{\raggedright{#2}}}}% {\strut\smash{\parbox[t]{\labelwidth}{\raggedleft{#2}}}}% } % For azetina sample \newlength{\itemwd} \settowidth{\itemwd}{\bfseries 10.} % max width \NewDocumentCommand \rating { }{8.5a, KSC} \ExplSyntaxOn \bool_new:N \l_azetina_rating_bool \NewDocumentCommand \showrating { m } { \str_case:nn {#1} { { true } { \bool_set_true:N \l_azetina_rating_bool \setenumext{show-ans=true,save-sep={ ~ }} } { false } { \bool_set_false:N \l_azetina_rating_bool \setenumext{show-ans=false,save-sep={ ~ }} } } } \NewDocumentCommand \myans { m +m } { \bool_if:NTF \l_azetina_rating_bool { \item*[(#1)] \textcolor{red}{#2} } { \item*[(#1)] \textcolor{black}{#2} } } \NewDocumentCommand \azwrapp { m } { \bool_if:NTF \l_azetina_rating_bool { \makebox[\dim_eval:n{\marginparwidth}][r] { \textcolor{red}{\bfseries\footnotesize\rating} } \hspace{\marginparsep}\textbf{#1} } { \makebox[\dim_eval:n{\marginparwidth+\marginparsep}][l]{ }\textbf{#1} } } \ExplSyntaxOff \setenumextmeta[1]{azetinasty}{label={\arabic*.},labelwidth={\marginparwidth+\marginparsep+\itemwd},list-offset={-\marginparwidth-\marginparsep},} \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % % \title{ % \scalebox{2.67}{\pkglogo}\\[-10pt] % {\large\textcolor{gray}{\fetamontotf{enumerate exercise sheets}}}\\[0pt] % \fileversion \quad \filedate\thanks{ % This file describes a documentation for \fileversion, last revised % \filedate.}\\[25pt] % \author{ % \large % \raisebox{-1pt}{\textcopyright{}2024--2026 by Pablo González L}\thanks{ % E-mail: \textcolor{OrangeRed}{\textsf{\guillemotleft}}\email{pablgonz@educarchile.cl}\textcolor{OrangeRed}{\textsf{\guillemotright}}. % }% % } % \small % \textsc{ctan}: \url{https://www.ctan.org/pkg/enumext}\\ % \textcolor{gray}{\scriptsize\faIcon[regular]{github}}\,\,\,\url{https://github.com/pablgonz/enumext} % \vspace*{-2cm} % } % \date{} % \maketitle % % \begin{abstract} % This package provides enumerated list environments compatible % with \emph{tagging} \texttt{PDF} for creating \emph{\enquote{simple % exercise sheets}} along with \emph{\enquote{multiple choice questions}}, % storing the \emph{\enquote{answers}} to these in memory using \mypkg{multicol} % package. % \end{abstract} % % \tableofcontents % % \section*{Motivation and acknowledgments} % % Usually, it is enough to use the classic \myenv[no-index]{enumerate} environment to % generate \emph{\enquote{simple exercise sheets}} or % \emph{\enquote{multiple choice questions}}, the basic idea behind % \mypkg*[no-index]{enumext} is to cover three points: % % \begin{enumerate}[left=0pt, nosep,labelsep=5pt, label=\small\arabic*.,topsep=2pt] % \item To have a simple interface to be able to write \emph{\enquote{lists of % exercises}} with \emph{\enquote{answers}}. % \item To have a simple interface for writing \emph{\enquote{multiple choice % questions}}. % \item To have a simple interface for placing \emph{\enquote{columns}} % and \emph{\enquote{drawings}} or \emph{\enquote{tables}}. % \end{enumerate} % % This package would not be possible without Phelype Oleinik who has % collaborated and adapted a large part of the code and all % \hologo{LaTeX} team for their great work and to the different members % of the \href{https://tex.stackexchange.com}{TeX-SX} community who have % provided great answers and ideas. Here are notes on the main ones: % % \begin{enumerate}[left=0pt, labelsep=5pt, nosep, label=\small\arabic*.,topsep=2pt] % \item Answer given by Alan Munn in \href{https://tex.stackexchange.com/a/300418}{\textbackslash topsep, \textbackslash itemsep, \textbackslash partopsep, \textbackslash parsep - what do they each mean (and what about the bottom)?} % % \item Answer given by Enrico Gregorio in \href{https://tex.stackexchange.com/a/34172}{Understanding minipages - aligning at top} % % \item Answer given by Ulrich Diez in \href{https://tex.stackexchange.com/a/553839/7832}{Different mechanics of hyperlink vs. hyperref} % % \item Answer given by Enrico Gregorio in \href{https://tex.stackexchange.com/a/294460/7832}{Minipage and multicols, vertical alignment} % % \end{enumerate} % % \thispagestyle{plain} % % \section*{License and Requirements} % \label{sec:licence} % % Permission is granted to copy, distribute and/or modify this software under % the terms of the LaTeX Project Public License (lppl), version 1.3 or later % (\url{https://www.latex-project.org/lppl.txt}). % The software has the status \enquote{maintained}. % % The \mypkg*[no-index]{enumext} package loads and requires \mypkg[no-index]{multicol}\cite{multicol} % package, need to have a modern \hologo{TeX} distribution such as % \hologo{TeX} Live or \hologo{MiKTeX}. It has been tested with the standard % classes provided by \hologo{LaTeX}: \myclass{book}, \myclass{report}, % \myclass{article} and \myclass{letter} on \mydim{10pt}, \mydim{11pt} and \mydim{12pt}. % % \begin{important}* % The minimum requirement is \hologo{LaTeX} release 2026-11-01. % \end{important} % % \pagestyle{myheader} % % \section{Introduction} % % In the \hologo{LaTeX} world there are many useful packages and % classes for creating \emph{\enquote{lists of exercises}}, \emph{\enquote{worksheets}} or % \emph{\enquote{multiple choice questions}}, classes like \myclass{exam}\cite{exam} % and packages like \mypkg{xsim}\cite{xsim} do the job perfectly, but % they don't always fit the basic day to day needs. % % In the work of many teachers it is common to use % \emph{\enquote{simple exercise sheets}} also known as % \emph{\enquote{informal lists of exercises}}, for example: % % \begin{enumext}[save-ans=temp2,columns=2,nosep,save-ref=true]% % \item Factor $x^{2}-2x+1$ \anskey{$\left(x-1\right)^{2}$} % \item Factor $3x+3y+3z$ \anskey{$3(x+y+z)$} % \item True False % \begin{enumext}[nosep] % \item $\alpha > \delta$ \anskey{False} % \item \LaTeX2e\ is cool? \anskey{Very True!} % \end{enumext} % \item Related to Linux % \begin{enumext}[nosep] % \item You use Linux? \anskey{Yes} % \item Usually uses the package manager? \anskey{Yes, \texttt{dnf}} % \item Rate the following package and class % \begin{enumext}[nosep] % \item \texttt{xsim-exam} \anskey{doesn't exist for now :(} % \item \texttt{xsim} \anskey{very good} % \item \texttt{exsheets} \anskey{obsolete} % \end{enumext} % \end{enumext} % \end{enumext} % % Sometimes it is also useful to show the \emph{\enquote{answers}} % along with the questions: % % \begin{enumext}[save-ans=worksheet,mark-ans={\oldtextasteriskcentered},columns=2,show-ans=true,nosep,save-ref=true] % \item Factor $x^{2}-2x+1$ \anskey{$\left(x-1\right)^{2}$} % \item Factor $3x+3y+3z$ \anskey{$3(x+y+z)$} % \item True False % \begin{enumext}[nosep] % \item $\alpha > \delta$ \anskey{False} % \item \LaTeX2e\ is cool? \anskey{Very True!} % \end{enumext} % \item Related to Linux % \begin{enumext}[nosep] % \item You use Linux? \anskey{Yes} % \item Usually uses the package manager? \anskey{Yes, \texttt{dnf}} % \item Rate the following package and class % \begin{enumext}[nosep] % \item \texttt{xsim-exam} \anskey{doesn't exist for now :(} % \item \texttt{xsim} \anskey{very good} % \item \texttt{exsheets} \anskey{obsolete} % \end{enumext} % \end{enumext} % \end{enumext} % % Or to refer to a specific question and its % \emph{\enquote{answer}}, for example: % % The answer to \ref{worksheet:4} is \enquote{\getkeyans{worksheet:4}} % and the answer to \ref{worksheet:8} is \enquote{\getkeyans{worksheet:8}}. % % Or to print all the \emph{\enquote{answers}}: % % \printkeyans{worksheet} % % Another very common thing to use is \emph{\enquote{multiple choice % questions}}, for example: % % \begin{enumext}[save-ans=mytest,columns=2,nosep,save-ref=true,save-sep={\space}] % \item First type of questions % \begin{keyans}[columns=2,noitemsep] % \item value % \item*[$x=5$] correct % \item value % \item value % \end{keyans} % \item Second type of questions % \begin{enumext}[no-store,label=\Roman*.,noitemsep] % \item $2\alpha+2\delta=90^{\circ}$ % \item $\alpha=\delta$ % \item $\angle EDF=45^{\circ}$ % \end{enumext} % \begin{keyans}[columns=2,noitemsep] % \item I only % \item II only % \item I and II only % \item* I and III only % \item I, II, and III % \end{keyans} % \item* Third type of questions % \begin{enumext}[no-store,list-offset=0.5cm,label=(\arabic*),noitemsep] % \item $2\alpha+2\delta=90^{\circ}$ % \item $\angle EDF=45^{\circ}$ % \end{enumext} % \begin{keyans}[columns=2,noitemsep] % \item value % \item value % \item*[some note] value % \item value % \item value % \end{keyans} % % \item Question with image and label below: % % \begin{keyanspic}[label-pos=below, layout-sty={3,2}] % \anspic{\includegraphics[scale=0.15]{example-image-a}} % \anspic{\includegraphics[scale=0.15]{example-image-b}} % \anspic{\includegraphics[scale=0.15]{example-image-a}} % \anspic{\includegraphics[scale=0.15]{example-image-a}} % \anspic*[A duck]{\includegraphics[scale=0.30]{example-image-duck}} % \end{keyanspic} % % \item Question with image on right side: % % \begin{keyans}[mini-env=0.5\linewidth, columns=1,noitemsep] % \item value % \item value % \item value % \item*[\enquote{other note}] correct % \item value % \miniright % \includegraphics[scale=0.15]{example-image-b} % \end{keyans} % \end{enumext} % % Here the \mymeta{label} and a % \emph{\enquote{short note}} left as an explanation are stored, and then % printed: % % \printkeyans{mytest} % % The \mypkg*[no-index]{enumext} package was created and designed to meet these % small requirements in the creation of \emph{\enquote{simple % worksheets}} and \emph{\enquote{multiple choice questions}}. % % \begin{important}* % These \emph{\enquote{simple worksheets}} or \emph{\enquote{multiple % choice questions}} appear to be easy to obtain using a combination of % the \myenv[no-index]{enumerate}, \myenv[no-index]{minipage} and \myenv[no-index]{multicols} % environments, but like many things, what \emph{\enquote{looks % simple}} is not so simple. % \end{important} % % \subsection{Description and usage}\label{subsec:description} % % The \mypkg*[no-index]{enumext} package defines enumerated environments using the % \myenv[no-index]{list} environment provided by \hologo{LaTeX}\cite{latexref}, but % \emph{\enquote{does not redefine}} any internal commands associated with % it such as |\list|, |\endlist| or |\item| outside of the % \emph{\enquote{scope}} in which they are defined. % % \begin{important}* % This package is NOT intended to replace the \myenv[no-index]{enumerate} environment % nor replace the powerful \mypkg{enumitem}\cite{enumitem}, the approach % is intended to work without hindering either of them. % \end{important} % % This package can be used with |xelatex|, |lualatex|, |pdflatex| and % the classical |latex>dvips>ps2pdf| and is present in \hologo{TeX} Live and \hologo{MiKTeX}, % use the package manager to install. For manual installation, download % \href{http://mirrors.ctan.org/macros/latex/contrib/enumext.zip}{enumext.zip} % and unzip it, run \lstinline[language=enumext-doc,basicstyle=\ttfamily]+luatex enumext.ins+ % and move all files to appropriate locations, then run |mktexlsr|. To produce the documentation run % \lstinline[language=enumext-doc,basicstyle=\ttfamily]+arara enumext.dtx+. % % \iffalse %<*example> % \fi \begin{examplecode}[frame=single,language={}] enumext.sty > TDS:tex/latex/enumext/ enumext.pdf > TDS:doc/latex/enumext/ README.md > TDS:doc/latex/enumext/ enumext.dtx > TDS:source/latex/enumext/ enumext.ins > TDS:source/latex/enumext/ \end{examplecode} % \iffalse % % \fi % % The package is loaded in the usual way: % % \iffalse %<*example> % \fi \begin{examplecode}[frame=single] \usepackage{enumext} \end{examplecode} % \iffalse % % \fi % % \subsection{The concept of left margin}\label{subsec:left-margin} % % There is a direct relationship between the parameters |\leftmargin|, % |\itemindent|, |\labelwidth| and |\labelsep| plus an % \emph{\enquote{extra space}}, which makes it difficult to obtain the % desired \emph{horizontal spaces} in a \myenv[no-index]{list} environment. % Usually the \myenv[no-index]{list} should not go beyond the left margin of the % page, but since these four values are related, that causes a problem. % % The \mypkg[no-index]{enumitem}\cite{enumitem} package adds the |\labelindent| parameter to % solve some of these problems. A simplified representation of this in % the figure~\ref{fig:one}. % \setlength\intextsep{3pt} % \begin{figure}[ht] % \centering % \begin{tikzpicture}[line cap=round,line join=round,x=0.8cm,y=0.8cm,every node/.style={font=\footnotesize}] % \draw[<->,color=gray] (-0.5,6.175) --node[below,text=lightgray,font=\footnotesize\ttfamily]{margin page} (2,6.175); % \draw[line width=0.5pt,dash pattern=on 2pt off 2pt,color=gray] (2,4.85) -- (2,7.5); % \draw[<->,color=gray] (2.0,7.0) --node[above,text=blue!75]{\texttt{\textbackslash{}labelindent}} (4.5,7.0); % \draw[<->,color=gray] (4.5,7.0) --node[above,text=blue!75]{\texttt{\textbackslash{}labelwidth}} (7.5,7.0); % \draw[<->,color=gray] (7.5,7.0) --node[above,text=blue!75]{\texttt{\textbackslash{}labelsep}} (9.5,7.0); % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (4.5,6.5) rectangle (7.5,6.85);% labelwidth % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.5,6.5) rectangle (9.5,6.85);% labelsep % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (9.5,6.5) rectangle (15,6.85);% item width % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (9.5,6.0) rectangle (15,6.35); % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (9.5,5.5) rectangle (15,5.85); % \draw[<->,color=gray] (2.0,5.35) --node[below,text=blue!75]{\texttt{\textbackslash{}leftmargin}} (7.5,5.35); % \draw[<->,color=gray] (7.5,5.35) --node[below,text=blue!75]{\texttt{\textbackslash{}itemindent}} (9.5,5.35); % \end{tikzpicture} % \caption{Representation of horizontal lengths in \mypkg[no-index]{enumitem}.} % \label{fig:one} % \end{figure} % % The \mypkg*[no-index]{enumext} package does NOT provide a user interface to set the values for % |\leftmargin| and |\itemindent|, instead it provides the keys % \mykey{list-offset} and \mykey{list-indent} which internally set the % values for |\leftmargin| and |\itemindent|. The concepts of |\leftmargin| and |\itemindent| % are different in \mypkg*[no-index]{enumext}. The figure~\ref{fig:two} shows the visual representation of idea. % % \begin{figure}[ht] % \centering % \begin{tikzpicture}[line cap=round,line join=round,x=0.8cm,y=0.8cm,every node/.style={font=\footnotesize}] % \draw[<->,color=gray] (-0.5,6.175) --node[below,text=lightgray,font=\footnotesize\ttfamily]{margin page} (2,6.175); % \draw[line width=0.5pt,dash pattern=on 2pt off 2pt,color=gray] (2,4.85) -- (2,7.5); % \draw[<->,color=gray] (2.0,7.0) --node[above,text=keyname]{\vphantom{p}\texttt{list-offset}} (4.5,7.0); % \draw[<->,color=gray] (4.5,7.0) --node[above,text=blue!75]{\vphantom{p}\texttt{\textbackslash{}labelwidth}} (7.5,7.0); % \draw[<->,color=gray] (7.5,7.0) --node[above,text=blue!75]{\texttt{\textbackslash{}labelsep}} (9.5,7.0); % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (4.5,6.5) rectangle (7.5,6.85);% labelwidth % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.5,6.5) rectangle (9.5,6.85);% labelsep % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (9.5,6.5) rectangle (15,6.85);% item width % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (9.5,6.0) rectangle (15,6.35); % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (9.5,5.5) rectangle (15,5.85); % \draw[<->,color=gray] (4.5,5.35) --node[below,text=keyname]{\texttt{list-indent}} (9.5,5.35); % \end{tikzpicture} % \caption{Representation of horizontal lengths concept in \mypkg*[no-index]{enumext}.} % \label{fig:two} % \end{figure} % % In this way the number of parameters to % pass is reduced a \emph{little}. With the default values of keys \mykey{list-offset}, % \mykey{list-indent}, \mykey{labelwidth} and \mykey{labelsep} the lists % will have the (usually) expected output for \emph{\enquote{simple % worksheets}}. The figure~\ref{fig:three} shows the visual representation. % % \begin{figure}[ht] % \centering % \begin{tikzpicture}[line cap=round,line join=round,x=0.8cm,y=0.8cm,every node/.style={font=\footnotesize}] % \draw[<->,color=gray] (-0.5,6.175) --node[below,text=lightgray,font=\footnotesize\ttfamily]{margin page} (2,6.175); % \draw [line width=0.5pt,dash pattern=on 2pt off 2pt,color=gray] (2,4.85) -- (2,7.5); % \draw[<->,color=gray] (2.0,7.0) --node[above,text=keyname]{\vphantom{p}\texttt{labelwidth}} (5.0,7.0); % \draw[<->,color=gray] (5.0,7.0) --node[above,text=keyname]{\texttt{labelsep}} (7.0,7.0); % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (2.0,6.5) rectangle (5.0,6.85);% labelwidth % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (5.0,6.5) rectangle (7.0,6.85);% labelsep % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,6.5) rectangle (15,6.85);% item width % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,6.0) rectangle (15,6.35); % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,5.5) rectangle (15,5.85); % \draw[<->,color=gray] (2.0,5.35) --node[below,text=keyname]{\texttt{list-indent}} (7.0,5.35); % \end{tikzpicture} % \caption{Default horizontal lengths \mykey{list-offset}=\mydim{0pt}, \mykey{list-indent}=\ics{labelwidth}+\ics{labelsep} in \mypkg*[no-index]{enumext}.} % \label{fig:three} % \end{figure} % % \subsection{User interface}\label{subsec:user-interface} % % The user interface consists of two main list environments \myenv*[no-index]{enumext} % (vertical) and \myenv*[no-index]{enumext*} (horizontal), the environment \myenv*[no-index]{anskey*} and % the command |\anskey| to \emph{\enquote{store content}} and the % environments \myenv*[no-index]{keyans}, \myenv*[no-index]{keyans*} and \myenv*[no-index]{keyanspic} for multiple choice. % It also provides the commands |\getkeyans| to print individual % \emph{stored content}, |\printkeyans| to print all \emph{stored content}, % |\foreachkeyans| to print a range of \emph{stored content}, |\miniright| % for \myenv[no-index]{minipage}, |\setenumext| to config \myoarg{key \textnormal{\textcolor{gray}{=}} val}, % |\setenumextmeta| to add a \emph{\enquote{meta-key}} and |\resetenumext| % to reset counters. % % \subsubsection{Public counters} % % The package \mypkg*[no-index]{enumext} uses the \icounter{enumXi}, % \icounter{enumXii}, \icounter{enumXiii}, \icounter{enumXiv} counters % for the \emph{four} nesting levels of the \myenv*{enumext} environment, % the \icounter{enumXv} counter for the \myenv*[no-index]{keyans} environment, the % \icounter{enumXvi} counter for the \myenv*[no-index]{keyanspic} environment, % the counter \icounter{enumXvii} for \myenv*{enumext*} environment and % the counter \icounter{enumXviii} for \myenv*[no-index]{keyans*} environment. % % \begin{important}* % If any package defines these \emph{counters} or they are user-defined % in the document, the package will return a \emph{\enquote{fatal error}} % and abort the load. % \end{important} % % \subsubsection{Public dimension} % % The package \mypkg*[no-index]{enumext} only provides a \emph{single public dimension} % \idimen{itemwidth} and is intended for user convenience only and is NOT % for internal use as such. The dimension |\itemwidth| is a \emph{rigid length} % and contains the \emph{\enquote{width of the content}} of each |\item| % regardless of \mykey{labelwidth} and \mykey{labelsep}. % % \begin{important}* % If any package defines |\itemwidth| or the user defines |\itemwidth| % in the document, the package will overwrite it without warning. % \end{important} % % \subsubsection{Support for \pkg{multicol}} % % The package provides direct support for using the \mypkg[no-index]{multicol}\cite{multicol} % package. This allows for a two-column output as shown % in the figure~\ref{fig:fourth}. % % \begin{figure}[ht] % \centering % \begin{tikzpicture}[line cap=round,line join=round,x=0.8cm,y=0.8cm,every node/.style={font=\footnotesize}] % \draw[<->,color=gray] (2.0,7.0) --node[above,text=keyname]{\vphantom{p}\texttt{labelwidth}} (5.0,7.0); % \draw[<->,color=gray] (5.0,7.0) --node[above,text=keyname]{\texttt{labelsep}} (7.0,7.0); % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (2.0,6.5) rectangle (5.0,6.85);% labelwidth % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (5.0,6.5) rectangle (7.0,6.85);% labelsep % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,6.5) rectangle (17.5,6.85);% item width % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,5.5) rectangle (11.5,6.35) node[pos=.5,text=black]% % {\begin{tabular}{c} % \texttt{column one} \\ % \textcolor{blue}{\emph{nested items}} % \end{tabular}}; % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (13.5,5.5) rectangle (17.5,6.35) node[pos=.5,text=black]% % {\begin{tabular}{c} % \texttt{column two} \\ % \textcolor{blue}{\emph{nested items}} % \end{tabular}}; % \draw[<->,color=gray] (2.0,5.35) --node[below,text=keyname]{\texttt{list-indent}} (7.0,5.35); % \draw[<->,color=gray] (11.5,5.35) --node[below,text=keyname]% % {\begin{tabular}{c} % \texttt{column-sep} \\ % \textcolor{blue}{\texttt{\textbackslash{}columnbreak}} % \end{tabular}} % (13.5,5.35); % \end{tikzpicture} % \caption{Representation of the two column output for a nested level in \myenv*{enumext} environment.} % \label{fig:fourth} % \end{figure} % % The \emph{\enquote{non starred}} version of the \myenv[no-index]{multicols} % environment is always used together with the |\raggedcolumns| % command and is controlled by \mykey{columns} and \mykey{columns-sep} % keys. It can be used in all nesting levels of the % environment \myenv*[no-index]{enumext} and the environment \myenv*[no-index]{keyans} and can % together with the \mykey{mini-env} key. If you need to force a % start a new column |\columnbreak| must be used (\S\ref{subsec:keys-multicols}). % % \begin{important}* % The |\columnseprule| command is not available as a key and is set to % \emph{\enquote{zero}} for the inner levels and the \myenv*[no-index]{keyans} environment. If the value of % this is set inside the document, it will affect \emph{\enquote{all environments}} that % use the \mykey{columns} key. % \end{important} % % \subsubsection{Support for \env{minipage}} % % The package provides direct support for \myenv[no-index]{minipage} % environment, this allows you to obtain an output like the % one shown in figure~\ref{fig:five}. % % \begin{figure}[!htbp] % \centering % \begin{tikzpicture}[line cap=round,line join=round,x=0.8cm,y=0.8cm,every node/.style={font=\footnotesize}] % \draw[<->,color=gray] (2.0,7.0) --node[above,text=keyname]{\vphantom{p}\texttt{labelwidth}} (5.0,7.0); % \draw[<->,color=gray] (5.0,7.0) --node[above,text=keyname]{\texttt{labelsep}} (7.0,7.0); % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (2.0,6.5) rectangle (5.0,6.85);% labelwidth % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (5.0,6.5) rectangle (7.0,6.85);% labelsep % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,6.5) rectangle (17.5,6.85);% item width % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,5.5) rectangle (12.5,6.35) node[pos=.5,text=black]% % {\begin{tabular}{c} % \texttt{minipage left} \\ % \textcolor{blue}{\emph{nested list}} % \end{tabular}}; % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (14.5,5.5) rectangle (17.5,6.35) node[pos=.5,text=black]% % {\begin{tabular}{c} % \texttt{minipage right} \\ % \textcolor{blue}{\emph{drawing or tabular}} % \end{tabular}}; % \draw[<->,color=gray] (2.0,5.35) --node[below,text=keyname]{\texttt{list-indent}} (7.0,5.35); % \draw[<->,color=gray] (7.0,5.35) --node[below,text=keyname]{\texttt{mini-env}} (12.5,5.35); % \draw[<->,color=gray] (12.5,5.35) --node[below,text=keyname]% % {\begin{tabular}{c} % \texttt{mini-sep} \\ % \textcolor{module_name}{\texttt{\textbackslash{}miniright}} % \end{tabular}} (14.5,5.35); % \end{tikzpicture} % \caption{Representation of the \mykey{mini-env} output for a nested level \myenv*{enumext} environment.} % \label{fig:five} % \end{figure} % % The \myenv[no-index]{minipage} environments on the \emph{\enquote{left side}} and % \emph{\enquote{right side}} are always used with \emph{\enquote{aligned % on top}} |[t]|. It can be used in all nesting levels of the % environment \myenv*[no-index]{enumext} and the environment \myenv*[no-index]{keyans} and is controlled % by \mykey{mini-env} and \mykey{mini-sep} keys. In order to switch from % the \emph{\enquote{left}} side \myenv[no-index]{minipage} environment to the % \emph{\enquote{right}} side one must use the command |\miniright| % (\S\ref{subsec:keys-minipage}). % % \subsubsection{The \cs[no-index]{label} and \cs[no-index]{ref} system} % % This package provides a user interface like the % \mypkg[no-index]{enumitem}\cite{enumitem} package to customize the references % which is activated by the \mykey{ref} key (\S\ref{subsec:label-and-ref}), the standard \hologo{LaTeX} % |\label| and |\ref| commands work as usual. % It also provides an \emph{\enquote{internal reference}} system for the % \emph{\enquote{stored content}} by means of the key \mykey{save-ref} % (\S\ref{subsubsec:label-ref}) when the key \mykey{save-ans} is active (\S\ref{subsec:storage-keys}). % % \subsubsection{Support for \cs[no-index]{footnote}}\label{subsubsec:footnote} % % The \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} environments and the % \mykey{mini-env} key use the \myenv[no-index]{minipage} environment in their % implementation but in a transparent way for the user, it is only % used for typesetting. The implementation supports |\footnote| and is % compatible with \mypkg{hyperref} and works the same way as if used % anywhere in the document. % % Unfortunately, if \mypkg[no-index]{hyperref} is loaded and \emph{tagged} \texttt{PDF} is not % active, it will not produce the \enquote{links}, the internal implementation % uses |\footnotetext|\myoarg{number} and |\footnotemark|\myoarg{number}\mymarg{text} % and \enquote{links} for this are not supported by the \mypkg[no-index]{hyperref} package. % % The best way to solve this if \emph{tagged} \texttt{PDF} is NOT active % is to use Jean-François Burnol's \mypkg{footnotehyper}\cite{footnotehyper} % package. It will support keeping the \enquote{links} if % \mypkg[no-index]{hyperref} is loaded with the |hyperfootnotes=true| option (default). % Load it is as follows: % % \iffalse %<*example> % \fi \begin{examplecode}[frame=single] \IfDocumentMetadataF { \usepackage{`\mypkg{footnotehyper}`} \makesavenoteenv{enumext} \makesavenoteenv{enumext*} } \end{examplecode} % \iffalse % % \fi % % \begin{important} % At the moment the \mypkg[no-index]{footnotehyper} package v1.1f (2025/11/15) is not compatible % with \emph{tagged} \texttt{PDF}. % \end{important} % % \section{The environments provided} % % The package \mypkg*[no-index]{enumext} provides two main list environments, the % \emph{vertical} environment \myenv*[no-index]{enumext} and the \emph{horizontal} % environment \myenv*[no-index]{enumext*}. % % \begin{function}{enumext,enumext*} % \begin{minipage}[t]{0.45\linewidth} % \envexamp{enumext} % \end{minipage}\hfill % \begin{minipage}[t]{0.45\linewidth} % \envexamp{enumext*} % \end{minipage} % \end{function} % % \subsection{The environment \texttt{enumext}}\label{subsec:envenumext} % % The \myenv*[no-index]{enumext} is an environment that works in the same way as % the standard \myenv[no-index]{enumerate} environment provided by \hologo{LaTeX}, % |\item| and |\item|\myoarg{custom} commands work in % the usual way. The environment can be nested with at most \emph{\enquote{four levels}} % and the options can be configured globally using |\setenumext| % command and locally using \myoarg{key \textnormal{\textcolor{gray}{=}} val} % in the environment. % % \subsubsection*{Example with \texttt{columns=2}} % % \begin{enumext}[columns=2, topsep=0pt] % \item This text is in the first level. % \begin{enumext} % \item This text is in the second level. % \begin{enumext} % \item This text is in the third level. % \begin{enumext} % \item This text is in the fourth level. % \end{enumext} % \end{enumext} % \end{enumext} % \item[X] This text is in the first level. % \item* This text is in the first level. % \end{enumext} % % \subsection{The environment \texttt{enumext*}}\label{subsec:enumext-starred} % % The \myenv*[no-index]{enumext*} is a \emph{horizontal list environment} % similar to the \myenv[no-index]{shortenumerate} or \myenv[no-index]{tasks} environments % provided by the \mypkg{shortlst}\cite{shortlst} and \mypkg{tasks}\cite{tasks} % packages, |\item| and |\item|\myoarg{custom} work as usual. % The options can be configured globally using |\setenumext| command % and locally using \myoarg{key \textnormal{\textcolor{gray}{=}} val} % in the environment. % % Some considerations to take into account for this environment: % % \begin{itemize}[nosep,parsep=1pt,topsep=2pt] % \item The environment cannot be nested within itself or in the % environment \myenv*[no-index]{keyans*}, but it can be nested within % \myenv*[no-index]{enumext} and vice versa. % % \item Each \emph{\enquote{item content}} in the environment is placed % within a \myenv[no-index]{minipage} environment whose \emph{width} is stored % in the dimension \idimen[no-index]{itemwidth} does NOT include \mykey{labelwidth} and % \mykey{labelsep}, only the \emph{width of the content}. The only exception % is an item that occupies the whole row when the key \mykey[env]{item-break} % is active (\S\ref{subsubsec:item-break}). % % \item You cannot have floating environments like \myenv[no-index]{figure} or % \myenv[no-index]{table} or |\marginpar| but |\footnote| with \mypkg[no-index]{hyperref} % is supported. If you want to activate links \emph{\enquote{without}} % \emph{tagged} \texttt{PDF} active you must load \mypkg[no-index]{footnotehyper} % and \mypkg[no-index]{hyperref} packages (\S\ref{subsubsec:footnote}). % % \item The standard list environments \myenv[no-index]{itemize}, % \myenv[no-index]{enumerate}, \myenv[no-index]{description}, % \myenv[no-index]{quote}, \myenv[no-index]{quotation}, \myenv[no-index]{verse} and % \myenv[no-index]{list}, and the environments \myenv[no-index]{center}, % \myenv[no-index]{flushleft}, \myenv[no-index]{flushright}, \myenv[no-index]{trivlist}, % \myenv[no-index]{tabbing}, \myenv[no-index]{verbatim} and those created with % |\newtheorem| can be used in the \emph{\enquote{item content}}, also nested in % themselves, because inside them |\item| is the standard command % (\S\ref{subsec:item-nested}). % \end{itemize} % % \subsubsection*{Example with \texttt{columns=2}} % % \begin{enumext*}[columns=2] % \item This text is in the first level. % \item This text is in the first level. % \item[X] This text is in the first level. % \item* This text is in the first level. % \end{enumext*} % % \subsection{The command \cs[no-index]{item*}}\label{subsec:item-star} % % \begin{function}{\item*} % \begin{syntax} % |\item*|\myoarg{symbol}\myoarg{offset} % \end{syntax} % The \ics*{item*}, |\item*|\myoarg{symbol} and |\item*|\myoarg{symbol}\myoarg{offset} % work like the numbered |\item|, but places a \mymeta{symbol} to % the \emph{\enquote{left}} of the \mymeta{label} separated from it by % the \mymeta{offset} set by the \emph{second optional argument}. % % The \emph{starred argument} `|*|' cannot be separated by spaces % `\verb*| |' from the command, i.e. |\item*| and the % \emph{first optional argument} does NOT support \emph{verbatim content}. % It can be configured with the keys \mykey{item-sym*} and \mykey{item-pos*} % locally in the environment or globally using |\setenumext| command (\S\ref{sec:setenumext}). % \end{function} % % \begin{important}* % The behavior of |\item*| in the \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} environments is NOT % the same as in the \myenv*[no-index]{keyans} and \myenv*[no-index]{keyans*} environments. % \end{important} % % \subsubsection{Keys for \cs[no-index]{item*}} % % \keyexampcmd{item-sym\textcolor{star}{*}}{symbol}{\textbackslash{}textborn}[env] % Sets the \emph{symbol} to be displayed to the \emph{\enquote{left}} of the % box containing the current \mymeta{label} set by \mykey{labelwidth} key for |\item*| in % \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*}. The \emph{symbol} can be in % \emph{text} or \emph{math} mode, for example \mykey{item-sym*}|={$\star$}|. % % \keyexampcmd{item-pos\textcolor{star}{*}}{rigid length}{by levels}[env] % Sets the \emph{offset} between the box containing the % current \mymeta{label} defined by \mykey{labelwidth} key and the % \mymeta{symbol} set by \mykey{item-sym*} key. The default values are % set by \mykey{labelsep} key at each level. If positive values are % passed, it will \emph{offset to the left}; if negative values are % passed it will \emph{offset to the right}. % % \subsection{The command \cs[no-index]{item} in \texttt{enumext*}}\label{subsec:item-in-starred} % % \begin{function}{\item} % \begin{syntax} % |\item|\myparg{columns} % \end{syntax} % The \ics*{item} command for the \myenv*[no-index]{enumext*} environment provides % a \emph{\enquote{first optional argument}} |\item|\myparg{columns} which \emph{\enquote{joins items}} % between columns. % \end{function} % % Let's consider the following examples adapted directly from % the \mypkg[no-index]{tasks} package: % % \iffalse %<*example> % \fi \begin{examplecode}[frame=single] \begin{enumext*}[widest=10,columns=4] \item The first \item* The second \item The third \item The fourth \item(3)* The fifth item is way too long for this and needs three columns \item The sixth \item The seventh \item(2)[X] The eighth item is way too long for this and needs two columns (\the\itemwidth) \item The ninth \item[Z] The tenth (\the\itemwidth) \end{enumext*} \end{examplecode} % \iffalse % % \fi % % \begin{enumext*}[widest=10,columns=4] % \item The first % \item* The second % \item The third % \item The fourth % \item(3)* The fifth item is way too long for this and needs three columns % \item The sixth % \item The seventh % \item(2)[X] The eighth item is way too long for this and needs two columns (\the\itemwidth) % \item The ninth % \item[Z] The tenth (\the\itemwidth) % \end{enumext*} % % \subsubsection{Items on the whole row: the \texttt{item-break} key}\label{subsubsec:item-break} % % \keyexampcmd{item-break}{true \textnormal{\textcolor{lightgray}{\textbar}} false}{false}[env] % By default the \emph{\enquote{item content}} is typeset in a % \myenv[no-index]{minipage}, so an item cannot be broken between two pages: if % it does not fit in the rest of the page it moves entirely to the next one. % When this key is \texttt{true} and an item occupies the \emph{whole row}, the % content is typeset directly in the paragraph, without % the \myenv[no-index]{minipage}, and it can continue on the next page. % % An item occupies the whole row when it is |\item|\myparg{columns} with % \mymeta{columns} equal to the value of the \mykey{columns} key and it is the % first item of a row, or when \mykey{columns}|=1|, where every item occupies % the whole row. If \mymeta{columns} is greater than the columns left in % the row it is reduced, as explained in the \emph{warnings} for joined items, % so the item does NOT occupy the whole row and remains in a % \myenv[no-index]{minipage}. % % The \mymeta{label} is placed as always in the box set by \mykey{labelwidth} % and \mykey{labelsep}, and the following lines of the item are indented by % the same amount. The keys \mykey{listparindent} and \mykey{parsep} apply to the % paragraphs of the item. The other items of the environment are not modified. % The key works in \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*}, % locally and with |\setenumext| (\S\ref{sec:setenumext}). % % \begin{important}* % The vertical space around an item typeset without % \myenv[no-index]{minipage} can differ slightly from that of an item typeset % in a box, because the item takes part in the paragraph and page breaking. % \end{important} % % In the following example the third item occupies the whole row; if it were % near the end of a page its text could continue on the next one: % % \iffalse %<*example> % \fi \begin{examplecode}[frame=single] \begin{enumext*}[columns=2,item-break=true] \item One \item Two \item(2) This item occupies the whole row and can be broken between pages. \item Four \end{enumext*} \end{examplecode} % \iffalse % % \fi % % \begin{enumext*}[columns=2,item-break=true] % \item One % \item Two % \item(2) This item occupies the whole row and can be broken between pages. % \item Four % \end{enumext*} % % \section{The command \cs{setenumext}}\label{sec:setenumext} % % \begin{function}{\setenumext} % \begin{minipage}[t]{0.45\linewidth} % \cmdexamp{setenumext}{key \textnormal{\textcolor{gray}{=}} val} % \cmdexamp{setenumext}[enumext\textnormal{\textcolor{gray}{,}} level]{key \textnormal{\textcolor{gray}{=}} val} % \cmdexamp{setenumext}[enumext*]{key \textnormal{\textcolor{gray}{=}} val} % \cmdexamp{setenumext}[keyans]{key \textnormal{\textcolor{gray}{=}} val} % \end{minipage}\hfill % \begin{minipage}[t]{0.45\linewidth} % \cmdexamp{setenumext}[keyans*]{key \textnormal{\textcolor{gray}{=}} val} % \cmdexamp{setenumext}[print\textnormal{\textcolor{gray}{,}} level]{key \textnormal{\textcolor{gray}{=}} val} % \cmdexamp{setenumext}[print\textnormal{\textcolor{gray}{,}} \textnormal{\textcolor{red}{*}}]{key \textnormal{\textcolor{gray}{=}} val} % \cmdexamp{setenumext}[print*]{key \textnormal{\textcolor{gray}{=}} val} % \end{minipage} % % The command \ics*{setenumext} sets the \mymeta{keys} on a global basis % for environments \myenv*[no-index]{enumext}, \myenv*[no-index]{enumext*}, \myenv*[no-index]{keyans}, % \myenv*[no-index]{keyans*} and the |\printkeyans| command. % It can be used both in the preamble and in the body of the document % as many times as desired. % \end{function} % % The \mymeta{keys} set in the \emph{optional argument} of environments and % commands have the \emph{highest precedence}, overriding both % options passed by |\setenumext|. If the \emph{optional argument} is not % passed, the \emph{first level} of the environment \myenv*[no-index]{enumext} will be % taken by default. % % \begin{important}* % For security reasons the keys \mykey{resume} \emph{\enquote{with value}}, % \mykey{resume*}, \mykey{reset}, \mykey{reset*}, \mykey{series} and % \mykey{save-ans} they can NOT be set by this command and are ignored. % The key \mykey{save-ans} that activates the \emph{\enquote{storage system}} % must be passed directly in the \emph{optional argument} of the % \emph{\enquote{first level}} of the environment in which they are executed. % \end{important} % % \section{The command \cs[no-index]{setenumextmeta}} % % \begin{function}{\setenumextmeta} % \begin{syntax} % |\setenumextmeta|\myoarg{\textnormal{\textcolor{argnum}{\texttt{1}}}}\mymarg{key name}\mymarg{key-one \textnormal{\textcolor{gray}{=}} val\textnormal{\textcolor{gray}{,}} key-two \textnormal{\textcolor{gray}{=}} val\textnormal{\textcolor{gray}{,}} \dots} % |\setenumextmeta|\myoarg{\textnormal{\textcolor{argnum}{\texttt{2}}}}\mymarg{key name}\mymarg{key-one \textnormal{\textcolor{gray}{=}} val\textnormal{\textcolor{gray}{,}} key-two \textnormal{\textcolor{gray}{=}} val\textnormal{\textcolor{gray}{,}} \dots} % |\setenumextmeta|\myoarg{\textnormal{\textcolor{argnum}{\texttt{3}}}}\mymarg{key name}\mymarg{key-one \textnormal{\textcolor{gray}{=}} val\textnormal{\textcolor{gray}{,}} key-two \textnormal{\textcolor{gray}{=}} val\textnormal{\textcolor{gray}{,}} \dots} % |\setenumextmeta|\myoarg{\textnormal{\textcolor{argnum}{\texttt{4}}}}\mymarg{key name}\mymarg{key-one \textnormal{\textcolor{gray}{=}} val\textnormal{\textcolor{gray}{,}} key-two \textnormal{\textcolor{gray}{=}} val\textnormal{\textcolor{gray}{,}} \dots} % |\setenumextmeta|\myoarg{\textnormal{\textcolor{star}{\texttt{*}}}}\mymarg{key name}\mymarg{key-one \textnormal{\textcolor{gray}{=}} val\textnormal{\textcolor{gray}{,}} key-two \textnormal{\textcolor{gray}{=}} val\textnormal{\textcolor{gray}{,}} \dots} % |\setenumextmeta*|\mymarg{key name}\mymarg{key-one \textnormal{\textcolor{gray}{=}} val\textnormal{\textcolor{gray}{,}} key-two \textnormal{\textcolor{gray}{=}} val\textnormal{\textcolor{gray}{,}} \dots} % \end{syntax} % The command \ics*{setenumextmeta} adds a new \emph{\enquote{meta-key}} % for the environments \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*}, the % \mymarg{key name} must be different from those defined by the package. % The \emph{optional argument} of the form |[1]|, |[2]|, |[3]|, |[4]| % adds a new \emph{\enquote{meta-key}} for levels |1|, |2|, |3| and |4| % of the \myenv*[no-index]{enumext} environment, the form |[*]| adds a new % \emph{\enquote{meta-key}} for the \myenv*[no-index]{enumext*} environment. If it is % run \emph{without} the \emph{optional argument}, it will adds a new % \emph{\enquote{meta-key}} for the \emph{\enquote{first level}} of % the \myenv*[no-index]{enumext} environment. % \end{function} % % The \emph{starred argument} `|*|' will create the new \emph{\enquote{meta-key}} % for the environment \myenv*[no-index]{enumext*} and for \emph{\enquote{all levels}} of the % environment \myenv*[no-index]{enumext}. For example: |\setenumextmeta*{midsep}{topsep=3pt, partopsep=0pt}| % will create a new key |midsep| available for all levels of the % \myenv*[no-index]{enumext} environment and the \myenv*[no-index]{enumext*} environment % and it can be used like any other key so |\begin{enumext}[midsep]| % and |\begin{enumext*}[midsep]| will be valid. % % \section{The \texttt{keyval} system} % % The \mymeta{key = val} system used by the \mypkg*[no-index]{enumext} package is % implemented using \mypkg{l3keys} so it must be noted that \mymeta{keys} % marked as \emph{\enquote{value forbidden}}, that is \mymeta{key} is % different from \mymeta{key=}. % % All \mymeta{keys} described in this section are available for the % \myenv*[no-index]{enumext}, \myenv*[no-index]{enumext*}, \myenv*[no-index]{keyans} and \myenv*[no-index]{keyans*} % environments with the exception of the keys \mykey{series}, \mykey{resume}, % \mykey{resume*}, \mykey{reset} and \mykey{reset*} which are only available % for the \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} environments; and the keys % \mykey{mini-right}, \mykey{mini-right*} which are only available for % the \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} environments. % % All \mymeta{keys} related to vertical or horizontal spacing accept a % \emph{\enquote{skip}} or \emph{\enquote{dim}} expression if passed % between braces, i.e. you do not need to use |\dimeval| or |\dimexpr| % to perform calculations. % % \begin{important}* % It should be kept in mind that using any \mymeta{key} that sets % \emph{rubber lengths} or \emph{rigid lengths} for vertical or % horizontal space on a level will influence the vertical and horizontal % space for \emph{inner levels} and \myenv*[no-index]{keyans}, \myenv*[no-index]{keyans*} and % \myenv*[no-index]{keyanspic} environments. % \end{important} % % \subsection{Keys for \texttt{label} and \texttt{ref}}\label{subsec:label-and-ref} % % \keyexampcmd*{mode-box}{value forbidden}{not used}[env] % This is a \emph{\enquote{switch-key}} that does not receive an % argument and is \enquote{only} available for the \emph{\enquote{first level}} % of the \myenv*[no-index]{enumext} environment and the \myenv*[no-index]{enumext*} environment. % When this is set the \mykey{label}, \mykey{font}, \mykey{wrap-label} % and \mykey{wrap-label*} keys are executed within |\makebox| for the % \myenv*[no-index]{enumext} and \myenv*[no-index]{keyans} environments. % % \begin{important} % This key is intended for compatibility with \emph{tagged} \texttt{PDF} % and is forcibly \emph{\enquote{enabled}} when |\DocumentMetadata|\cite{userguide} is % present. If you want to get the same document output whether |\DocumentMetadata| % is active or not, you must enable this key. % \end{important} % % \begin{important}* % In the \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} environments |\makelabel| % is redefined using |\makebox| by default. If \myenv*[no-index]{enumext} or % \myenv*[no-index]{keyans} is used in the \myenv*[no-index]{enumext*} environment the key % must be activated manually. % \end{important} % % \keyexampcmd{label} % {\textnormal % {\ilabel{alph*} \textcolor{lightgray}{\textbar} \ilabel{Alph*} % \textcolor{lightgray}{\textbar} \ilabel{arabic*} % \textcolor{lightgray}{\textbar} \ilabel{roman*} % \textcolor{lightgray}{\textbar} \ilabel{Roman*}} % }{by levels}[env] % % Sets the \mymeta{label} that will be printed at the \emph{current level} % and default value for \mykey{labelwidth} key. % The default value for the first level of the environments % \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} is \ilabel{arabic*.}, for % second level are \ilabel*{alph*)}, for third level are \ilabel{roman*.} % and for fourth level is \ilabel{Alph*.}. For \myenv*[no-index]{keyans} % and \myenv*[no-index]{keyans*} environments the default value is \ilabel{Alph*)}. % % \begin{important}* % This key is intended to give the basic structure with which the % \mymeta{label} will be displayed, and the form in which it is % used by standard \emph{\enquote{label and ref}} and the % \emph{\enquote{internal label and ref}} system with the % \mykey{save-ref} key. You cannot use commands with \mymeta{label} as an % argument, for example |\emph|\mymarg{\textnormal{\ilabel[no-index]{alph*}}} will return an % error. For full customization of how \mymeta{label} is displayed use % the \mykey{font}, \mykey{wrap-label} and/or \mykey{wrap-label*} keys. % \end{important} % % \keyexampcmd{labelsep}{rigid length}{\mydim{0.3333}em}[env] % Sets the \emph{horizontal space} between the box containing the % current \mymeta{label} defined by \mykey{label} key and the text of an % item on the first line. Internally sets the value of |\labelsep| for % the current level. % % \keyexampcmd{labelwidth}{rigid length}{by label}[env] % Sets the \emph{width} of the label box containing the current \mymeta{label} % set by the \mykey{label} key. % Internally sets the value of |\labelwidth| for the current level. % The default values are calculated by means of the \emph{width} of a box % by setting a \emph{value} to the current counter set by \mykey{label} % key using `\mydim{0}' for \ilabel[no-index]{arabic*}, `|M|' for \ilabel[no-index]{Alph*}, % `|m|' for \ilabel[no-index]{alph*}, `|VIII|' for \ilabel[no-index]{Roman*} and `|viii|' % for \ilabel[no-index]{roman*}. % % \keyexampcmd{widest}{integer \textnormal{\textcolor{lightgray}{\textbar}} string}{empty}[env] % Sets the \mykey{labelwidth} key passing the \mymeta{integer} or converting % the \mymeta{string} of the form |\Alph|, |\alph|, |\Roman| or |\roman| % to a \emph{value} for the current counter defined by \mykey{label} key, % then calculating the \emph{width} by means of a box. For example |widest={XXIII}| % or |widest={23}| are equivalent. This key is useful when the default % values of the \mykey{labelwidth} key are smaller than those actually used. % % \keyexampcmd{font}{font commands}{empty}[env] % Sets the \emph{font style} for the current \mymeta{label} defined by \mykey{label} key. % You cannot use commands with an argument, for example |font={\small\textbf{#1}}| will % return an error, but |font={\bfseries\small}| it will work. For full customization % of how \mymeta{label} is displayed use \mykey{wrap-label} and/or \mykey{wrap-label*} keys. % % \keyexampcmd{align}{left \textnormal{\textcolor{lightgray}{\textbar}} right \textnormal{\textcolor{lightgray}{\textbar}} center}{left}[env] % Sets the \emph{aligned} of \mymeta{label} defined by \mykey{label} % key on the current level in the label box of width set by \mykey{labelwidth}. % % \newsavebox{\hashbox} % \begin{lrbox}{\hashbox} % \lstinline[language=enumext-doc,basicstyle=\ttfamily]+{#1}+ % \end{lrbox} % % \keyexampcmd{wrap-label}{code{} \space\usebox{\hashbox} more code}{empty}[env] % % Wraps the \emph{current} \mymeta{label} defined by \mykey{label} key % referenced by |{#1}| after executing the \mykey{align} and \mykey{font} % keys. The \mymarg{code} must be passed between braces and it does not modify % the value set by the \mykey{labelwidth} key and is applied \emph{only} % on |\item| and |\item*|. % When using it in the |\setenumext| command it is necessary to use the % \emph{double} `|{##1}|'. For example |wrap-label={\fbox{#1}}| % or you can create a command: % % \iffalse %<*example> % \fi \begin{examplecode}[frame=none] \NewDocumentCommand \mywrap { s m } { \IfBooleanTF{#1} {\textcolor{red}{\textbf{Q}}\textcolor{blue}{\textbf{.}}\textcolor{gray}{#2}} {\textcolor{blue}{\textbf{Q}}\textcolor{red}{\textbf{.}}\textcolor{gray}{#2}} } \end{examplecode} % \iffalse % % \fi % % and then pass it through the key |wrap-label={\mywrap{#1}}| or |wrap-label={\mywrap*{#1}}|. % % \keyexampcmd{wrap-label\textcolor{star}{*}}{code{} \space\usebox{\hashbox} more code}{empty}[env] % % The same as the \mykey{wrap-label} key but also applies on |\item|\myoarg{custom}. % % % \newsavebox{\refboxsample} % \begin{lrbox}{\refboxsample} % \small\textcolor{gray}{\ttfamily\{}\textnormal{\small\ilabel[no-index]{alph*}\textcolor{lightgray}{\textbar} \ilabel[no-index]{Alph*}\textcolor{lightgray}{\textbar} \ilabel[no-index]{arabic*}\textcolor{lightgray}{\textbar} \ilabel[no-index]{roman*}\textcolor{lightgray}{\textbar} \ilabel[no-index]{Roman*}}\textcolor{gray}{\ttfamily\}} % \end{lrbox} % \keyexampcmd{ref}{code{} \space\usebox{\refboxsample} more code}{empty}[env] % % Modifies the way \emph{cross references} are displayed. The % \mykey{label} key sets the default form of the \emph{cross references}, % by using this key you can define a different format, for example: % \mykey{ref}|=\emph|\mymarg{\textnormal{\ilabel[no-index]{alph*}}} is valid. % % Internally it renews the command associated with each counter when it % is executed, i.e., in the environment \myenv*[no-index]{enumext} the command |\theenumXi| % is modified when the key is executed at the first level, |\theenumXii| % when it is executed at the second level and |\theenumXiii| together % with |\theenumXiv| when it is executed at the % third and fourth levels. % % \begin{important}* % This must be kept in mind, since the values set by the \mykey{label} and % \mykey{ref} keys are not cumulative by levels, so if you have used the \mykey{ref} % key in the first level and then want to associate the counter with % \mykey{label} or \mykey{ref} in the second level you must use the direct commands, % i.e. |\arabic{enumXi}| to indicate the count of the first level % instead of using |\theenumXi|. % \end{important} % % \subsection{Keys for penalties}\label{subsec:penalties} % % Page breaks in the provided environments are controlled by the % following three parameters, which work together to ensure they look % good, avoiding unsightly page breaks that could distort the output. % % \keyexampcmd{beginpenalty}{integer}{\mydim{-51}}[env] % Set the \emph{page breaking} penalty for breaking at the beginning of % the \myenv*[no-index]{enumext}, \myenv*[no-index]{enumext*}, \myenv*[no-index]{keyans} and % \myenv*[no-index]{keyans*} environments. Internally sets the value of \textcolor{red}{\texttt{\textbackslash}}|@beginparpenalty|. % % \keyexampcmd{midpenalty}{integer}{\mydim{-51}}[env] % Set the \emph{page breaking} penalty for breaking between items of % the \myenv*[no-index]{enumext} and \myenv*[no-index]{keyans} environments. % Internally sets the value of \textcolor{red}{\texttt{\textbackslash}}|@itempenalty|. % In the \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} environments % the items are set inside the lines of a paragraph, so there is no vertical % space between items where this penalty could be inserted and the key has no effect. % % \keyexampcmd{endpenalty}{integer}{\mydim{-51}}[env] % Set the \emph{page breaking} penalty for breaking at the end of % the \myenv*[no-index]{enumext}, \myenv*[no-index]{enumext*}, \myenv*[no-index]{keyans} and % \myenv*[no-index]{keyans*} environments. Internally sets the value of \textcolor{red}{\texttt{\textbackslash}}|@endparpenalty|. % % \begin{important}* % The values passed to these \mymeta{keys} affect the nested % environments in which they were set and cannot be reset. % \hologo{LaTeX} default is \textcolor{red}{\texttt{-}}\textcolor{red}{\texttt{\textbackslash}}|@lowpenalty|, % that is, \mydim{-51}. Because it is negative, it somewhat encourages a % page break at each spot. Change it with, e.g., \textcolor{red}{\texttt{\textbackslash}}|@beginparpenalty=|\mydim{9999}; a value % of \mydim{10000} prohibits a page break. Please, refer to your % \hologo{LaTeX} or \hologo{TeX} manual about how penalties control page % breaks. % \end{important} % % \subsection{Keys for spaces}\label{subsec:keys-spaces} % % \keyexampcmd{show-length}{true \textnormal{\textcolor{lightgray}{\textbar}} false}{false}[env] % Displays on the terminal the values for \emph{all list parameters} at the current level. % For \emph{vertical spaces} show the values of |\topsep|, |\itemsep|, |\parsep| and |\partopsep|. % For \emph{horizontal spaces} show the values of |\labelwidth|, |\labelsep|, |\itemindent|, |\listparindent| and |\leftmargin|. % % \subsubsection{Vertical spaces} % % \keyexampcmd{topsep}{rubber length \textnormal{\textcolor{lightgray}{\textbar}} rigid length}{by levels}[env] % % Set the \emph{vertical space} added to both the top and bottom of the list. % Internally sets the value of |\topsep| for the current level. % The default value for the first level of the environments % \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} are \mydim{8.0pt plus 2.0pt minus 4.0pt}, % for second level are \mydim{4.0pt plus 2.0pt minus 1.0pt}, for third and % fourth level are \mydim{2.0pt plus 1.0pt minus 1.0pt}. For \myenv*[no-index]{keyans} % and \myenv*[no-index]{keyans*} environments the default value is \mydim{4.0pt plus 2.0pt minus 1.0pt}. % % \keyexampcmd{parsep}{rubber length \textnormal{\textcolor{lightgray}{\textbar}} rigid length}{by levels}[env] % % Set the \emph{vertical space} between paragraphs within an item. % Internally sets the value of |\parsep| for the current level. % The default value for the first level of the environments \myenv*[no-index]{enumext} % and \myenv*[no-index]{enumext*} are \mydim{4.0pt plus 2.0pt minus 1.0pt}, % for second level are \mydim{2.0pt plus 1.0pt minus 1.0pt}, for third and % fourth level are \mydim{0pt}. For \myenv*[no-index]{keyans} and \myenv*[no-index]{keyans*} % environments the default value is \mydim{2.0pt plus 1.0pt minus 1.0pt}. % % \begin{important}* % In the \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} environments this value % is passed to |\parskip| within the \myenv[no-index]{minipage} environment where % \emph{\enquote{item content}} is placed. % \end{important} % % \keyexampcmd{partopsep}{rubber length \textnormal{\textcolor{lightgray}{\textbar}} rigid length}{by levels}[env] % % Set the \emph{vertical space} added, beyond \mykey{topsep}, to the \enquote{top} and \enquote{bottom} % of the entire environment if the environment instance is preceded by a \emph{\enquote{blank % line}} or |\par| command. Internally sets the value of |\partopsep| for the current level. % The default values for first and second level in environment % \myenv*[no-index]{enumext} are \mydim{2.0pt plus 1.0pt minus 1.0pt}, % for third and fourth level are \mydim{1.0pt minus 1.0pt}. % For the \myenv*[no-index]{keyans} environment the default value is \mydim{2.0pt % plus 1.0pt minus 1.0pt}, and for the \myenv*[no-index]{keyans*} and % \myenv*[no-index]{enumext*} environments it is available but \emph{without} % effect. % % \begin{important}* % The value of this parameter also affects the \emph{inner levels} and the % environments \myenv*[no-index]{keyans}, \myenv*[no-index]{keyanspic} and \myenv*[no-index]{keyans*}. % Caution should be taken with \emph{\enquote{blank lines}} or |\par| % command \emph{\enquote{before}} each environment or nested level when % formatting the source code of document. \hologo{TeX} will enter \mymeta{vertical mode} % and apply this value to the \enquote{top} and \enquote{bottom} the % environment or nested level. % \end{important} % % \keyexampcmd{itemsep}{rubber length \textnormal{\textcolor{lightgray}{\textbar}} rigid length}{by levels}[env] % Set the \emph{vertical space} between items, beyond the \mykey{parsep}. % Internally sets the value of |\itemsep| for the current level. % The default value for the first level of the environments \myenv*[no-index]{enumext} % and \myenv*[no-index]{enumext*} are \mydim{4.0pt plus 2.0pt minus 1.0pt}, % for the rest of the levels are \mydim{2.0pt plus 1.0pt minus 1.0pt}. % For \myenv*[no-index]{keyans} and \myenv*[no-index]{keyans*} environments the default % value is \mydim{4.0pt plus 2.0pt minus 1.0pt}. % % \begin{important}* % In the \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} environments this value % corresponds to the separation between rows. % \end{important} % % \keyexampcmd*{noitemsep}{value forbidden}{not used}[env] % This is a \emph{\enquote{meta-key}} that does not receive an argument. Set % \mykey{itemsep} and \mykey{parsep} equal to \mydim{0pt} the entire level of environment. % % \keyexampcmd*{nosep}{value forbidden}{not used}[env] % This is a \emph{\enquote{meta-key}} that does not receive an argument. Sets all keys % for vertical spacing equal to \mydim{0pt} the entire level of environment. % % \keyexampcmd*{base-fix}{value forbidden}{not used}[env] % % This is a \emph{\enquote{switch-key}} that does not receive an % argument available \emph{only} for the \emph{\enquote{first level}} of environment % \myenv*[no-index]{enumext}. Fix the \emph{baseline} when an environment \myenv*[no-index]{enumext} % is nested in \myenv*[no-index]{enumext*} and there is no material between the % |\item| and the start of the environment for example |\item \begin{enumext}| % within the environment \myenv*[no-index]{enumext*}. Internally sets the keys \mykey{topsep}, % \mykey{above} and \mykey{above}|*| at \mydim{0pt}. % % \begin{important}* % This key is provided as a way to work around this minor issue, but you % should be aware that if for some reason you have the \mykey{itemindent} % key set in the \myenv*[no-index]{enumext*} environment it will be lost and you % will need to adjust it using the \mykey{list-offset} key in the % \myenv*[no-index]{enumext} environment. % \end{important} % % \subsubsection*{Extra vertical spaces} % % \begin{important}* % The following \mymeta{keys} should be used with \emph{\enquote{caution}}, they % are intended to be used at the \enquote{top} and \enquote{bottom} of % the environment when the \mykey{columns} or \mykey{mini-env} keys do % not provide adequate \emph{vertical spaces}. % The values passed can be \emph{rubber} or \emph{rigid} lengths, the % way they are applied is the way you differ, using the \emph{star} `|*|' % \mymeta{keys} applies |\vspace*| so that \hologo{LaTeX} does % \emph{not discard} this space at page break. % \end{important} % % \keyexampcmd{above}{rubber length \textnormal{\textcolor{lightgray}{\textbar}} rigid length}{not used}[env] % % Set the \emph{extra vertical space} added, beyond \mykey{topsep}, to % the top of the entire level of environment. This key is intended to % give a \emph{\enquote{fine adjustment}} of the vertical space % \emph{\enquote{above}} the environment without hindering the value of % the \mykey{topsep} key. The space is added with |\vspace| so is % \emph{\enquote{discardable}}. % % \keyexampcmd{above\textcolor{star}{*}}{rubber length \textnormal{\textcolor{lightgray}{\textbar}} rigid length}{not used}[env] % % Set the \emph{extra vertical space} added, beyond \mykey{topsep}, to % the top of the entire level of environment. This key is intended to % give a \emph{\enquote{fine adjustment}} of the vertical space % \emph{\enquote{above}} the environment without hindering the value of % the \mykey{topsep} key. The space is added with |\vspace*| so is % \emph{\enquote{not discardable}}. % % \keyexampcmd{below}{rubber length \textnormal{\textcolor{lightgray}{\textbar}} rigid length}{not used}[env] % % Set the \emph{extra vertical space} space added, beyond \mykey{topsep}, to % the bottom of the entire level of environment. This key is intended to % give a \emph{\enquote{fine adjustment}} of the vertical space on the % \emph{\enquote{below}} the environment without hindering the value of % the \mykey{topsep} key. The space is added with |\vspace| so is % \emph{\enquote{discardable}}. % % \keyexampcmd{below\textcolor{star}{*}}{rubber length \textnormal{\textcolor{lightgray}{\textbar}} rigid length}{not used}[env] % % Set the \emph{extra vertical space} space added, beyond \mykey{topsep}, to % the bottom of the entire level of environment. This key is intended to % give a \emph{\enquote{fine adjustment}} of the vertical space on the % \emph{\enquote{below}} the environment without hindering the value of % the \mykey{topsep} key. The space is added with |\vspace*| so is % \emph{\enquote{not discardable}}. % % \subsubsection{Horizontal spaces} % % \keyexampcmd{list-offset}{rigid length}{\mydim{0}pt}[env] % Sets the \emph{horizontal translation} of the entire environment level from the left edge % of the box defined by the \mykey{labelwidth} key. Internally sets the values of % |\leftmargin| and |\itemindent| for the current level. % % \keyexampcmd{list-indent}{rigid length}{labelwidth + labelsep}[env] % Sets the \emph{indentation} of the whole environment under the box defined by % \mykey{labelwidth} and \mykey{labelsep} keys. Internally sets the value of % |\leftmargin| and |\itemindent| for the current level. % If |list-indent=|\mydim{0pt} is set in the environments \myenv*[no-index]{enumext} % and \myenv*[no-index]{keyans} the \mymeta{label} will be part of the text, separated % by the value of the \mykey{labelsep} key and the \emph{first word}, in % simple terms it will look like a \emph{\enquote{common paragraph}}. % % \begin{important}* % The \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} environments are % implemented using |\makebox| and \myenv[no-index]{minipage} which causes % \emph{\enquote{list indent}} to always be equal to the value passed to % \mykey{labelwidth} plus \mykey{labelsep}. Passing a value to this key is % equivalent to setting the value for the \mykey{list-offset} key. % \end{important} % % \keyexampcmd{itemindent}{rigid length}{\mydim{0}pt}[env] % % Sets the extra \emph{horizontal indentation}, beyond \mykey{labelsep}, % of the \emph{\enquote{first line}} of each |\item| that is not followed % by a \emph{\enquote{blank line}} or the |\par| command. This value must % be greater than or equal to \mydim{0pt} and is applied internally using % |\hspace| \emph{without} modifying the value of |\itemindent|. % % \begin{important}* % This key is intended for the \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} % environments where, by their implementation, it is not possible to % adjust \mykey{labelwidth} and \mykey{list-indent} \emph{without} % modifying the output. If you use \myenv*[no-index]{enumext} or \myenv*[no-index]{keyans} % and want to get around the effect of a \emph{blank line} or of the |\par| % command followed by |\item| you can modify \mykey{labelwidth} and % \mykey{list-indent} and get the same effect. % \end{important} % % \keyexampcmd{rightmargin}{rigid length}{\mydim{0}pt}[env] % % Set the \emph{horizontal space} between the right margin of the environment and the % right margin of the enclosing environment, the value it takes must be % greater than or equal to \mydim{0pt}. Internally sets the value of % |\rightmargin| for the current level. % % \keyexampcmd{listparindent}{rigid length}{\mydim{0}pt}[env] % Sets the \emph{horizontal space} indentation, beyond \mykey{list-indent}, % for second and subsequent paragraphs within a list item. Internally % sets the value of |\listparindent| for the current level. % % \begin{important}* % In the \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} environments this value % is passed to |\parindent| within the \myenv[no-index]{minipage} environment where % \emph{\enquote{item content}} is placed. % \end{important} % % \subsection{Keys for add \texttt{code}}\label{subsec:keys-code} % % The following \mymeta{keys} should be used with \emph{\enquote{caution}}, % they are intended to inject \mymarg{code} into different parts of the % defined environments. It must be kept in mind that the defined % environments are based on the \myenv[no-index]{list} base environment provided by % \hologo{LaTeX} which is defined (simplified) as plain form |\list|\mymarg{arg one}\mymarg{arg two}. % Using the \mykey{before*} key does not allow access to the \myenv[no-index]{list} % parameters defined by \myoarg{key % \textnormal{\textcolor{gray}{=}} val}. % % \keyexampcmd{before}{code}{not used}[env] % Execute \mymarg{code} \emph{\enquote{before}} the environment % starts. The \mymarg{code} must be passed between braces, is executed % \emph{\enquote{after}} all calculations related to the \emph{list % parameters} in the environment and the \mymeta{keys} sets by % \myoarg{key \textnormal{\textcolor{gray}{=}} val} have been performed, % that is, in the \emph{second argument} of the list: |\begin{list}|\mymarg{arg one}|{|\mymeta{arg two}\mymarg[cbc=module_name,ac=araracolor]{code}|}|. % % \keyexampcmd{before\textcolor{star}{*}}{code}{not used}[env] % Execute \mymarg{code} \emph{\enquote{before}} the % environment starts. The \mymarg{code} must be passed between braces, is executed % \emph{\enquote{before}} performing all calculations related to the \emph{list % parameters} and the \mymeta{keys} sets in \myoarg{key \textnormal{\textcolor{gray}{=}} % val} of the environment that is, \emph{\enquote{before}} the arguments % defining the list environment are executed: % \mymarg[type=tt,cbc=module_name,ac=araracolor]{code}|\begin{list}|\mymarg{arg % one}\mymarg{arg two}. % % \keyexampcmd{first}{code}{not used}[env] % Executes \mymarg{code} when \emph{\enquote{starting}} the % environment. The \mymarg{code} must be passed between % braces, is executed right \emph{\enquote{after}} all \emph{list % parameters} are done, after the second argument of list, just before the first occurrence of |\item|: % |\begin{list}|\mymarg{arg one}\mymarg{arg two}\mymarg[cbc=module_name,ac=araracolor]{code}|\item|. % % \begin{important}* % Keep in mind that the \mymarg{code} set in this \mymeta{key} will affect % the entire \emph{\enquote{body}} of the environment and therefore the % inner levels of the list and the \myenv*[no-index]{keyans}, \myenv*[no-index]{keyans*} and % \myenv*[no-index]{keyanspic} environments. It is recommended to set this \mymeta{key} % per level. In the \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} environments % this \mymeta{key} is executed \emph{\enquote{after}} the \mykey{listparindent}, % \mykey{parsep} and \mykey{itemindent} \mymeta{keys} within the \myenv[no-index]{minipage} % environment in which the \emph{\enquote{item content}} is placed. % Making modifications to |\setcounter| in these environments using this \mymeta{key} % will not have the expected effect. % \end{important} % % \keyexampcmd{after}{code}{not used}[env] % Execute \mymarg{code} \emph{\enquote{after}} finishing the % environment. The \mymarg{code} must be passed between braces. % % \subsection{Keys for \texttt{start}, \texttt{series} and \texttt{resume}}\label{subsec:keys-start-series-resume} % % \keyexampcmd{start}{integer \textnormal{\textcolor{lightgray}{\textbar}} integer expression}{\mydim{1}}[env] % Sets the \emph{start value} of the numbering on the \emph{\enquote{current level}}. % The \mymarg{integer expression} must be passed between braces, internally is evaluated and pass % to the \emph{\enquote{counter}} defined by \mykey{label} key on the current level, i.e. it is equivalent to enter % |start={\dimeval{100*\value{chapter}}| or |start={100*\value{chapter}}|. % % \keyexampcmd{start\textcolor{star}{*}}{integer \textnormal{\textcolor{lightgray}{\textbar}} string}{not used}[env] % Sets the \emph{start value} of the numbering on the \emph{\enquote{current level}}. % Internally \mymeta{string} is converted and passed as value to the \emph{\enquote{counter}} % defined by \mykey{label} key on the current level, i.e. it is equivalent to enter % |start*=5|, |start*=E| or |start*=v|. % % \begin{important} % The \emph{start value} in \myenv*[no-index]{enumext} and \myenv*[no-index]{keyans} are set in the \emph{second argument} of the \myenv[no-index]{list} % environment and \emph{\enquote{before}} the execution of the keys \mykey{before} % and \mykey{first}, but in the \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} it is set much later: |\begin{list}|\mymarg{arg one}\mymarg{arg two}|\setcounter|. % \end{important} % % \begin{important}* % The following \mymeta{keys} are available only for the \myenv*[no-index]{enumext} % and \myenv*[no-index]{enumext*} environments. % \end{important} % % \keyexampcmd{series}{series name}{not used}[env] % % Stores the \emph{keys} of the \emph{optional argument} of the \emph{\enquote{current level}} % of the environment in which it is executed in \mymarg{series name} which % is used as an \emph{argument} in the \mykey{resume} key. The \mymeta{keys} % stored in \mymarg{series name} are NOT cumulative and are overwritten % if the same \mymarg{series name} is used again at the \emph{\enquote{same level}} % at which the key was executed. % % \begin{important}* % For security reasons the \mykey{series} key will never save in % \mymarg{series name} the \mymeta{keys} \mykey{series}, \mykey{resume}, % \mykey{resume*}, \mykey{reset}, \mykey{reset*}, \mykey{save-ans}, \mykey{save-key}, % \mykey{start*} and \mykey{start}. % \end{important} % % \keyexampcmd{resume}{series name}{not used}[env] % Sets the \emph{start value} and \emph{options} for the \emph{\enquote{current level}} % continuing the numbering and \emph{options} of the \emph{\enquote{same level}} as % the environment in which the \mykey{series}|=|\mymarg{series name} % key was executed, the \emph{start value} will continue numbering according to % the last execution of \mykey{resume}|=|\mymarg{series name}. If passed % \emph{\enquote{without value}} this will only set \emph{start value} % continue the numbering of the \emph{\enquote{same level}} % from the last environment and level in which \mykey{series}|=|\mymarg{series name} % or \mykey{resume}|=|\mymarg{series name} is NOT present and if the % \mykey{save-ans} key is active (on the left) it will continue the numbering from the % \enquote{last} environment in which it was executed. The \emph{start value} % can be overwritten using \mykey{start} or \mykey{start*} keys. % % \begin{important}* % The \mykey{resume} key passed \emph{\enquote{without value}} must be % exactly \emph{\enquote{without value}}, i.e. \mykey{resume}|=| cannot % be used and if executed before \mykey{resume*} it will affect the % \emph{start value}. % \end{important} % % \keyexampcmd*{resume\textcolor{star}{*}}{value forbidden}{not used}[env] % Sets the \emph{start value} and \emph{options} for the \emph{\enquote{current level}} % continuing the numbering and options of the \emph{\enquote{same level}} % as the last environment and level in which the \mykey{series}|=|\mymarg{series name} or % \mykey{resume}|=|\mymarg{series name} keys are NOT present and if the % \mykey{save-ans} key is active (on the left) it will continue the numbering and options % from the \enquote{last} environment in which it was executed. The \emph{start value} % can be overwritten using \mykey{start} or \mykey{start*} keys. % % \begin{important}* % When using the key \mykey{resume}|=|\mymarg{series name} or % \mykey{resume*} you will have hierarchy in the \mymeta{keys} that are % stored in \mymarg{series name} or in an internal version of % \mymarg{series name} in the case of \mykey{resume*}. If you want to % \emph{reset} the value of a \mymeta{key} that is already stored in % \mymarg{series name} or in an internal version of \mymarg{series name} % this must be placed to the \emph{right} of the key % \mykey{resume}|=|\mymarg{series name} or \mykey{resume*}. % \end{important} % % \begin{important}* % When the \mykey{resume}|*| key is executed consecutively, it does not % rewrite the \mymeta{keys} stored in the internal version of % \mymarg{series name} and if the environment that precedes it does not % have the \emph{optional argument}, it will just continue with the % numbering. % \end{important} % % \subsection{Keys for \texttt{reset}}\label{subsec:reset} % % \keyexampcmd*{reset}{value forbidden}{not used}[env] % Resets the \emph{start value} of the \emph{\enquote{counters}} in the % \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} environments along with the % \emph{\enquote{internal counters}} used by the \mykey{resume} \emph{without value} % and \mykey{resume*} keys at the \emph{\enquote{level}} at which it is % executed. The \emph{start value} can be overwritten using the \mykey{start} % or \mykey{start*} keys. % % \keyexampcmd*{reset\textcolor{star}{*}}{value forbidden}{not used}[env] % Resets the \emph{start value} of the \emph{\enquote{counters}} in the % \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} environments along with the % \emph{\enquote{internal counters}} used by the \mykey{resume} \emph{without value} % and \mykey{resume*} keys at the \emph{\enquote{level}} at which it is % executed and in the \emph{\enquote{levels below}} it in the case of % the \myenv*[no-index]{enumext} environment. The \emph{start value} can be overwritten % using the \mykey{start} or \mykey{start*} keys. % % \begin{important}* % These keys are intended to be used in cases where the |\resetenumext| % command does not work, e.g. after an unnumbered chapter. It should % preferably be set \emph{only} on the \emph{first level}, although it is % available for all levels. % \end{important} % % \subsubsection{The command \cs{resetenumext}}\label{subsubsec:resetenumext} % % \begin{function}{\resetenumext} % \begin{minipage}[t]{0.45\linewidth} % \cmdexamp{resetenumext}[\textnormal{\textcolor{argnum}{\texttt{1}}}]{some counter} % \cmdexamp{resetenumext}[\textnormal{\textcolor{argnum}{\texttt{2}}}]{some counter} % \cmdexamp{resetenumext}[\textnormal{\textcolor{argnum}{\texttt{3}}}]{some counter} % \end{minipage}\hfill % \begin{minipage}[t]{0.45\linewidth} % \cmdexamp{resetenumext}[\textnormal{\textcolor{argnum}{\texttt{4}}}]{some counter} % \cmdexamp{resetenumext}[\textnormal{\textcolor{star}{\texttt{*}}}]{some counter} % \cmdexamp{resetenumext\textcolor{star}{*}}{some counter} % \end{minipage} % % The \ics*{resetenumext} command \emph{\enquote{resets}} the \emph{start value} % of the \emph{\enquote{counters}} for the \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} % environments along with the \emph{\enquote{internal counters}} used by % the keys \mykey{resume} \emph{without value} and \mykey{resume*} % according to the value of \mymarg{some counter}. For example |\resetenumext{chapter}| % will \emph{\enquote{reset}} the numbering of \emph{\enquote{all levels}} % of the \myenv*[no-index]{enumext} environment for each execution of a \emph{\enquote{numbered}} chapter. % \end{function} % % The \emph{optional argument} of the form |[1]|, |[2]|, |[3]|, |[4]| % \emph{\enquote{reset}} the values for levels |1|, |2|, |3| and |4| % of the \myenv*[no-index]{enumext} environment, the form |[*]| % \emph{\enquote{reset}} the values for the \myenv*[no-index]{enumext*} % environment. If is run \emph{without} the \emph{optional argument}, it % will \emph{\enquote{reset}} the values for \emph{\enquote{all % levels}} of the \myenv*[no-index]{enumext} environment. % % The \emph{starred argument} `|*|' will \emph{\enquote{reset}} the % values for \emph{\enquote{all levels}} of the \myenv*[no-index]{enumext} and % \myenv*[no-index]{enumext*} environments. % % \subsection{Keys for \env{multicols}}\label{subsec:keys-multicols} % % \keyexampcmd{columns}{integer}{\mydim{1}}[env] % % Set the \emph{number of columns} to be used by the \myenv[no-index]{multicols} % environment within the environments \myenv*[no-index]{enumext} and \myenv*[no-index]{keyans}. The value must be a positive % integer less than or equal to \mydim{10}. % In the \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} environments they % correspond to the default number of columns (without joining) and % internally adjust the value of \idimen[no-index]{itemwidth}. % % \keyexampcmd{columns-sep}{rigid length}{by level}[env] % % Set the \emph{space between} columns used by the \myenv[no-index]{multicols} % environment within the environments \myenv*[no-index]{enumext} and \myenv*[no-index]{keyans}. Internally sets the value of % |\columnsep|, by default its value is equal to the sum of the % values set in the keys \mykey{labelwidth} and \mykey{labelsep} of the % current level. % In the \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} environments they % correspond to the \emph{space between} columns (without joining) and % internally adjust the value of \idimen[no-index]{itemwidth}. % % \subsection{Keys for \env{minipage}}\label{subsec:keys-minipage} % % \keyexampcmd{mini-env}{rigid length}{not used}[env] % % Sets the \emph{width} of the \myenv[no-index]{minipage} environment on % the \emph{\enquote{right side}}. This value added to the value set by % the \mykey{mini-sep} key to determines the \emph{width} of the % \myenv[no-index]{minipage} environment on the \emph{\enquote{left side}}, taking % |\linewidth| as the maximum reference value. % % \keyexampcmd{mini-sep}{rigid length}{\mydim{0.3333}em}[env] % % Sets the \emph{space between} the \myenv[no-index]{minipage} environment on the % \emph{\enquote{left side}} and the \myenv[no-index]{minipage} environment on % the \emph{\enquote{right side}}. This separation is applied together % with |\hfill|. % % \subsubsection{The command \cs[no-index]{miniright}} % % \begin{function}{\miniright} % \begin{syntax} % |\begin{enumext}[mini-env=|\mymarg{rigid length}|]| \mymeta[cf=gray]{items before} |\item \miniright| \mymeta[cf=gray]{content} |\end{enumext}|\par % |\begin{enumext}[mini-env=|\mymarg{rigid length}|]| \mymeta[cf=gray]{items before} |\item \miniright*|\mymeta[cf=gray]{content} |\end{enumext}| % \end{syntax} % \end{function} % % The \ics*{miniright} command close the \myenv[no-index]{minipage} environment on % the \emph{\enquote{left side}} and opens the \myenv[no-index]{minipage} environment % on the \emph{\enquote{right side}} by starting it with the |\centering| % command. It must be placed \emph{\enquote{after}} the last |\item| % of the current environment and \emph{\enquote{before}} starting the % material to be placed on the \emph{\enquote{right side}}. % % The \emph{starred argument} `|*|' inhibits the use of |\centering| % command i.e. the usual \hologo{LaTeX} justification is maintained in % the \myenv[no-index]{minipage} on the \emph{\enquote{right side}}. % % \subsubsection{The key \texttt{mini-right}} % % In the \emph{horizontal list environments} \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} % it is not possible to use the |\miniright| command and the \mykey{mini-right} % key must be used instead. % % \keyexampcmd{mini-right}{content}{not used}[env] % % Set the \emph{content} for the drawing or tabular to be placed in the % \myenv[no-index]{minipage} environment on the \emph{\enquote{right side}} by % starting it with |\centering|. The \mymarg{content} must be passed between braces. % % \keyexampcmd{mini-right\textcolor{star}{*}}{content}{not used}[env] % % Same as above, but \emph{without} starting with |\centering|. % % \section{The storage system}\label{sec:storage-system} % % The entire mechanism for \emph{\enquote{storing content}} it is % activated according to \mykey{save-ans} key on the % \emph{\enquote{first level}} of \myenv*[no-index]{enumext} or \myenv*[no-index]{enumext*} % environments and it is ignored if they are established when they are % nested inside each other. Only when this \mymeta{key} is \emph{\enquote{active}} % the |\anskey| command and the environments \myenv*[no-index]{anskey*}, % \myenv*[no-index]{keyans}, \myenv*[no-index]{keyans*} and \myenv*[no-index]{keyanspic} are available. % % \iffalse %<*example> % \fi \vspace*{-1\baselineskip} \begin{minipage}[t]{0.45\linewidth} \centering \begin{examplecode}[frame=none,mathescape=true] \begin{enumext}[save-ans=`\mymarg{store name}`] \item Text \anskey{answer} \item Text \begin{keyans} $\cdots$ \end{keyans} \end{enumext} \end{examplecode} \end{minipage}\hfill \begin{minipage}[t]{0.45\linewidth} \vspace{0pt}\centering \begin{examplecode}[frame=none,mathescape=true] \begin{enumext}[save-ans=`\mymarg{store name}`] \item Text \anskey{answer} \item Text \begin{keyanspic} $\cdots$ \end{keyanspic} \end{enumext} \end{examplecode} \end{minipage} % \iffalse % % \fi % % By executing the key \mykey{save-ans}|=|\mymarg{store name} the entire % \emph{\enquote{structure}} of the environment (excluding the \emph{first level}) % including the \emph{optional argument} passed to the inner levels or % the environment nested in it, along with the \mymeta{content} passed % to |\anskey| or \myenv*[no-index]{anskey*}, the current \mymeta{labels} for % |\item*| and |\anspic*| in the environments \myenv*[no-index]{keyans}, % \myenv*[no-index]{keyans*} and \myenv*[no-index]{keyanspic} will be \emph{\enquote{stored}} % in a \emph{sequence} \mymarg{store name} and at the same time will be % \emph{\enquote{stored}} (without the \emph{\enquote{structure}} or % \emph{optional argument}) in a \emph{prop list} \mymarg{store name}. % % For security reasons the \emph{optional argument} of the inner levels % or the nested environment are \emph{filtered} by excluding all \mymeta{keys} % related to the \emph{\enquote{storage system}} (\S\ref{subsec:storage-keys}) % along with the keys \mykey{mini-env}, \mykey{mini-sep}, \mykey{mini-right}, % \mykey{mini-right*}, \mykey{series}, \mykey{resume} and \mykey{resume*} % when storing in \emph{sequence} \mymarg{store name} set by \mykey{save-ans} key. % % \subsection{Keys for storage system}\label{subsec:storage-keys} % % The only \mymeta{keys} available for all levels of the \myenv*[no-index]{enumext} % environment and the \myenv*[no-index]{enumext*} environment are \mykey{no-store} % and \mykey{save-key}, the rest of the \mymeta{keys} described in this % section must be passed directly in the \emph{optional argument} of the % \emph{\enquote{first level}} of the environment in which the key % \mykey{save-ans} is executed. The key \mykey{save-ans} should NOT be passed % with the command |\setenumext|. % % \keyexampcmd{save-ans}{store name}{not set}[env] % Sets the \emph{name} of the \emph{sequence} and \emph{prop list} in % which the \mymarg{contents} will be \emph{\enquote{stored}} by |\anskey| % and \myenv*[no-index]{anskey*} in \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} % environments and the current \mymeta{labels} for |\item*| and % |\anspic*| in the environments \myenv*[no-index]{keyans}, \myenv*[no-index]{keyans*} % and \myenv*[no-index]{keyanspic}. If the \emph{sequence} or \emph{prop list} % \mymarg{store name} does not exist, it will be created globally and % will not be \emph{overwritten} if the key is used again. % % \keyexampcmd{save-key}{key list}{not set}[env] % This key \emph{overrides} the default \emph{\enquote{stored keys}} of % the \emph{optional argument} of the inner levels or nested environment % that will be passed to the \emph{sequence} \mymarg{store name} set by % \mykey{save-ans} key. The \mymeta{key list} passed to this key ignores % any \mymeta{keys} in the \emph{\enquote{stored structure}} and must be % passed between braces. For example, if executed at a second level: % % \iffalse %<*example> % \fi \begin{examplecode}[frame=none,mathescape=true] \begin{enumext}[save-ans=`\mymarg{store name}`] \item Text \anskey{answer} \item Text \begin{enumext}[nosep, columns=2, save-key={columns=3}] $\cdots$ \end{enumext} \end{enumext} \end{examplecode} % \iffalse % % \fi % % The \emph{\enquote{stored keys}} by default in the \emph{sequence} % \mymarg{store name} would be |nosep| and |columns=2|, but using the key % \mykey{save-key}|={columns=3}| will overwrite and the % \emph{\enquote{stored key}} in the \emph{sequence} \mymarg{store name} % are only |columns=3| ignoring all the others. % % \keyexampcmd{save-sep}{text symbol}{\{, \}}[env] % Sets the \emph{text symbol} that will separate the current \mymeta{label} % to the \emph{optional argument} passed to the |\item*| and |\anspic*| % in the environments \myenv*[no-index]{keyans}, \myenv*[no-index]{keyans*} and \myenv*[no-index]{keyanspic} % and storing them in the \emph{sequence} and \emph{prop list} \mymarg{store name} % set by \mykey{save-ans} key. % The \mymarg{text symbol} must always be passed between % braces, whitespace `\verb*+ +' is preserved within the braces and only % affects the \emph{\enquote{stored content}} and not what is displayed % when using the \mykey{show-ans} or \mykey{show-pos} keys. % % \keyexampcmd*{no-store}{value forbidden}{not used}[env] % % This is a \emph{\enquote{switch-key}} that does not receive an argument % and disables the \emph{\enquote{storing content}} in the \emph{sequence} % and \emph{prop list} \mymarg{store name} set by \mykey{save-ans} key at % the entire level or a nested environment in which it runs. This key % is intended for use in internal levels or nested \myenv*[no-index]{enumext} or % \myenv*[no-index]{enumext*} environments in which you want to use \myenv*[no-index]{enumext} % or \myenv*[no-index]{enumext*} but \emph{\enquote{without}} using the |\anskey| % command or use \myenv*[no-index]{anskey*} environment and \emph{\enquote{without}} % interfering with the \mykey{check-ans} key. % % \subsubsection{Keys for \texttt{label} and \texttt{ref}}\label{subsubsec:label-ref} % % \keyexampcmd{save-ref}{true \textnormal{\textcolor{lightgray}{\textbar}} false}{false}[env] % Activates the \emph{\enquote{internal label and ref}} mechanism for % referencing \emph{\enquote{stored content}} in \emph{prop list} % \mymarg{store name} set by \mykey{save-ans} key. To reference the % location of the \emph{\enquote{stored content}} within the environment % you must use |\ref|\mymarg{store name \textnormal{\textcolor{red}{:}} position}, % where \mymeta{position} corresponds to the position occupied by the % \emph{\enquote{stored content}} in the \emph{prop list} \mymarg{store name} % returned by the \mykey{show-pos} key. For example |\ref{test:4}| will % return |3.(b)| which corresponds to the location of the \emph{\enquote{stored content}} % at position |4| in \emph{prop list} |test| within the environment in % which the key \mykey{save-ans}|=test| was set. % % \keyexampcmd{mark-ref}{symbol}{\textbackslash{}textreferencemark}[env] % Sets the \emph{symbol} that will be displayed by the |\printkeyans| % command only if the \mypkg[no-index]{hyperref} package is detected and the % \mykey{save-ref} key are active. % This \emph{\enquote{symbol}} is used as a \emph{\enquote{link}} between the environment % in which the \mykey{save-ans} key was used and the place where the % command is executed. % % \subsubsection{Keys for \texttt{wrap} and \texttt{marks}}\label{subsubsec:wrap-display} % % The \mypkg*[no-index]{enumext} package provides a set of \mymeta{keys} to set and % manipulate \emph{\enquote{symbol marks}} associated with % \emph{\enquote{answers}} and how they are displayed and stored in the % \emph{sequence} and \emph{prop list}. % % The \mymeta{keys} available for the |\anskey| command and the % \myenv*[no-index]{anskey*} environment can be passed \emph{\enquote{only}} in the % \emph{optional argument} in the \emph{\enquote{first level}} of the % \myenv*[no-index]{enumext} or \myenv*[no-index]{enumext*} environment. % % The \mymeta{keys} available for the \myenv*[no-index]{keyans} and % \myenv*[no-index]{keyans*} environments can be passed locally in the % \emph{optional argument}, at the \emph{\enquote{first level}} of the % \myenv*[no-index]{enumext} or \myenv*[no-index]{enumext*} environment or via the % |\setenumext| command with one minor difference, when \mymeta{keys} are passed % through the \emph{\enquote{first level}} of the \myenv*[no-index]{enumext} or % \myenv*[no-index]{enumext*} environment they are set in \emph{\enquote{both}} % environments, but when they are passed using the |\setenumext| command % they are set \emph{\enquote{individually}} in each environment. % % \keyexampcmd{show-ans}{true \textnormal{\textcolor{lightgray}{\textbar}} false}{false}[env] % % Display the \emph{symbol} set by the \mykey{mark-ans} key to the left of % the \emph{mandatory argument} \mymeta{content} passed to the |\anskey| % command and \mymeta{body} for the \myenv*[no-index]{anskey*} environment using % the \mykey{wrap-ans} key if set. % For |\item*| and |\anspic*| the \myenv*[no-index]{keyans}, % \myenv*[no-index]{keyans*} and \myenv*[no-index]{keyanspic} environments it will display % the \emph{symbol} set by the \mykey{mark-ans*} key to the left of the % current \mymeta{label} and \emph{optional argument}. If the % \emph{optional argument} is present in |\item*| or |\anspic*| % it will be shown using \mykey{wrap-opt} key. % % \subsubsection*{Keys for \texttt{\textbackslash{}anskey} and \texttt{anskey*}} % % \keyexampcmd{mark-ans}{symbol}{\textbackslash{}textasteriskcentered}[env] % Sets the \emph{symbol} to be displayed in the left margin for % |\anskey| command and \myenv*[no-index]{anskey*} environment when using the % key \mykey{show-ans}. The \emph{\enquote{symbol}} is placed in a box % of width equal to the value of \mykey{labelwidth} at the current level, % separated by the value of the key \mykey{mark-sep} and aligned by % the value of the key \mykey{mark-pos}. This key is not affected by the % keys \mykey{font} or \mykey{wrap-label} so if you want to apply % \emph{styling} you have to do it directly, for example: |mark-ans={\textcolor{red}{\textbf{\textasteriskcentered}}|. % % \keyexampcmd{mark-pos}{left \textnormal{\textcolor{lightgray}{\textbar}} right \textnormal{\textcolor{lightgray}{\textbar}} center}{right}[env] % Sets the \emph{aligned} of the \emph{\enquote{symbol}} defined by % \mykey{mark-ans} key for |\anskey| command and \myenv*[no-index]{anskey*} % environment. The \emph{\enquote{symbol}} is aligned in a box with the % same dimensions of the label box defined by \mykey{labelwidth} key % on the current level and separated by the value of the \mykey{mark-sep} % key. % % \keyexampcmd{mark-sep}{rigid length}{labelsep}[env] % Sets the \emph{horizontal space} between the box containing the % \emph{\enquote{symbol}} defined by \mykey{mark-ans} key and the % \emph{mandatory argument} \mymeta{content} passed to the |\anskey| % command and the \mymeta{body} in \myenv*[no-index]{anskey*} environment. % % \keyexampcmd{wrap-ans}{code{} \space\usebox{\hashbox} more code}{\textbackslash{}fbox+\textbackslash{}parbox\{\#1\}}[env] % Wraps the \emph{mandatory argument} \mymeta{content} passed to the |\anskey| % and the \mymeta{body} in \myenv*[no-index]{anskey*} environment referenced by |{#1}| % when using the \mykey{show-ans} or \mykey{show-pos} keys. % The \mymarg{code} must be passed between braces and only affects how the % \mymeta{content} or \mymeta{body} is displayed and NOT the \emph{\enquote{stored % content}} in the \emph{sequence} and \emph{prop list} \mymarg{store % name} set by \mykey{save-ans} key. If this key is passed using % |\setenumext| it is necessary to use double `|{##1}|'. % % \subsubsection*{Keys for \texttt{keyans}, \texttt{keyans*} and \texttt{keyanspic}} % % \keyexampcmd{mark-ans\textcolor{star}{*}}{symbol}{\textbackslash{}textasteriskcentered}[env] % Sets the \emph{symbol} to be displayed in the left margin for % |\item*| and |\anspic*| for the \myenv*[no-index]{keyans}, \myenv*[no-index]{keyans*} % and \myenv*[no-index]{keyanspic} environments when using the key \mykey{show-ans}. % The \emph{\enquote{symbol}} is placed in a box of width equal to the value of % \mykey{labelwidth} of the environment in which it is executed, separated by the value of the % key \mykey{mark-sep*} and aligned by the value of the key % \mykey{mark-pos*}. This key is not affected by the keys \mykey{font} or % \mykey{wrap-label} so if you want to apply \emph{styling} you have to do it % directly, for example: |mark-ans*={\textcolor{red}{\textbf{\textasteriskcentered}}|. % % \keyexampcmd{mark-pos\textcolor{star}{*}}{left \textnormal{\textcolor{lightgray}{\textbar}} right \textnormal{\textcolor{lightgray}{\textbar}} center}{right}[env] % Sets the \emph{aligned} of the \emph{\enquote{symbol}} defined by % \mykey{mark-ans*} key for the \myenv*[no-index]{keyans}, \myenv*[no-index]{keyans*} % and \myenv*[no-index]{keyanspic} environments. The \emph{\enquote{symbol}} is % aligned in a box with the same dimensions of the label box defined by % \mykey{labelwidth} key of the environment in which it is executed and % separated by the value of the \mykey{mark-sep*} key. % % \keyexampcmd{mark-sep\textcolor{star}{*}}{rigid length}{labelsep}[env] % Sets the \emph{horizontal space} between the box containing the % \emph{\enquote{symbol}} defined by \mykey{mark-ans*} key and the current \mymeta{label} for % |\item*| and |\anspic*| in the \myenv*[no-index]{keyans}, \myenv*[no-index]{keyans*} % and \myenv*[no-index]{keyanspic} environments. % % \keyexampcmd{wrap-ans\textcolor{star}{*}}{code{} \space\usebox{\hashbox} more code}{not used}[env] % Wraps the \emph{current} \mymeta{label} when using the \mykey{show-ans} % key for |\item*| and |\anspic*| referenced by |{#1}| in the % \myenv*[no-index]{keyans}, \myenv*[no-index]{keyans*} and \myenv*[no-index]{keyanspic} environments % after executing the \mykey{align} and \mykey{font} keys. % The \mymarg{code} must be passed between braces and \emph{only} affects % how the \mymeta{label} is displayed and NOT the \emph{\enquote{stored label}} % in the \emph{sequence} and \emph{prop list} \mymarg{store name} set by % \mykey{save-ans} key. This key overwrites the key \mykey{wrap-label} % and if is passed using |\setenumext| it is necessary to use double `|{##1}|'. % For example, if you want the \mymeta{label} to be displayed in red when % using \mykey{show-ans} you just set |wrap-ans*={\textcolor{red}{#1}}|. % % \keyexampcmd{wrap-opt}{code{} \space\usebox{\hashbox} more code}{[\{\#1\}]}[env] % Wraps the \emph{optional argument} passed to the % |\item*| and |\anspic*| referenced by |{#1}| % in the \myenv*[no-index]{keyans}, \myenv*[no-index]{keyans*} and \myenv*[no-index]{keyanspic} % environments when using the \mykey{show-ans} or \mykey{show-pos} keys. % The \mymarg{code} must be passed between braces % and only affects the current \emph{optional argument} and NOT the % \emph{\enquote{stored content}} in the \emph{sequence} and \emph{prop list} % \mymarg{store name} set by \mykey{save-ans} key. % If this key is passed using |\setenumext| it is necessary to use double `|{##1}|'. % % \subsubsection{Keys for debug and checking} % % \keyexampcmd{show-pos}{true \textnormal{\textcolor{lightgray}{\textbar}} false}{false}[env] % % Displays the \emph{position} occupied by the \emph{\enquote{stored content}} by % |\anskey|, \myenv*[no-index]{anskey*}, |\item*| and |\anspic*| in the % \emph{prop list} \mymarg{store name} set by \mykey{save-ans} key. % This position is used by the |\getkeyans| command and by the |\ref| % command if the \mykey{save-ref} key is active. % % \keyexampcmd{check-ans}{true \textnormal{\textcolor{lightgray}{\textbar}} false}{false}[env] % % Enables the \emph{checking answer} mechanism: a warning is shown on the % terminal when the number of items and answers differ, and the result is written % to the |.log| file. This key works under the logic % that each |\item| or |\item*| that does not open an % inner level or nested environment contains \emph{\enquote{only one % answer}} or \emph{\enquote{only one execution}} of the |\anskey| % or \myenv*[no-index]{anskey*}. It is intended to be used in conjunction with the % \mykey{no-store} key. % % \subsection{The command \cs[no-index]{anskey}}\label{subsec:anskey-cmd} % % \begin{function}{\anskey} % \begin{syntax} % \cmdexamp{anskey}[keys]{content} % \end{syntax} % The command \ics*{anskey} takes a mandatory non empty argument \mymarg{content} % and \emph{\enquote{stores}} it in the \emph{sequence} and \emph{prop % list} \mymarg{store name} set by \mykey{save-ans} key. % By design the command cannot be nested or passed \emph{verbatim material} in the % argument and it is assumed that each \emph{numbered} |\item| or |\item*| within the % environment in which it is active it has a \emph{\enquote{single % execution}} of |\anskey| unless |\item| or |\item*| open a nested level % or use the \mykey{no-store} key. % % If \mykey{save-ref} key are active and the % \mypkg[no-index]{hyperref}\cite{hyperref} package is detected, |\hyperlink| and % |\hypertarget| will be used, otherwise the usual \emph{\enquote{label % and ref}} system provided by \hologo{LaTeX} will be used. % \end{function} % % The |\anskey| command is available for all levels of the % \myenv*[no-index]{enumext} environment and the \myenv*[no-index]{enumext*} environment, but % is disabled for the \myenv*[no-index]{keyans}, \myenv*[no-index]{keyans*} and % \myenv*[no-index]{keyanspic} environments. % % \subsubsection{Keys for \cs[no-index]{anskey}} % % By default the \emph{mandatory argument} \mymeta{content} passed to |\anskey| % when \emph{\enquote{storing}} in the \emph{sequence} \mymarg{store name} % has the form |\item| \mymeta{content}, the following \mymeta{keys} allow % modifying the way in which it is \emph{\enquote{stored}} in the \emph{sequence}. % % \keyexampcmd*{break-col}{value forbidden}{not used}[anskey,anskey*] % % Stores \mymarg{content} in the \emph{sequence} \mymarg{store name} of % the form |\columnbreak| |\item| \mymeta{content}. % % \keyexampcmd{item-join}{columns}{not set}[anskey,anskey*] % % Set the \emph{number of columns} to be used for |\item|\myparg{columns} and stores \mymarg{content} in the \emph{sequence} % \mymarg{store name} of the form |\item|\myparg{columns} \mymeta{content}. % % \keyexampcmd*{item-star}{value forbidden}{not used}[anskey,anskey*] % % Stores \mymarg{content} in the \emph{sequence} \mymarg{store name} of % the form |\item*| \mymeta{content}. % % \keyexampcmd{item-sym\textcolor{star}{*}}{symbol}{not set}[anskey,anskey*] % % Sets the \emph{symbol} for |\item*| when using the key % \mykey[anskey,anskey*]{item-star} and stores \mymarg{content} in the \emph{sequence} % \mymarg{store name} of the form |\item*|\myoarg{symbol} \mymeta{content}. % The \emph{symbol} can be in text or math mode, for example % \mykey[anskey,anskey*]{item-sym*}|={$\ast$}| stores |\item*[$\ast$]| \mymeta{content}. % % \keyexampcmd{item-pos\textcolor{star}{*}}{rigid length}{not set}[anskey,anskey*] % Sets the \emph{offset} for |\item*| when using the keys % \mykey[anskey,anskey*]{item-star} and \mykey[anskey,anskey*]{item-sym*} and stores \mymarg{content} in the \emph{sequence} % \mymarg{store name} of the form |\item*|\myoarg{symbol}\myoarg{offset} \mymeta{content}. % % \subsubsection*{Example} % % \iffalse %<*example> % \fi \begin{examplecode}[frame=single] \begin{enumext}[save-ans=test,show-ans=true] \item* Text containing our instructions or questions. `\ics*{anskey}\mymarg{first answer}` \item Text containing our instructions or questions. \begin{enumext} \item Question.`\ics*{anskey}\mymarg{second answer}` \end{enumext} \item Text containing our instructions or questions. `\ics*{anskey}\mymarg{third answer}` \item Text containing our instructions or questions. `\ics*{anskey}\mymarg{fourth answer}` \end{enumext} \end{examplecode} % \iffalse % % \fi % % \begin{enumext}[save-ans=test,mark-ans={\oldtextasteriskcentered},show-ans=true,columns=2,nosep] % \item* Text containing our instructions or questions.\anskey{first answer} % \item Text containing our instructions or questions. % \begin{enumext} % \item Question.\anskey{second answer} % \end{enumext} % \item Text containing our instructions or questions. \anskey{third answer} % \item Text containing our instructions or questions. \anskey{fourth answer} % \end{enumext} % % \subsection{The environment \env{anskey*}}\label{subsec:anskey-env} % % \begin{function}{anskey*} % \begin{syntax} % |\begin{anskey*}|\myoarg{key \textnormal{\textcolor{gray}{=}} val} \mymeta{body content} |\end{anskey*}| % \end{syntax} % The environment \myenv*{anskey*} takes a mandatory \mymarg{body content} % and \emph{\enquote{stores it}} in the \emph{sequence} and \emph{prop % list} \mymarg{store name} set by \mykey{save-ans} key. If \mykey{save-ref} % key are active and the \mypkg[no-index]{hyperref}\cite{hyperref} package is % detected |\hyperlink| and |\hypertarget| will be used, otherwise the % usual \emph{\enquote{label and ref}} system provided by \hologo{LaTeX} will be used. % \end{function} % % By design the environment cannot be nested but full supports % \emph{\enquote{verbatim material}} in the \mymeta{body} and it is assumed % that \emph{\enquote{each numbered}} |\item| or |\item*| within the % environment in which it is active it has a \emph{\enquote{single % execution}} unless |\item| or |\item*| open a nested level % or use the \mykey{no-store} key. % % The \myenv*[no-index]{anskey*} environment is implemented using the new % \emph{\enquote{collect code}} \texttt{c-type} argument % part of \hologo{LaTeX} release 2025-06-01\cite{ltnews}. % |\begin{anskey*}| and |\end{anskey*}| must be in different lines and % should not appear within verbatim environments or commands. All \mymeta{keys} % must be passed separated by commas and \enquote{without separation} % of the start of the environment. % % Comments `\textcolor{gray}{\texttt{\%}}' or \emph{any character} % after |\begin{anskey*}| or \myoarg{key \textnormal{\textcolor{gray}{=}} val} % on the same line are NOT supported, \hologo{LaTeX} will return an % \enquote{error} message if this happens. In a similar way comments % `\textcolor{gray}{\texttt{\%}}' or \emph{any character} after % |\end{anskey*}| on the same line \hologo{LaTeX} will % return a \enquote{warning} message. % % \subsubsection{Keys for \texttt{anskey*}} % % The \myenv*[no-index]{anskey*} environment uses the same \mymeta{keys} as the % |\anskey| command next to the \mymeta{keys} \mykey{write-env}, \mykey{overwrite} % and \mykey{force-eol}. The environment is available for all levels of the % \myenv*[no-index]{enumext} environment and the \myenv*[no-index]{enumext*} environment, but % it is disabled for the \myenv*[no-index]{keyans}, \myenv*[no-index]{keyans*} and % \myenv*[no-index]{keyanspic} environments. % % \keyexampcmd{write-env}{file.ext}{not used}[anskey*] % % Sets the \emph{name} of the \mymeta{external file} in which the \mymeta{contents} of % the environment will be written. The \mymeta{file.ext} will be created % in the working directory, relative or absolute paths are not supported. If \mymeta{file.ext} % does not exist, it will be created or overwritten if the \mykey{overwrite} key is used. % % \keyexampcmd{overwrite}{true \textnormal{\textcolor{lightgray}{\textbar}} false}{false}[anskey*] % Sets whether the \mymeta{file.ext} generated by \mykey{write-env} % from the \myenv*[no-index]{anskey*} environment will be rewritten. % % \keyexampcmd{force-eol}{true \textnormal{\textcolor{lightgray}{\textbar}} false}{false}[anskey*] % % Sets if the \emph{last end of line} for the \mymeta{stored content} is hidden or not. % This key is necessary only if the last line is the closing of some % environment defined by the \mypkg{fancyvrb} package as |\end{|\myenv[no-index]{Verbatim}|}| % or another environment that does not support a comments `\textcolor{gray}{\texttt{\%}}' % after closing |\end{|\myenv[no-index]{Verbatim}|}%|. % % \subsubsection*{Example} % % \iffalse %<*example> % \fi \begin{examplecode}[frame=single] \begin{enumext}[save-ans=test,show-pos=true,start=5] \item* Text containing our instructions or questions. \begin{anskey*}[item-star] `\mymeta{first answer}` \end{anskey*} \item Text containing our instructions or questions. \begin{enumext} \item Question. \begin{anskey*} `\mymeta{second answer}` \end{anskey*} \end{enumext} \item Text containing our instructions or questions. \begin{anskey*} `\mymeta{third answer}` \end{anskey*} \item Text containing our instructions or questions. \begin{anskey*} `\mymeta{fourth answer}` \end{anskey*} \end{enumext} \end{examplecode} % \iffalse % % \fi % % \begin{enumext}[save-ans=test,show-pos=true,columns=2,nosep,start=5] % \item* Text containing our instructions or questions. % \begin{anskey*} % First answer with \verb+verbatim+ % \end{anskey*} % \item Text containing our instructions or questions. % \begin{enumext} % \item Question.\anskey{second answer} % \end{enumext} % \item Text containing our instructions or questions. \anskey{third answer} % \item Text containing our instructions or questions. \anskey{fourth answer} % \end{enumext} % % \subsection[The environment \texttt{keyans}]{The environments \env{keyans} and \env{keyans*}}\label{subsec:keyans} % % \begin{function}{keyans,keyans*} % \begin{syntax} % |\begin{keyans}|\myoarg{key \textnormal{\textcolor{gray}{=}} val} |\item| |\item|\myoarg{custom} |\item*| |\item*|\myoarg{content} |\end{keyans}|\par % |\begin{keyans*}|\myoarg{key \textnormal{\textcolor{gray}{=}} val} |\item| |\item|\myoarg{custom} |\item*| |\item*|\myoarg{content} |\end{keyans*}| % \end{syntax} % The \myenv*{keyans} and \myenv*{keyans*} environments are % \emph{\enquote{enumerated list}} environments designed for % \emph{\enquote{multiple choice}} questions activated by the \mykey{save-ans} key. % % This environments can NOT be nested and must always be at the % \emph{\enquote{first level}} of the \myenv*[no-index]{enumext} environment, the % commands |\item| and |\item|\myoarg{custom} work in the usual % and the command |\item|\myparg{columns} is available for the \myenv*[no-index]{keyans*} environment. % % \begin{important}* % The behavior of |\item*| in \myenv*[no-index]{keyans} and \myenv*[no-index]{keyans*} environments % is NOT the same as in the \myenv*[no-index]{enumext} or \myenv*[no-index]{enumext*} environments. % \end{important} % \end{function} % % \iffalse %<*example> % \fi \vspace*{-1\baselineskip} \begin{minipage}[t]{0.45\linewidth} \begin{examplecode}[frame=none] \begin{enumext}[save-ans=test] \item `\mymeta[type=tt,ac=lightgray,cf=gray]{item content}` \begin{keyans}`\myoarg{key \textnormal{\textcolor{gray}{=}} val}` \item `\mymeta[type=tt,ac=lightgray,cf=gray]{item content}` \item `\myoarg{custom} \mymeta[type=tt,ac=lightgray,cf=gray]{item content}` \item* `\mymeta[type=tt,ac=lightgray,cf=gray]{item content}` `\ics*{item*}\myoarg{content} \mymeta[type=tt,ac=lightgray,cf=gray]{item content}` \end{keyans} \end{enumext} \end{examplecode} \end{minipage} \hfill \begin{minipage}[t]{0.45\linewidth} \begin{examplecode}[frame=none] \begin{enumext}[save-ans=test] \item `\mymeta[type=tt,ac=lightgray,cf=gray]{item content}` \begin{keyans*}`\myoarg{key \textnormal{\textcolor{gray}{=}} val}` \item `\mymeta[type=tt,ac=lightgray,cf=gray]{item content}` \item `\myoarg{custom} \mymeta[type=tt,ac=lightgray,cf=gray]{item content}` \item* `\mymeta[type=tt,ac=lightgray,cf=gray]{item content}` `\ics*{item*}\myoarg{content} \mymeta[type=tt,ac=lightgray,cf=gray]{item content}` \end{keyans*} \end{enumext} \end{examplecode} \end{minipage} % \iffalse % % \fi % % The \mymeta{keys} set in the \emph{optional argument} of the environment are the same % (almost) as those of the \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} % environments and have \emph{higher precedence} than those set by % |\setenumext|\myoarg{keyans}\mymarg{key \textnormal{\textcolor{gray}{=}} val} or % |\setenumext|\myoarg{keyans\textnormal{\textcolor{star}{\texttt{*}}}}\mymarg{key \textnormal{\textcolor{gray}{=}} val}. % If the \emph{optional argument} is not passed or the \mymeta{keys} % are not set by |\setenumext|, the default values will be the same % as the \emph{\enquote{second level}} of the \myenv*[no-index]{enumext} environment % with the difference in the \mymeta{label} which will be set to \mykey{label}=\ilabel[no-index]{Alph*)}. % % The keys \mykey{mark-ans*}, \mykey{mark-pos*}, \mykey{mark-sep*}, \mykey{save-sep}, % \mykey{wrap-opt}, \mykey{wrap-ans*}, \mykey{show-ans} and \mykey{show-pos} % are available for both environments. % % \subsubsection[The \texttt{\textbackslash item*} in \texttt{keyans}]{The \cs[no-index]{item*} in \texttt{keyans} and \texttt{keyans*}} % % \begin{function}[label={}]{\item*} % \begin{syntax} % |\item*| % |\item*|\myoarg{content} % \end{syntax} % The \ics*{item*} and |\item*|\myoarg{content} command \emph{\enquote{store}} % the current \mymeta{label} set by \mykey{label} key next to the \emph{optional argument} \mymeta{content} % in \emph{sequence} and \emph{prop list} \mymarg{store name} set by % \mykey{save-ans} key in the \emph{\enquote{first level}} of the % \myenv*[no-index]{enumext} or \myenv*[no-index]{enumext*} environments. % \end{function} % % The \emph{starred argument} `|*|' cannot be separated by spaces `\verb*| |' % from the command, i.e. |\item*| and the \emph{optional argument} % does \enquote{NOT} support \emph{verbatim content}. By design it is % assumed that the |\item*| will only appear \emph{\enquote{once}} % within the environment. % % \subsubsection*{Example} % % \iffalse %<*example> % \fi \begin{examplecode}[frame=single] \begin{enumext}[save-ans=test,columns=2,show-ans=true] \item Text containing a question. \begin{keyans*}[nosep,columns=2] \item Choice \item* Correct choice \item Choice \item Choice \item Choice \end{keyans*} \item Text containing a question and image. \begin{keyans}[nosep,mini-env={0.4\linewidth}] \item Choice \item Choice \item Choice \item Choice `\ics*{item*}\myoarg{note}` Correct choice \miniright \includegraphics[scale=0.25]{example-image-a} Some text \end{keyans} \end{enumext} \end{examplecode} % \iffalse % % \fi % % \begin{enumext}[save-ans=test,mark-ans*={\oldtextasteriskcentered},show-ans=true,columns=2,nosep] % \item Text containing a question. % % \begin{keyans*}[nosep,columns=2] % \item Choice % \item* Correct choice % \item Choice % \item Choice % \item Choice % \end{keyans*} % % \item Text containing a question and image. % % \begin{keyans}[nosep,mini-env={0.4\linewidth}] % \item Choice % \item Choice % \item Choice % \item Choice % \item*[note] Correct choice % \miniright % \includegraphics[scale=0.15]{example-image-a} % % Some text % \end{keyans} % \end{enumext} % % \subsection{The environment \texttt{keyanspic}}\label{subsec:keyanspic} % % \begin{function}{keyanspic} % \begin{syntax} % |\begin{keyanspic}|\myoarg{key \textnormal{\textcolor{gray}{=}} val} |\anspic*|\myoarg{content}\mymarg{drawing or tabular} |\end{keyanspic}| % \end{syntax} % The \myenv*{keyanspic} environment is an \emph{\enquote{enumerated % list}} environment activated by the \mykey{save-ans} key that has the % same configuration for \emph{\enquote{spacing}} and \mymeta{label} % as the \myenv*[no-index]{keyans} environment that uses the |\anspic| command % instead of |\item|. It is intended for placing \emph{drawings or tabular} % with \mymeta{label} centered \emph{above} or \emph{below} in a \emph{single line} % or \emph{upper and lower} layout style. % % When the \myenv*[no-index]{keyanspic} environment is used \emph{without keys} % the \mymeta{labels} are centered \emph{below} the \emph{drawings % or tabular} in a \emph{single line} layout style. % \end{function} % % A representation of the output can be seen in the figure~\ref{fig:keyanspicdoc}. % % \begin{figure}[ht] % \centering % \begin{tikzpicture}[line cap=round,line join=round,x=0.8cm,y=0.8cm,every node/.style={font=\footnotesize}] % % space above % \draw[color=white] (7.0,6.10) rectangle (17.5,6.5) node[pos=.5,text=black]% % { \textcolor{lightgray}{\texttt{number of drawings or tabular upper}} }; % \draw[color=white] (7.0,4.5) rectangle (17.5,4.9) node[pos=.5,text=black]% % { \mykey{layout-sep} }; %%%[+itemsep] % \draw[color=white] (7.0,2.9) rectangle (17.5,3.3) node[pos=.5,text=black]% % { \textcolor{lightgray}{\texttt{number of drawings or tabular lower}} }; % \draw[<->,color=gray] (2.0,7.0) --node[above,text=keyname]{\vphantom{p}\texttt{labelwidth}} (5.0,7.0); % \draw[<->,color=gray] (5.0,7.0) --node[above,text=keyname]{\texttt{labelsep}} (7.0,7.0); % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (2.0,6.5) rectangle (5.0,6.85);% labelwidth % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (5.0,6.5) rectangle (7.0,6.85);% labelsep % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,6.5) rectangle (17.5,6.85) node[pos=.5,text=black]% % {\begin{tabular}{c} % \textcolor{blue}{\emph{item text above the keyanspic environment}} % \end{tabular}};% item width % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,5.25) rectangle (10.5,6.10) node[pos=.5,text=black]% % {\begin{tabular}{c} % \texttt{above one} \\ % \textcolor{blue}{\emph{drawing or tabular}} % \end{tabular}}; % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,4.9) rectangle (10.5,5.25) node[pos=.5,text=black]% % { \textcolor{blue}{\texttt{label}} }; % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (10.5,5.25) rectangle (14,6.10) node[pos=.5,text=black]% % {\begin{tabular}{c} % \texttt{above two} \\ % \textcolor{blue}{\emph{drawing or tabular}} % \end{tabular}}; % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (10.5,4.9) rectangle (14,5.25) node[pos=.5,text=black]% % { \textcolor{blue}{\texttt{label}} }; % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (14,5.25) rectangle (17.5,6.10) node[pos=.5,text=black]% % {\begin{tabular}{c} % \texttt{above three} \\ % \textcolor{blue}{\emph{drawing or tabular}} % \end{tabular}}; % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (14,4.9) rectangle (17.5,5.25) node[pos=.5,text=black]% % { \textcolor{blue}{\texttt{label}} }; % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,3.65) rectangle (12.25,4.5) node[pos=.5,text=black]% % {\begin{tabular}{c} % \texttt{below one} \\ % \textcolor{blue}{\emph{drawing or tabular}} % \end{tabular}}; % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,3.3) rectangle (12.25,3.65) node[pos=.5,text=black]% % { \textcolor{blue}{\texttt{label}} }; % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (12.25,3.65) rectangle (17.5,4.5) node[pos=.5,text=black]% % {\begin{tabular}{c} % \texttt{below two} \\ % \textcolor{blue}{\emph{drawing or tabular}} % \end{tabular}}; % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (12.25,3.3) rectangle (17.5,3.65) node[pos=.5,text=black]% % { \textcolor{blue}{\texttt{label}} }; % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (2.0,2.55) rectangle (5.0,2.9);% labelwidth % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (5.0,2.55) rectangle (7.0,2.9);% labelsep % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,2.55) rectangle (17.5,2.9) node[pos=.5,text=black]% % {\begin{tabular}{c} % \textcolor{blue}{\emph{item text below the keyanspic environment}} % \end{tabular}};% item width % \end{tikzpicture} % \caption{Representation of the \myenv*{keyanspic} environment with \mykey{layout-sty}=\mymarg{3, 2} in \mypkg*[no-index]{enumext}.} % \label{fig:keyanspicdoc} % \end{figure} % % This environment cannot be nested and must \emph{always} be at the % \emph{\enquote{first level}} of the \myenv*[no-index]{enumext} environment, the % |\item| command is disabled and \mymeta{keys} cannot be set using % |\setenumext|. % % \subsubsection{Keys for \texttt{keyanspic}} % % \keyexampcmd{label-pos}{above \textnormal{\textcolor{lightgray}{\textbar}} below}{below}[env] % % Set the \emph{position} of \mymeta{label} to be centered % \enquote{above} or \enquote{below} \emph{drawings} or \emph{tabular} % when the |\anspic| command is executed. % % \keyexampcmd{label-sep}{rubber length \textnormal{\textcolor{lightgray}{\textbar}} rigid length}{internal adjustment}[env] % % Set the \emph{vertical spacing} between the \mymeta{label} centered % \enquote{above} or \enquote{below} and \emph{drawings} or \emph{tabular} % when running the |\anspic| command. % % \keyexampcmd{layout-sty}{n° upper \textnormal{\textcolor{gray}{,}} n° lower}{not set}[env] % % Set the \emph{number} of \emph{drawings} or \emph{tabular} that will be % distributed \enquote{upper} and \enquote{lower} within the environment % when executing the |\anspic| command. The value must be passed in braces % and if not set or the \mymeta{nº lower} is omitted the \emph{drawings} % or \emph{tabular} will be put on a \emph{single line}. % % \keyexampcmd{layout-sep}{rubber length \textnormal{\textcolor{lightgray}{\textbar}} rigid length}{adjusted parsep from keyans}[env] % % Set the \emph{vertical separation} between the number of % \emph{drawings} or \emph{tabular} placed at the \enquote{upper} and % \enquote{lower} within the environment when executing the |\anspic| % command. Internally adjusts the \mykey{parsep} value taken from the % \myenv*[no-index]{keyans} environment. % % \keyexampcmd{layout-top}{rubber length \textnormal{\textcolor{lightgray}{\textbar}} rigid length}{adjusted topsep from keyans}[env] % % Set the \emph{vertical space} added to both the top and bottom of the environment. % Internally adjust the value of \mykey{topsep} taken from \myenv*[no-index]{keyans} environment. % % The keys \mykey{mark-ans*}, \mykey{mark-pos*}, \mykey{mark-sep*}, \mykey{save-sep}, % \mykey{wrap-opt}, \mykey{wrap-ans*}, \mykey{show-ans} and \mykey{show-pos} % are available for this environment. % % \subsubsection{The command \cs[no-index]{anspic}} % % \begin{function}{\anspic} % \begin{syntax} % \cmdexamp{anspic}{drawing or tabular} % \cmdexamp[*]{anspic}[content]{drawing or tabular} % \end{syntax} % The \ics*{anspic} command takes three arguments, the \emph{starred % argument} `|*|' store the current \mymeta{label} next to the % \emph{optional argument} \mymeta{content} in \emph{sequence} and % \emph{prop list} \mymarg{store name} set by \mykey{save-ans} key. % \end{function} % % The \emph{starred argument} `|*|' cannot be separated by spaces `\verb*| |' % from the command, i.e. |\anspic*| and the \emph{optional argument} % does \enquote{NOT} support \emph{verbatim content}. By design it % is assumed that the \emph{starred argument} `|*|' will only % appear \emph{\enquote{once}} within the environment. % % \subsubsection*{Example} % % \iffalse %<*example> % \fi \begin{examplecode}[frame=single] \begin{enumext}[save-ans=test,show-ans=true,nosep] \item Question with images and labels below. \begin{keyanspic}[layout-sty={3,2}] \anspic{\includegraphics[scale=0.15]{example-image-a}} \anspic{\includegraphics[scale=0.15]{example-image-b}} \anspic{\includegraphics[scale=0.15]{example-image-a}} \anspic{\includegraphics[scale=0.15]{example-image-a}} \anspic*[note]{\includegraphics[scale=0.15]{example-image-a}} \end{keyanspic} \item Question with images and labels above. \begin{keyanspic}[label-pos=above, layout-sty={3,2},layout-sep=0.25cm] \anspic{\includegraphics[scale=0.15]{example-image-a}} \anspic{\includegraphics[scale=0.15]{example-image-b}} \anspic{\includegraphics[scale=0.15]{example-image-a}} \anspic{\includegraphics[scale=0.15]{example-image-a}} \anspic*[note]{\includegraphics[scale=0.15]{example-image-a}} \end{keyanspic} \item Question with images and labels below on a single line. \begin{keyanspic} \anspic{\includegraphics[scale=0.15]{example-image-a}} \anspic{\includegraphics[scale=0.15]{example-image-b}} \anspic{\includegraphics[scale=0.15]{example-image-a}} \anspic{\includegraphics[scale=0.15]{example-image-a}} \anspic*[note]{\includegraphics[scale=0.15]{example-image-a}} \end{keyanspic} \end{enumext} \end{examplecode} % \iffalse % % \fi % % \begin{enumext}[save-ans=test, mark-ans*={\oldtextasteriskcentered},show-ans=true,nosep, before={\setenumext[keyans]{nosep,parsep=5mm}}] % \item Question with images and labels below. % \begin{keyanspic}[layout-sty={3,2}] % \anspic{\includegraphics[scale=0.15]{example-image-a}} % \anspic{\includegraphics[scale=0.15]{example-image-b}} % \anspic{\includegraphics[scale=0.15]{example-image-a}} % \anspic{\includegraphics[scale=0.15]{example-image-a}} % \anspic*[note]{\includegraphics[scale=0.15]{example-image-a}} % \end{keyanspic} % \item Question with images and labels above. % \begin{keyanspic}[label-pos=above, layout-sty={3,2},layout-sep=0.25cm,layout-top=10pt] % \anspic{\includegraphics[scale=0.15]{example-image-a}} % \anspic{\includegraphics[scale=0.15]{example-image-b}} % \anspic{\includegraphics[scale=0.15]{example-image-a}} % \anspic{\includegraphics[scale=0.15]{example-image-a}} % \anspic*[note]{\includegraphics[scale=0.15]{example-image-a}} % \end{keyanspic} % \item Question with images and labels below on a single line. % \begin{keyanspic}[layout-top=10pt] % \anspic{\includegraphics[scale=0.15]{example-image-a}} % \anspic{\includegraphics[scale=0.15]{example-image-b}} % \anspic{\includegraphics[scale=0.15]{example-image-a}} % \anspic{\includegraphics[scale=0.15]{example-image-a}} % \anspic*[note]{\includegraphics[scale=0.15]{example-image-a}} % \end{keyanspic} % \end{enumext} % % \begin{important} % Remember to pass the |alt=|\mymarg{description} key to the |\includegraphics| % command when creating a \emph{tagged} PDF. % \end{important} % % \subsection{Printing stored content}\label{subsec:printing} % % \subsubsection{The command \cs[no-index]{getkeyans}}\label{subsubsec:getkeyans} % % \begin{function}{\getkeyans} % \begin{syntax} % \cmdexamp{getkeyans}{store name \textnormal{\textcolor{red}{:}} position} % \end{syntax} % The command \ics*{getkeyans} prints the \emph{\enquote{stored content}} % in \emph{prop list} \mymarg{store name} defined by % \mykey{save-ans} key in the \mymeta{position} returned by the % \mykey{show-pos} key. % % The \emph{\enquote{stored content}} can only be accessed \emph{after} % it is stored, if \mymarg{store name} does not exist the command % will return an error. % \end{function} % % The form taken by the argument \mymarg{store name \textnormal{\textcolor{red}{:}} position} % is the same as that used to generate the \emph{\enquote{internal % label and ref}} system when \mykey{save-ref} key are active, so to % refer to a \emph{\enquote{stored content}}. For example % |\getkeyans{test:4}| will return the \emph{\enquote{stored content}} % at position |4| of the environment in which the key |save-ans=test| % was set. % % \subsubsection{The command \cs{foreachkeyans}}\label{subsubsec:foreachkeyans} % % \begin{function}{\foreachkeyans} % \begin{syntax} % \cmdexamp{foreachkeyans}[key \textnormal{\textcolor{gray}{=}} val]{store name} % \end{syntax} % \end{function} % % The command \ics*{foreachkeyans} goes through and executes the command |\getkeyans| % on the contents in \emph{prop list} \mymarg{store name}. If you pass without options run % |\getkeyans| on all contents in \emph{prop list} \mymarg{store name}. % % \subsubsection*{Options for command}\label{subsubsec:optcmdforeach} % % \keyexampcmd{sep}{code}{\{; \}}[foreachkeyans] % % Establishes the \emph{separation} between \emph{\enquote{each}} \mymarg{content} stored in \emph{prop list} \mymarg{store name}. % For example, you can use \mykey[foreachkeyans]{sep}|={\\[10pt]}| for vertical separation of stored % contents. % % \keyexampcmd{step}{integer}{\mydim{1}}[foreachkeyans] % % Sets the \emph{step} (increment) applied to the value set by key \mykey[foreachkeyans]{start} % for \emph{\enquote{each}} \mymarg{content} stored in \emph{prop list} \mymarg{store name}. The value must be a % \mymeta{positive integer}. % % \keyexampcmd{start}{integer}{\mydim{1}}[foreachkeyans] % % Sets the \emph{position} of the \emph{prop list} \mymarg{store name} from which execution % will start. The value must be a \mymeta{positive integer}. % % \keyexampcmd{stop}{integer}{\mydim{0}}[foreachkeyans] % % Sets the \emph{position} of the \emph{prop list} \mymarg{store name} from which execution % will finish. The value must be a \mymeta{positive integer}. % % \keyexampcmd{before}{code}{empty}[foreachkeyans] % % Sets the \mymarg{code} that will be executed \mymeta{before} each \mymarg{content} stored % in \emph{prop list} \mymarg{store name}. The \mymarg[type=tt]{code} must be passed between braces. % % \keyexampcmd{after}{code}{empty}[foreachkeyans] % % Sets the \mymarg{code} that will be executed \mymeta{after} each \mymarg{content} stored % in \emph{prop list} \mymarg{store name}. The \mymarg{code} must be passed between braces. % % \keyexampcmd{wrapper}{code{} \space\usebox{\hashbox} more code}{empty}[foreachkeyans] % % Wraps the \mymarg{content} stored in \emph{prop list} \mymarg{store name} referenced by |{#1}|. % The \mymarg{code} must be passed between braces. For example % |\foreachkeyans[wrapper={\makebox[1em][l]{#1}}]|\mymarg{store name}. % % \subsubsection{The command \cs[no-index]{printkeyans}}\label{subsubsec:printkeyans} % % \begin{function}{\printkeyans} % \begin{syntax} % \cmdexamp{printkeyans}{store name} % \cmdexamp{printkeyans}[keys]{store name} % \cmdexamp[*]{printkeyans}[keys]{store name} % \end{syntax} % The command \ics*{printkeyans} prints \emph{\enquote{all stored content}} % in \emph{sequence} \mymarg{store name} defined by \mykey{save-ans} % key placing this inside the \myenv*[no-index]{enumext} or \myenv*[no-index]{enumext*} % environment if the \emph{starred argument} `|*|' is used. % % The \emph{\enquote{stored content}} can only be accessed \emph{after} it is % stored in the \emph{sequence}, if \mymarg{store name} does not exist the % command will return an error. % \end{function} % % The \emph{optional argument} allows managing the \mymeta{keys} in the % \emph{\enquote{first level}} of the environment in which the % \emph{\enquote{stored content}} of the \emph{sequence} \mymarg{store % name} will be printed, if the \emph{starred argument} `|*|' is used it will be % \myenv*[no-index]{enumext*} otherwise \myenv*[no-index]{enumext}. % % The default values for the \emph{\enquote{first level}} are the % same as the default values for the \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} % environments along with the keys |nosep,first=\small,font=\small| and |columns=2|. % For the inner levels of the environment \myenv*[no-index]{enumext} saved in the % \emph{sequence} \mymarg{store name} the default values are the same % as those established for the second, third and fourth levels plus the % keys |nosep,first=\small,font=\small|. If the environment \myenv*[no-index]{enumext*} % is saved within the \emph{sequence} \mymarg{store name} it will have % the same default values plus the keys |nosep,first=\small, font=\small|. % These are the default values of the package: the values set with |\setenumext| % for the environments \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} % do not modify them. % % Since the command encapsulates by default the \myenv*[no-index]{enumext} % environment or the \myenv*[no-index]{enumext*} environment, some % considerations must be taken into account: % %\begin{itemize}[topsep=0pt] % \item If |\printkeyans*|\mymarg{store name} is executed and the \emph{sequence} % \mymarg{store name} already contains any \myenv*[no-index]{enumext*} environment % an error will be returned, since nesting is not possible. % % \item If |\printkeyans*|\mymarg{store name} is executed and the \emph{sequence} % \mymarg{store name} contains any \myenv*[no-index]{enumext} environments, they % will start with the \mymeta{keys} set for the first level unless they % are set in the \emph{optional argument} or \mykey{save-key} is used to modify it. % % \item If |\printkeyans|\mymarg{store name} is executed and the \emph{sequence} % \mymarg{store name} contains any environment \myenv*[no-index]{enumext*}, they % will start with the \mymeta{keys} set by default unless they are set % in the \emph{optional argument} or \mykey{save-key} is used to modify it. %\end{itemize} % % The default values for the \emph{\enquote{first level}} of |\printkeyans| commands and % |\printkeyans*| are established using |\setenumext|\myoarg{print \textnormal{\textcolor{gray}{,}} \textcolor{star}{1}}\mymarg{keys} and % |\setenumext|\myoarg{print\textnormal{\textcolor{star}{\texttt{*}}}}\mymarg{keys}. % % To set the \mymeta{keys} for the environment % \myenv*[no-index]{enumext} \enquote{saved} in the \emph{sequence} \mymarg{store % name}, use |\setenumext|\myoarg{print % \textnormal{\textcolor{gray}{,}} level}\mymarg{keys}, and to % set the \mymeta{keys} for the environment \myenv*[no-index]{enumext*} % \enquote{saved} in the \emph{sequence} \mymarg{store name}, use % |\setenumext|\myoarg{print \textnormal{\textcolor{gray}{,}} % \textnormal{\textcolor{star}{\texttt{*}}}}\mymarg{keys}. % % \subsubsection*{Example} % % \iffalse %<*example> % \fi \begin{examplecode}[frame=single] \begin{enumext}[save-ans=sample,columns=1,show-pos=true,nosep,save-ref=true] \item Factor $3x+3y+3z$. \anskey{$3(x+y+z)$} \item True False \begin{enumext}[nosep] \item \LaTeX2e\ is cool? \anskey{Very True!} \end{enumext} \item Related to Linux \begin{enumext}[nosep] \item You use Linux? \anskey{Yes} \item Rate the following package and class \begin{enumext}[nosep] \item \texttt{xsim} \anskey{very good} \item \texttt{exsheets} \anskey{obsolete} \end{enumext} \end{enumext} \end{enumext} The answer to \ref{sample:4} is \getkeyans{sample:4} and the answers to all the worksheets are as follows: \printkeyans{sample} \end{examplecode} % \iffalse % % \fi % % \begin{enumext}[save-ans=sampleXX,columns=1,show-pos=true,save-ref=true] % \item Factor $3x+3y+3z$. \anskey{$3(x+y+z)$} % \item True False % \begin{enumext}[nosep] % \item \LaTeX2e\ is cool? \anskey{Very True!} % \end{enumext} % \item Related to Linux % \begin{enumext}[nosep] % \item You use Linux? \anskey{Yes} % \item Rate the following package and class % \begin{enumext}[nosep] % \item \texttt{xsim} \anskey{very good} % \item \texttt{exsheets} \anskey{obsolete} % \end{enumext} % \end{enumext} % \end{enumext} % % The answer to \ref{sampleXX:4} is \getkeyans{sampleXX:4} and the answers to % all the worksheets are as follows: % % \printkeyans[columns=1]{sampleXX} % % \newpage % % \section{Full examples} % % Some adapted questions taken from \href{https://tex.stackexchange.com}{TeX-SX} are included as an example. % The source files of the examples can be compiled with the excellent \arara\footnote{The cool \TeX\ automation tool: % \url{https://www.ctan.org/pkg/arara}} tool. % % \subsubsection*{Example 1} % % Adapted from the response given by Enrico Gregorio in \href{https://tex.stackexchange.com/q/461730/7832}{Squares for answer choice options and perfect alignment to mathematical answers}. % \myattachfile*{enumext-exa-1} % % \setenumext[keyans]{label=\Alph*,font=\small,nosep,wrap-label={\fbox{\makebox[\height]{##1}}}} % \begin{enumext}[columns=2,save-ans=sabastiano,itemsep=2pt, topsep=5pt,below*={8pt}] % \item La velocità di \qty{1,00e2}{m/s} espressa in \unit{km/h} è: % % \begin{keyans} % \item \qty{36}{km/h}. % \item* \qty{360}{km/h}. % \item \qty{27,8}{km/h}. % \item \qty{3,60e8}{km/h}. % \end{keyans} % % \item In fisica nucleare si usa l'angstrom (simbolo: % $\qty{1}{\angstrom} = \qty{1e-10}{m}$) e il fermi o femtometro % ($\qty{1}{fm} = \qty{1e-15}{m}$). Qual è la relazione tra queste due % unità di misura? % \begin{keyans} % \item* $\qty{1}{\angstrom}=\qty{1e5}{fm}$. % \item $\qty{1}{\angstrom}=\qty{1e-5}{fm}$. % \item $\qty{1}{\angstrom}=\qty{1e-15}{fm}$. % \item $\qty{1}{\angstrom}=\qty{1e3}{fm}$. % \end{keyans} % % \item La velocità di \qty{1,00e2}{m/s} espressa in \unit{km/h} è: % % \begin{keyans} % \item \qty{36}{km/h}. % \item* \qty{360}{km/h}. % \item \qty{27,8}{km/h}. % \item \qty{3,60e8}{km/h}. % \end{keyans} % % \item In fisica nucleare si usa l'angstrom (simbolo: % $\qty{1}{\angstrom} = \qty{1e-10}{m}$) e il fermi o femtometro % ($\qty{1}{fm} = \qty{1e-15}{m}$). Qual è la relazione tra queste due % unità di misura? % \begin{keyans} % \item* $\qty{1}{\angstrom}=\qty{1e5}{fm}$. % \item $\qty{1}{\angstrom}=\qty{1e-5}{fm}$. % \item $\qty{1}{\angstrom}=\qty{1e-15}{fm}$. % \item $\qty{1}{\angstrom}=\qty{1e3}{fm}$. % \end{keyans} % \end{enumext} % % \printkeyans[columns=1]{sabastiano} % % \subsubsection*{Example 2} % % Adapted from the response given by Florent Rougon in \href{https://tex.stackexchange.com/q/529034/7832}{Multiple choice questions with proposed answers in random order — addition of automatic correction (cross mark)}. % \myattachfile*{enumext-exa-2} % \setenumext[keyans]{label=\Alph*,font=\small,nosep,wrap-label={\mySquared{##1}}} % \begin{enumext}[columns=2,save-ans=sabastiano2,mark-sep*=2pt,mark-ans*={\textcolor{gray}{✔}},save-ref=true,show-ans=true,itemsep=0pt] % \item La velocità di \qty{1,00e2}{m/s} espressa in \unit{km/h} è: % \begin{keyans} % \item \qty{36}{km/h}. % \item* \qty{360}{km/h}. % \item \qty{27,8}{km/h}. % \item \qty{3,60e8}{km/h}. % \end{keyans} % % \item In fisica nucleare si usa l'angstrom (simbolo: % $\qty{1}{\angstrom} = \qty{1e-10}{m}$) e il fermi o femtometro % ($\qty{1}{fm} = \qty{1e-15}{m}$). Qual è la relazione tra queste due % unità di misura? % \begin{keyans} % \item* $\qty{1}{\angstrom}=\qty{1e5}{fm}$. % \item $\qty{1}{\angstrom}=\qty{1e-5}{fm}$. % \item $\qty{1}{\angstrom}=\qty{1e-15}{fm}$. % \item $\qty{1}{\angstrom}=\qty{1e3}{fm}$. % \end{keyans} % % \item La velocità di \qty{1,00e2}{m/s} espressa in \unit{km/h} è: % \begin{keyans} % \item \qty{36}{km/h}. % \item* \qty{360}{km/h}. % \item \qty{27,8}{km/h}. % \item \qty{3,60e8}{km/h}. % \end{keyans} % % \item In fisica nucleare si usa l'angstrom (simbolo: % $\qty{1}{\angstrom} = \qty{1e-10}{m}$) e il fermi o femtometro % ($\qty{1}{fm} = \qty{1e-15}{m}$). Qual è la relazione tra queste due % unità di misura? % \begin{keyans} % \item* $\qty{1}{\angstrom}=\qty{1e5}{fm}$. % \item $\qty{1}{\angstrom}=\qty{1e-5}{fm}$. % \item $\qty{1}{\angstrom}=\qty{1e-15}{fm}$. % \item $\qty{1}{\angstrom}=\qty{1e3}{fm}$. % \end{keyans} % \end{enumext} % % \printkeyans*[columns=2]{sabastiano2} % % \subsubsection*{Example 3} % % A \emph{\enquote{simple multiple choice}} test. % \myattachfile*{enumext-exa-3} % \setenumext[keyans]{labelsep=8pt,label=\Alph*,font=\small,nosep,wrap-label={\myCircled{##1}}} % \begin{enumext}[mode-box,save-ans=simplemc,columns=1,nosep,save-ref=true] % \item First type of questions % \begin{keyans*}[labelsep=8pt,label=\Alph*,font=\small,nosep,wrap-label={\myCircled{#1}},columns=2] % \item value % \item*[$x=5$] correct % \item value % \item value % \end{keyans*} % \item Second type of questions % \begin{enumext}[no-store,label=\Roman*.,nosep] % \item $2\alpha+2\delta=90^{\circ}$ % \item $\alpha=\delta$ % \item $\angle EDF=45^{\circ}$ % \end{enumext} % \begin{keyans}[columns=2,noitemsep] % \item I only % \item II only % \item I and II only % \item* I and III only % \item I, II, and III % \end{keyans} % \item Third type of questions % \begin{enumext}[no-store,list-offset=0.5cm,label=(\arabic*),nosep] % \item $2\alpha+2\delta=90^{\circ}$ % \item $\angle EDF=45^{\circ}$ % \end{enumext} % \begin{keyans}[columns=2,noitemsep] % \item value % \item value % \item*[some note] value % \item value % \item value % \end{keyans} % % \item Question with image and label below: % \begin{keyanspic}[label-sep=3pt] % \anspic{\includegraphics[scale=0.15]{example-image-a}} % \anspic{\includegraphics[scale=0.15]{example-image-b}} % \anspic{\includegraphics[scale=0.15]{example-image-a}} % \anspic{\includegraphics[scale=0.15]{example-image-a}} % \anspic*[A duck]{\includegraphics[scale=0.32]{example-image-duck}} % \end{keyanspic} % % \item Question with image on right side: % \begin{keyans}[mini-env=0.5\linewidth, columns=1,noitemsep] % \item value % \item value % \item value % \item*[other note] correct % \item value % \miniright % \includegraphics[scale=0.15]{example-image-b} % \end{keyans} % \end{enumext} % % Test keys % % \printkeyans[columns=2]{simplemc} % % \subsubsection*{Example 4} % % A \emph{\enquote{simple worksheet}} using ducks :) % \myattachfile*{enumext-exa-4} % % \begin{enumext}[save-ans=simplews,columns=1,check-ans=true,nosep,save-ref=true,wrap-label={\tikz[scale=0.25]\duck[signpost=\scalebox{0.6}{#1}];}] % \item Factor $x^{2}-2x+1$ \anskey{$\left(x-1\right)^{2}$} % \item Factor $3x+3y+3z$ \anskey{$3(x+y+z)$} % \item[] The following questions need to be quantified :) % \item True False % \begin{enumext}[nosep] % \item $\alpha > \delta$ \anskey{False} % \item \LaTeX2e\ is cool? \anskey{Very True!} % \end{enumext} % \item Related to Linux % \begin{enumext}[nosep] % \item You use Linux? \anskey{Yes} % \item Usually uses the package manager? \anskey{Yes, \texttt{dnf}} % \item Rate the following package and class % \begin{enumext}[nosep] % \item \texttt{xsim-exam} \anskey{doesn't exist for now :(} % \item \texttt{xsim} \anskey{very good} % \item \texttt{exsheets} \anskey{obsolete} % \end{enumext} % \end{enumext} % \end{enumext} % % The answer to \ref{simplews:1} is \getkeyans{simplews:1} and the answer % to \ref{simplews:3} is \getkeyans{simplews:3}. % % \printkeyans[columns=2]{simplews} % % \subsubsection*{Example 5} % % Adapted from the response given by Stephen in \href{https://tex.stackexchange.com/a/691544}{SAT like question format}. % \myattachfile*{enumext-exa-5} % \setenumext[keyans]{label=\Alph*),font=\small,nosep,wrap-label={##1}} % \begin{enumext}[label=\arabic*,labelwidth=20pt,labelsep=0pt,columns=2,save-ans=stylesat, wrap-label={\stylesat{#1}}] % \item Which choice best describes what happens in the passage? % \begin{keyans} % \item* One character argues with another character who intrudes on her home. % \item One character receives a surprising request from another character. % \item One character reminisces about choices she has made over the years. % \item One character criticizes another character for pursuing an unexpected course of action. % \end{keyans} % % \item Which choice best describes what happens in the passage? % \begin{keyans} % \item One character argues with another character who intrudes on her home. % \item One character receives a surprising request from another character. % \item* One character reminisces about choices she has made over the years. % \item One character criticizes another character for pursuing an unexpected course of action. % \end{keyans} % % \item Which choice best describes what happens in the passage? % \begin{keyans} % \item One character argues with another character who intrudes on her home. % \item* One character receives a surprising request from another character. % \item One character reminisces about choices she has made over the years. % \item One character criticizes another character for pursuing an unexpected course of action. % \end{keyans} % % \item Which choice best describes what happens in the passage? % \begin{keyans} % \item One character argues with another character who intrudes on her home. % \item One character receives a surprising request from another character. % \item One character reminisces about choices she has made over the years. % \item* One character criticizes another character for pursuing an unexpected course of action. % \end{keyans} % \end{enumext} % % \printkeyans[columns=4]{stylesat} % % \subsubsection*{Example 6} % % Adapted from the response to \href{https://tex.stackexchange.com/q/728584}{Environment for enumerate environment}. % \myattachfile*{enumext-exa-6} % \setenumext[keyans]{label={\Alph*},font={\bfseries},wrap-ans*={\textcolor{red}{\bfseries##1}},mark-ans*={\textcolor{red}{✔}},wrap-opt={ },save-sep={ }} % \showrating{true} % \begin{enumext}[azetinasty,start=10,wrap-label={\azwrapp{#1}},save-ans=test2024] % \item sample % \begin{keyans} % \item sample % \item*[(8.5a, KSC)] answer % \item sample % \item sample % \end{keyans} % \RenewDocumentCommand \rating { }{9.5a, KSC} % \item sample % \begin{keyans} % \item sample % \item sample % \item sample % \item*[(9.5a, KSC)] answer % \end{keyans} % \end{enumext} % \showrating{false} % \RenewDocumentCommand \rating { }{10.5a, KSC} % \begin{enumext}[save-ans=test2024,resume*] % \item sample % \begin{keyans} % \item sample % \item*[(10.5a, KSC)] answer % \item sample % \item sample % \end{keyans} % \RenewDocumentCommand \rating { }{11.5a, KSC} % \item sample % \begin{keyans} % \item sample % \item sample % \item sample % \item*[(11.5a, KSC)] answer % \end{keyans} % \end{enumext} % \printkeyans[start=10]{test2024} % % \section{Tagged PDF examples} % % This section is just to show the compatibility of \mypkg*[no-index]{enumext} with % \emph{tagged} \texttt{PDF} using |lualatex|. The files described below % are just for testing and are intended as examples and, in a way, to % simplify the time of Matthew Bertucci (\texttt{@mbertucci}) when he sees this % excellent package and adds it to \href{https://github.com/latex3/tagging-project}{The LaTeX Tagged PDF repository}. % % To compile the tests with |lualatex-dev| the packages \mypkg[no-index]{multicol}, % \mypkg{unicode-math}, \mypkg{geometry}, \mypkg{graphicx}, \mypkg{luamml} % and \mypkg[no-index]{hyperref} are required along with the line: % % \iffalse %<*example> % \fi \begin{examplecode}[frame=single] \DocumentMetadata{lang = en-US, pdfversion = 2.0, pdfstandard = `\mydim{ua-2}`, tagging=on,} \end{examplecode} % \iffalse % % \fi % % \begin{important} % All examples have been checked using \href{https://dev.verapdf-rest.duallab.com}{\texttt{veraPDF}} % together with \href{https://ngpdf.com}{\texttt{ngpdf}}. % \end{important} % % \begin{itemize}[topsep=1pt,partopsep=0pt,parsep=1pt,itemsep=1pt] % \item The file \myfile{enumext-01.tex} contains the basic tests for the % \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} environments and the nesting % between them plus the use of the \mykey{label}, \mykey{labelwidth}, % \mykey{labelsep}, \mykey{ref}, \mykey{align} and \mykey{wrap-label} keys. % \myattachfile{enumext-01} % % \item The file \myfile{enumext-02.tex} contains the tests for the \myenv*[no-index]{enumext} % and \myenv*[no-index]{enumext*} environments and the support for \myenv[no-index]{minipage} % and \myenv[no-index]{multicols} environments using the keys \mykey{columns}, % \mykey{columns-sep}, \mykey{mini-env}, \mykey{mini-right} and % |\miniright| command. % \myattachfile{enumext-02} % % \item The file \myfile{enumext-03.tex} contains the tests for the \myenv*[no-index]{enumext} % and \myenv*[no-index]{keyanspic} environments activated by the \mykey{save-ans} % key together with the \mykey{save-sep} and \mykey{save-ref} keys and % the |\printkeyans| command. % \myattachfile{enumext-03} % % \item The file \myfile{enumext-04.tex} contains the tests for the |\anskey| % command and the \myenv*[no-index]{anskey*} environment activated by the % \mykey{save-ans} key along with the |\getkeyans| and |\printkeyans| commands. % \myattachfile{enumext-04} % % \item The file \myfile{enumext-05.tex} contains the tests for the environments % \myenv*[no-index]{keyans}, \myenv*[no-index]{keyans*} and \myenv*[no-index]{keyanspic} activated by the key % \mykey{save-ans} together with the keys \mykey{no-store} and \mykey{show-ans} % and the commands |\setenumext|, |\setenumextmeta|, |\printkeyans| and |\foreachkeyans|. % \myattachfile{enumext-05} % % \item The file \myfile{enumext-06.tex} contains the tests for the environments % \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} for \emph{fake} \myenv[no-index]{itemize} and \myenv[no-index]{description}. % \myattachfile{enumext-06} % % \item The file \myfile{enumext-07.tex} contains the tests for starting the % environments with |\setenumext{resume}|, the |\resetenumext| command % and the \mykey{series}, \mykey{resume}, \mykey{resume*} and \mykey{reset} keys. % \myattachfile{enumext-07} % \end{itemize} % % \section{The way of non-enumerated lists} % % It is possible to use (or abuse) the \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} environments to % mimic \emph{non-enumerated} list environments such as \myenv[no-index]{itemize} and % \myenv[no-index]{description}, clearly the \mymeta{keys} to \emph{\enquote{store answers}}, % the \myenv*[no-index]{keyans}, \myenv*[no-index]{keyans*} and \myenv*[no-index]{keyanspic} environments lose their % sense and it is not the focus of \mypkg*[no-index]{enumext} package, but, why not % to do it?. % % Other uses of the \myenv*[no-index]{enumext} environment that can be helpful for % specific purposes are shown as examples. The \emph{trick} % to generate these \emph{\enquote{fake environments}} is to set \mykey{label}|={}| % or \mykey{label}|=|\mymarg{some} and play with the \mykey{list-indent}, \mykey{list-offset}, % \mykey{font} and \mykey{wrap-label} keys. % % \subsection*{Fake \texttt{itemize} environment}\label{subsec:fake-itemize} % % The \mykey{label} key is set here using the default settings in % \hologo{LaTeX} for the four levels |\textbullet|, |\textendash|, |\textasteriskcentered| % and |\textperiodcentered| together with the % \mykey{nosep} key to reduce the vertical spaces in the left side example and set the % \mykey{label} key in \emph{mathematical mode} for the right side as % |\ast|, |\diamond|, |\circ| and |\star| for the four levels % together with the \mykey{nosep} key % % \noindent\begin{minipage}[t]{0.45\linewidth} % \begin{enumext}[nosep, label=\textbullet] % \item First level item % \begin{enumext}[nosep,label=\normalfont\bfseries\textendash] % \item Second level item % \begin{enumext}[nosep,label=\textasteriskcentered] % \item Third level item % \begin{enumext}[nosep,label=\textperiodcentered] % \item Fourth level item % \end{enumext} % \end{enumext} % \end{enumext} % \item First level item % \end{enumext} % \end{minipage}\hfill % \begin{minipage}[t]{0.45\linewidth} % \begin{enumext}[nosep, label=$\ast$] % \item First level item % \begin{enumext}[nosep,label=$\diamond$] % \item Second level item % \begin{enumext}[nosep,label=$\circ$] % \item Third level item % \begin{enumext}[nosep,label=$\star$] % \item Fourth level item % \end{enumext} % \end{enumext} % \end{enumext} % \item First level item % \end{enumext} % \end{minipage} % % \subsection*{Fake \texttt{description} environment}\label{subsec:fake-description} % % Here \mykey{label}|={}| and |list-indent=2.5em,font=\bfseries| are set. % % \begin{enumext}[label={},list-indent=2.5em,font=\bfseries,noitemsep,topsep=3pt] % \item[SomeThing] A short one-line description. % \item[] This is an entry \emph{without} a label. % \item[Something] A short \emph{one-line} description text. % \item[Something long] A much \emph{longer} description text may take % more than one line or more than one paragraph. % % Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod % tempor incididunt ut labore et dolore magna aliqua. % \end{enumext} % % Adding |list-indent=0pt| gives the \emph{widest style}: % % \begin{enumext}[label={},list-indent=0pt,font=\bfseries,noitemsep,topsep=3pt] % \item[SomeThing] A short one-line description. % \item[] This is an entry \emph{without} a label. % \item[Something] A short \emph{one-line} description text. % \item[Something long] A much \emph{longer} description text may take % more than one line or more than one paragraph. % % Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod % tempor incididunt ut labore et dolore magna aliqua. % \end{enumext} % % \begin{important}* % The small space at the beginning of the \emph{\enquote{unlabeled entry}} corresponds to % |\labelsep| and can be removed using |\hspace{-\labelsep}| at the % beginning of the line. % \end{important} % % \begin{important} % When \emph{tagged} PDF is active the default \myenv[no-index]{description} style % is NOT available due to the redefinition of |\makelabel| for the % \mykey{align} key which uses |\makebox| in this case, meaning that % |\item|\myoarg{content} will not extend beyond |\labelwidth| which % causes overlaps, % \end{important} % % \subsection*{Description indented by label}\label{subsec:description-indented} % % Here \mykey{label}|={}| is set and a convenient value is given to % \mykey{labelsep} and \mykey{labelwidth}, for example taking the % \emph{longest label} as reference and passing it as value using: % % \iffalse %<*example> % \fi \begin{examplecode}[frame=none] \newlength{\descitemwd} \settowidth{\descitemwd}{\textbf{Something long}} \end{examplecode} % \iffalse % % \fi % % and then use \mykey{labelsep}|=4pt,|\mykey{labelwidth}|=\descitemwd,font=\bfseries|. % % \newlength{\descitemwd} % \settowidth{\descitemwd}{\textbf{Something long}} % \begin{enumext}[label={},labelsep=4pt,labelwidth=\descitemwd,font=\bfseries,noitemsep,topsep=3pt] % \item[SomeThing] A short one-line description. % \item[] This is an entry \textit{without} a label. % \item[Something] A short one-line description. % \item[Something long] A much longer description. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. % Ut purus elit, vestibulum ut, placerat ac, adipiscing vitae, felis. % Curabitur dictum gravida mauris. % \end{enumext} % % The environment can be translated so that the \mymeta{labels} are on % the left margin calculating the value passed to the \mykey{list-offset} % key, in this case it will be equal to the sum of the values set by the % \mykey{labelwidth} and \mykey{labelsep} keys finally resulting as % \mykey{list-offset}|={-\descitemwd - 4pt}|. % % \begin{enumext}[label={},labelsep=4pt,labelwidth=\descitemwd,list-offset={-\descitemwd-4pt}, font=\bfseries,noitemsep,topsep=3pt] % \item[SomeThing] A short one-line description. % \item This is an entry \textit{without} a label. % \item[Something] A short one-line description. % \item[Something long] A much longer description. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. % Ut purus elit, vestibulum ut, placerat ac, adipiscing vitae, felis. % Curabitur dictum gravida mauris. % \end{enumext} % % Adding \mykey{align}|=right| gives: % % \begin{enumext}[label={},align=right,labelsep=4pt,labelwidth=\descitemwd,list-offset={-\descitemwd - 4pt}, font=\bfseries,noitemsep,topsep=3pt] % \item[SomeThing] A short one-line description. % \item This is an entry \textit{without} a label. % \item[Something] A short one-line description. % \item[Something long] A much longer description. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. % Ut purus elit, vestibulum ut, placerat ac, adipiscing vitae, felis. % Curabitur dictum gravida mauris. % \end{enumext} % % \begin{important}* % At this point \mykey{list-offset}|={-\descitemwd - 4pt}| instead of % |list-offset={-\labelwidth - \labelsep}|, % this is because the parameters |\labelwidth| and |\labelsep| take the % default values, as if \mykey{label} had not been set. % \end{important} % % \subsection*{Description with multi-line labels}\label{subsec:description-multiline} % % The \mykey{label} key does not accept \emph{multiline material}, this % is where the \mykey{wrap-label} and \mykey{wrap-label*} keys comes into % play. Unlike the \mypkg[no-index]{enumitem} package, the \mykey{align} key only % supports three options, so a command is created in the % style |\parleft| of \mypkg[no-index]{enumitem} that allows placing \emph{multiline labels} % using |\parbox|. % % \iffalse %<*example> % \fi \begin{examplecode}[frame=none] \NewDocumentCommand \labelbx { s +m } {% \SuspendTagging{\parbox}% \IfBooleanTF{#1} {\strut\smash{\parbox[t]{\labelwidth}{\raggedright{#2}}}}% {\strut\smash{\parbox[t]{\labelwidth}{\raggedleft{#2}}}}% \ResumeTagging{\parbox}% } \end{examplecode} % \iffalse % % \fi % % Now it is only necessary to set |wrap-label*={\labelbx{#1}}|. % % \begin{enumext}[mode-box,label={},labelsep=4pt,labelwidth=\descitemwd,list-offset=-\dimeval{\descitemwd+4pt}, wrap-label*={\labelbx{#1}}, font=\bfseries,noitemsep,topsep=3pt] % \item[SomeThing] A short one-line description. % \item This is an entry \textit{without} a label. % \item[Something] A short one-line description. % \item[Something \\ long] A much longer description. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. % Ut purus elit, vestibulum ut, placerat ac, adipiscing vitae, felis. % Curabitur dictum gravida mauris. % % Lorem ipsum dolor sit amet, consectetuer adipiscing elit. % Ut purus elit, vestibulum ut, placerat ac, adipiscing vitae, felis. % Curabitur dictum gravida mauris. % % \item[SoMeThInG \\ LoNg] A much longer description. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. % Ut purus elit, vestibulum ut, placerat ac, adipiscing vitae, felis. % Curabitur dictum gravida mauris. % \end{enumext} % % \section*{Final notes} % % The original implementation (if you can call it that) of the ideas that % led to the creation of \mypkg*[no-index]{enumext} were some macros using the \mypkg{enumerate}\cite{enumerate} % package for personal use created in early 2003, the code was quite % questionable, but functional for these simple requirements. % % With the great answers given by Christian Hupfer in % \href{https://tex.stackexchange.com/a/364763/7832}{Create a fake label ref % using list} and the answer given by David Carlisle in % \href{https://tex.stackexchange.com/a/363963/7832}{Change the use of label % ref by data save in an array (list)} I managed to create a more solid % code than the original version, now using the \mypkg{l3prop}\cite{inter3} and \mypkg{l3seq}\cite{inter3} % modules together with the \mypkg[no-index]{hyperref}\cite{hyperref} and \mypkg[no-index]{enumitem}\cite{enumitem} packages, which did % the job, but with some shortcomings. % % As time went by I took these shortcomings as a personal challenge which % I called \emph{\enquote{reinventing the wheel}}, since there were packages and classes % that did more or less what I was looking for, but did not fit my simple % requirements. This \emph{\enquote{reinventing the wheel}} finally ended up becoming % \mypkg*[no-index]{enumext}. % % \subsubsection*{Why list environments?} % % The answer is simple, first I love the beauty of its syntax and many of % what I had already written used the \myenv[no-index]{enumerate} environment or % lists created using the \mypkg[no-index]{enumitem} package. In my mind I thought: % how complicated could it be to write a package that looked like % \mypkg[no-index]{enumitem}? It seemed simple enough, of course I didn't have in % mind the mess I was getting into working with \myenv[no-index]{list} % environments, \myenv[no-index]{minipage} and adding support for the % \mypkg[no-index]{multicol} and \mypkg[no-index]{hyperref} packages. % % Of course, seeing the final result of the experiment % \emph{\enquote{reinventing the wheel}} I am quite satisfied. % % \subsubsection*{Why not random questions and other utilities} % % The \emph{\enquote{random}} type questions I love and hate them at the % same time, although they simplify a lot the work when creating a % multiple choice test, but you lose the beauty of typesetting a % document with \hologo{LaTeX}, that is to say the output does not always % look as nice as it should, even if they are only alternatives these % must follow a certain order when presented either numerical or % presentation, that said handling that using \emph{nested lists} is quite % complicated so I do not classify to be implemented. % % \subsubsection*{Why has it taken so long?} % % One of the setbacks, beyond my laziness, was including compatibility % with \emph{tagged} \texttt{PDF}. To be honest, it's something I never % considered at any point, but I firmly believe that being able to create % \emph{accessible documents} provides a great opportunity in the world of % mathematics education. From my perspective as a \emph{high school} teacher, % beyond theorems and deep mathematics, the use of exercise lists is one % of the most common things. Being able to open the way to work in % parallel with those who have different abilities is really important % and I regret not having looked into this in the past. I hope that % \mypkg*[no-index]{enumext} serves this purpose and inspires more users and % authors to follow this path. % % \subsubsection*{Regression tests} % % The source repository includes a set of regression tests for \texttt{l3build}, % kept in the \myfile{testfiles} directory. They are run with the % \hologo{LuaTeX} engine and the development format \texttt{latex-dev}, and % each test is compiled twice so that references and labels are resolved before % the log is compared: % % \begin{itemize} % \item \myfile{test-001} and \myfile{test-002}: lists without tagging, with % the labels, the spacing, the nesting, the counters, the series and % \myenv*[no-index]{enumext*}, and the independence between |\setenumext| % and |\printkeyans|; % \item \myfile{test-003}: the keys that set vertical and horizontal spaces, % penalties, the symbol of |\item*|, the code keys \mykey{before}, % \mykey{first} and \mykey{after}, and the \myenv{minipage} keys; % \item \myfile{test-004}: the storage system with |\anskey|, % \myenv*[no-index]{anskey*}, |\printkeyans|, |\getkeyans| and % |\foreachkeyans|, and the keys that store and show the answers; % \item \myfile{test-005}: the environments \myenv*[no-index]{keyans}, % \myenv*[no-index]{keyans*} and \myenv*[no-index]{keyanspic}, their keys and % the standard lists nested in the options of \myenv*[no-index]{keyans*}; % \item \myfile{test-006}: the exact vertical spaces above, below and beside % the \myenv{minipage} and \myenv{multicols} variants (\mykey{mini-env}, % \mykey{mini-right}, |\miniright| and \myenv*[no-index]{multicols}) in % \myenv*[no-index]{enumext}, \myenv*[no-index]{enumext*}, % \myenv*[no-index]{keyans} and \myenv*[no-index]{keyans*}, measured with % boxes, and the closing of the \myenv{minipage} when the content ends in a % character; % \item \myfile{test-010} and \myfile{test-011}: the same lists and the % storage system with |tagging=on|, including the structure tree and the % standard lists and the environments based on \myenv[no-index]{trivlist} % nested in the content of an item of \myenv*[no-index]{enumext*}; % \item \myfile{test-012}: the structure tree with |tagging=on| of the % \myenv{minipage} and \myenv{multicols} variants, where the position of % the figures records the vertical spaces; % \item \myfile{test-013}: the \mykey{base-fix} key, with the baseline of the % nested list measured with boxes for different values of \mykey{parsep}, % \mykey{itemsep} and \mykey{columns}; % \item \myfile{test-014}: the vertical spaces of the environment % \myenv*[no-index]{keyanspic} with the label below and above the figures, % measured with boxes for the keys \mykey[env]{layout-top}, % \mykey[env]{layout-sep} and \mykey[env]{label-sep}; % \item \myfile{test-015}: the standard lists (\myenv[no-index]{itemize}, % \myenv[no-index]{enumerate} and \myenv[no-index]{description}) nested in the % content of an item of \myenv*[no-index]{enumext*}, measured with boxes for % different values of \mykey{columns}, \mykey[env]{item-break} and joined items; % \item \myfile{test-016}: the values of \mykey{labelwidth} and \mykey{labelsep} % inside the nested lists, and the environments \myenv[no-index]{quote}, % \myenv[no-index]{quotation}, \myenv[no-index]{verse}, \myenv[no-index]{list}, % \myenv[no-index]{center}, \myenv[no-index]{trivlist}, \myenv[no-index]{tabbing}, % \myenv[no-index]{verbatim} and the theorems nested in the content of an item % of \myenv*[no-index]{enumext*}, measured with boxes; % \item \myfile{test-100}: the error and warning messages of the package. % \end{itemize} % % From the root of the repository, |l3build check| runs all the tests and % |l3build check test-001| runs a single one. After a deliberate change in the % package, |l3build save test-001| regenerates the reference file % \myfile{test-001.tlg}, which must be reviewed before committing it. % The target |l3build testSE| compiles twice the documents in % \myfile{sources/test-pkg}, validates the tagged structure and copies the % \texttt{PDF} files that are attached to this manual; it is also run by % |l3build release|. % % \let\stdsection\section % \def\section*#1{\stdsection{#1}} % \expandafter\let\expandafter\thebibliography\csname HDorg@thebibliography\endcsname % % \begin{thebibliography}{10} % % \bibitem{multicol} \textsc{Mittelbach, Frank}. \enquote{An % environment for \textsf{multicolumn} output}. Available from % \textsc{ctan}, \url{https://www.ctan.org/pkg/multicol}, 2025. % % \bibitem{exam} \textsc{Hirschhorn, Philip}. \enquote{Using the % \textsf{exam} document class}. Available from % \textsc{ctan}, \url{https://www.ctan.org/pkg/exam}, 2023. % % \bibitem{xsim} \textsc{Niederberger, Clemens}. \enquote{\textsf{xsim} – eXercise % Sheets IMproved}. Available from % \textsc{ctan}, \url{https://www.ctan.org/pkg/xsim}, 2023. % % \bibitem{latexref} \textsc{Berry, Karl}. \enquote{\hologo{LaTeX2e}: An % Unofficial Reference Manual}. Available from \textsc{ctan}, % \url{https://ctan.org/pkg/latex2e-help-texinfo}, 2026. % % \bibitem{enumitem} \textsc{Bezos, Javier}. \enquote{Customizing lists % with the \textsf{enumitem} package}. Available from % \textsc{ctan}, \url{https://www.ctan.org/pkg/enumitem}, 2025. % % \bibitem{footnotehyper} \textsc{Burnol, Jean-François}. \enquote{The \textsf{footnotehyper} % package}. Available from % \textsc{ctan}, \url{https://www.ctan.org/pkg/footnotehyper}, 2025. % % \bibitem{shortlst} \textsc{Lemvig, Mogens}. \enquote{The \textsf{shortlst} % package}. Available from % \textsc{ctan}, \url{https://www.ctan.org/pkg/shortlst}, 1998. % % \bibitem{tasks} \textsc{Niederberger, Clemens}. \enquote{\textsf{tasks} – Horizontally % columned lists}. Available from % \textsc{ctan}, \url{https://www.ctan.org/pkg/tasks}, 2022. % % \bibitem{userguide} The \hologo{LaTeX} Project. \enquote{\hologo{LaTeX} for authors % current version}. Available from % \textsc{ctan}, \url{https://ctan.org/pkg/latex-base}, 2026. % % \bibitem{hyperref} The \hologo{LaTeX} Project. \enquote{Extensive support % for hypertext in \hologo{LaTeX}}. Available from % \textsc{ctan}, \url{https://www.ctan.org/pkg/hyperref}, 2026. % % \bibitem{ltnews} The \hologo{LaTeX} Project. \enquote{\hologo{LaTeX} News, % Issue 41, June 2025}. Available from % \textsc{ctan}, \url{https://ctan.org/tex-archive/macros/latex/base}, 2025. % % \bibitem{enumerate} The \hologo{LaTeX} Project. \enquote{\textsf{enumerate} – Enumerate % with redefinable labels}. Available from % \textsc{ctan}, \url{https://www.ctan.org/pkg/enumerate}, 2025. % % \bibitem{inter3} The \hologo{LaTeX} Project. \enquote{The \hologo{LaTeX}3 % Interfaces}. Available from % \textsc{ctan}, \url{https://www.ctan.org/pkg/l3kernel}, 2026. % % \bibitem{latex2e} The \hologo{LaTeX} Project. \enquote{The \hologo{LaTeX2e} % sources}. Available from % \textsc{ctan}, \url{https://ctan.org/tex-archive/macros/latex/base}, 2026. % % \bibitem{latexlab} The \hologo{LaTeX} Project. \enquote{\textsf{latex-lab} – \hologo{LaTeX} % laboratory}. Available from % \textsc{ctan}, \url{https://www.ctan.org/pkg/latex-lab}, 2026. % % \bibitem{indent} \enquote{\textsf{indent} – Environments that change margins}. % Available from \textsc{ctan}, \url{https://www.ctan.org/pkg/indent}, 1993. % % \bibitem{scontents} \textsc{González, Pablo}. \enquote{\textsf{scontents} - Stores % \hologo{LaTeX} contents in memory or files}. Available from % \textsc{ctan}, \url{https://www.ctan.org/pkg/scontents}, 2026. % % \bibitem{tagpdf} \textsc{Fischer, Ulrike}. \enquote{\textsf{tagpdf} – \hologo{LaTeX} % kernel code for PDF tagging}. Available from % \textsc{ctan}, \url{https://www.ctan.org/pkg/tagpdf}, 2026. % % \bibitem{ltsockets} \textsc{Mittelbach, Frank}. \enquote{\hologo{LaTeX}’s % socket management}. Available from % \textsc{ctan}, \url{https://ctan.org/tex-archive/macros/latex/base}, 2026. % % \bibitem{expl3} The \hologo{LaTeX} Project. \enquote{The \textsf{expl3} % package}. Available from % \textsc{ctan}, \url{https://www.ctan.org/pkg/l3kernel}, 2026. % % \end{thebibliography} % % \let\section\stdsection % % \section{Change history} % \label{sec:changes} % % \setlist[itemize,1]{label=\textendash,leftmargin=*,labelsep=0.5em,nosep,noitemsep} % \newlength\descrwidth % \settowidth{\descrwidth}{\textsf{v1.0, (ctan), 2024-11-01} } % \begin{description}[font=\small\sffamily,wide=0pt,style=multiline,leftmargin=1.1\descrwidth,nosep,noitemsep] % \item [\fileversion{} (ctan), \filedate] % \begin{itemize} % \item New key \mykey{item-break} for \myenv*[no-index]{enumext*} and % \myenv*[no-index]{keyans*}: an item that occupies the whole row is % typeset without \myenv[no-index]{minipage} and can be broken between pages. % \item The standard lists and the environments \myenv[no-index]{quote}, % \myenv[no-index]{quotation}, \myenv[no-index]{verse}, \myenv[no-index]{center}, % \myenv[no-index]{tabbing}, \myenv[no-index]{verbatim}, those created with % |\newtheorem| and similar ones can be used in the items of % \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*}. % \item Fixed the duplicate error messages when the \mykey[env]{save-ans} key is % missing, the behavior of |\setenumext| with invalid levels and its % interaction with |\printkeyans|, and \mykey{widest} for the labels % \ilabel[no-index]{Roman*} and \ilabel[no-index]{roman*}. % \item Fixed |\miniright| and \mykey{mini-env}, \mykey{mini-right} and % \mykey{mini-right*}: spurious errors, exact vertical spaces and the end % of the \myenv[no-index]{minipage}. Fixed \mykey{base-fix} with % \mykey{parsep}, \mykey{itemsep} and \mykey{columns}. % \item Tagged \texttt{PDF}: balanced paragraph hooks, \texttt{TextAlign} % attribute in \mykey{item-break}, and the \myenv[no-index]{minipage} on the % right side no longer leaves the tagging state active. % \item Error and information messages with a common layout. % \item Added regression tests, run with |l3build check|. % \end{itemize} % \item [v2.3 (ctan), 2026-10-23] % \begin{itemize} % \item Update requirement to \hologo{LaTeX} release 2026-11-01. % \item Cleanup warnings and details returned by |expltools|. % \item Replace \myhlc|\exp_after:wN| by \myhlc|\exp_after:w|. % \item Update code for \emph{tagged} \texttt{PDF}. % \item Adjustments in the documentation. % \end{itemize} % \item [v2.2 (ctan), 2026-06-01] % \begin{itemize} % \item Update requirement to \hologo{LaTeX} release 2026-06-01. % \item Move |\setcounter| to |\begin{list}|\mymarg{arg one}|{|\mymeta{arg two}|\setcounter}| for \myenv*[no-index]{enumext*}. % \item Adjustments in the documentation. % \end{itemize} % \item [v2.1 (ctan), 2026-01-15] % \begin{itemize} % \item Fixed bad interaction between |\setenumext| and the \mykey{ref} key. % \end{itemize} % \item [v2.0 (ctan), 2025-12-02] % \begin{itemize} % \item Update requirement to \mypkg[no-index]{multicol} release 2025-10-21. % \item Adjustments in the documentation. % \end{itemize} % \item [v1.9 (ctan), 2025-11-01] % \begin{itemize} % \item Update requirement to \hologo{LaTeX} release 2025-11-01. % \item Move |\setcounter| to |\begin{list}|\mymarg{arg one}|{|\mymeta{arg two}|\setcounter}|. % \item Update code for \emph{tagged} \texttt{PDF}. % \end{itemize} % \item [v1.8 (ctan), 2025-10-04] % \begin{itemize} % \item Replacing |\scantokens| (primitive) with \myhlc|\tl_retokenize:n|. % \item Cleanup warnings and details returned by |expltools|. % \end{itemize} % \item [v1.7 (ctan), 2025-07-10] % \begin{itemize} % \item Fixed |\setenumext{|\myenv*[no-index]{enumext*}|}{|\mykey{resume}|}|. % \item Fixed bad interaction between |\setenumext| and the \mykey{resume} key. % \item The behavior of the key \mykey{resume*} has been updated and documented. % \end{itemize} % \item [v1.6 (ctan), 2025-07-04] % \begin{itemize} % \item Syntax simplification for |\setenumextmeta|. % \item Environments can be started with the key \mykey{resume} \emph{without value}. % \item Add |\resetenumext|, \mykey{reset} and \mykey{reset*} keys. % \item The \mykey{resume}, \mykey{resume*} and \mykey{series} % keys can now be set per level. % \item Fixed bad interaction between |\printkeyans| and the \mykey{resume}, \mykey{resume*} keys. % \end{itemize} % \item [v1.5 (ctan), 2025-06-11] % \begin{itemize} % \item Replacing \myhlc|\regex_match:| (deprecated) with \myhlc|\regex_if_match:|. % \item Add keys \mykey{beginpenalty}, \mykey{midpenalty} and \mykey{endpenalty}. % \end{itemize} % \item [v1.4 (ctan), 2025-06-09] % \begin{itemize} % \item Improved implementation of the \mykey{start} key for \emph{tagged} \texttt{PDF}. % \item Improved implementation of the \mykey{ref} key. % \item Fixed the behavior of the \mykey{save-sep} key. % \item Fixed the behavior of the \mykey{resume*} key. % \end{itemize} % \item [v1.3 (ctan), 2025-06-01] % \begin{itemize} % \item Removed dependency on the \mypkg{scontents} package. % \item The \myenv*[no-index]{anskey*} environment has been rewritten using the new % \texttt{c-type} argument. % \end{itemize} % \item [v1.2 (ctan), 2025-03-28] % \begin{itemize} % \item Replace signature (prevent expansion for optional argument). % \item Solve Inconsistent local/global assignment. % \end{itemize} % \item [v1.1 (ctan), 2024-11-14] % \begin{itemize} % \item Fixed implementation for \mykey{font} and \mykey{base-fix} keys. % \item Added new keys for symbol marks. % \item Update and improvements in the internal code. % \item Adjustments in the documentation. % \end{itemize} % \item [v1.0 (ctan), 2024-11-01] % \begin{itemize} % \item First public release. % \end{itemize} % \end{description} % % \newpage % % \indexprologue{ % The italic numbers denote the pages where the corresponding entry is % described.} % % \printindex[userdoc] % % \newpage % % \StartImplementation % % \StopEventually{^^A % \newgeometry{top=0.5in,bottom=0.3in,left=1.0in,right=0.5in,footskip=0.2in,headheight=1cm,headsep=0.27cm} % \addtocontents{toc}{\protect\setcounter{tocdepth}{2}} % \cleardoublepage % \phantomsection % \indexprologue{ % The italic numbers denote the pages where the corresponding entry is % described, the numbers underlined and all others indicate the line on % which they are implemented in the package code. % } % \printindex % } % % \newgeometry{top=0.5in,bottom=0.3in,left=1.95in,right=0.5in,footskip=0.2in,headheight=1cm,headsep=0.27cm} % % \section{Implementation} % \label{sec:implementation} % \addtocontents{toc}{\protect\setcounter{tocdepth}{0}} % % The most recent publicly released version of \mypkg*[no-index]{enumext} is % available at \textsc{ctan}: \url{https://www.ctan.org/pkg/enumext}. % While general feedback via email is welcomed, specific bugs or % feature requests should be reported through the issue % tracker: \textcolor{gray}{\scriptsize\faIcon[regular]{github}} \url{https://github.com/pablgonz/enumext/issues}. % % \begin{important}* % The documentation presented here is far from professional, it contains % a lot of obvious information that to the eye of a \hologo{TeX}pert are % superfluous, but, after so many years developing this project is the % only way to remember what does what. % \end{important} % % \subsection{General conventions}\label{subsec:general-conventions} % % Variables containing \lstinline+i+, \lstinline+ii+, \lstinline+iii+ and % \lstinline+iv+ are associated by level with the \myenv*[no-index]{enumext} % environment, variables containing \lstinline+v+ are associated with the % \myenv*[no-index]{keyans} environment, variables containing \lstinline+vi+ are % associated with the \myenv*[no-index]{keyanspic} environment, variables % containing \lstinline+vii+ are associated with the \myenv*{enumext*} % environment and variables containing \lstinline+viii+ are associated % with the \myenv*[no-index]{keyans*} environment. % % To simplify writing and documentation some variables and functions that % are common to the different levels of the environments are described % using a capital \enquote{\texttt{\textcolor{keyname}{X}}}. % % The temporary function \myhlc|\@@_tmp:n| is used in % different parts of the package code for variable creation or execution % of other functions that are grouped into this one. % % All variables and functions defined in this package are private and % are NOT intended to work or be used by another package or module. % % % \subsection{Initial set up}\label{subsec:initial-setup} % % Start the \pkg{DocStrip} guards. % \begin{macrocode} %<*package> % \end{macrocode} % Identify the internal prefix (\LaTeX3 \pkg{DocStrip} convention) for % \myclass{l3doc} class. % \begin{macrocode} %<@@=enumext> % \end{macrocode} % % \subsection{Declaration of the package}\label{subsec:declaration} % % Checks for a minimum release version of \hologo{LaTeX}; otherwise it % returns an \enquote{error}. % \begin{macrocode} \NeedsTeXFormat{LaTeX2e}[2026-11-01] \IfFormatAtLeastF { 2026-11-01 } { \PackageError { enumext } { LaTeX~kernel~too~old~need~2026-11-01~or~later } { enumext~requires~a~LaTeX2e~release~2026-11-01~or~ later.~Update~your~TeX~distribution. } } % \end{macrocode} % Now declare the \mypkg*[no-index]{enumext} package. % \begin{macrocode} \ProvidesExplPackage {enumext} {2026-11-01} {2.4} {Enumerate exercise sheets} % \end{macrocode} % Finally, check if the \mypkg{multicol} package is loaded; if not, it is loaded. % \begin{macrocode} \hook_gput_code:nnn {begindocument} {enumext} { \IfPackageLoadedTF { multicol } { \msg_info:nnn { enumext } { package-load } { multicol } } { \msg_info:nnn { enumext } { package-not-load } { multicol } \RequirePackage{multicol}[2025-10-21] } } % \end{macrocode} % % \subsection{Definition of variables}\label{subsec:variables} % % This section describes the variables shared by several commands, keys or % environments, in groups and by purpose. The variables that belong to a single % command, key or environment are defined in the subsection where they are used, % in the part \emph{\enquote{Definition of variables}}. The variables that do not % appear in either place are created by means of \myhlc|\keys_define:nn| or some % function described below. % % \subsubsection{Nesting levels and state of the environments} % % \begin{variable}[int]{ % \l_@@_level_int, % \l_@@_level_h_int, % \l_@@_keyans_level_int, % \l_@@_keyans_level_h_int, % \l_@@_keyans_pic_level_int, % } % Integer variables will control the nesting levels of the environments. % \begin{macrocode} \int_new:N \l_@@_level_int \int_new:N \l_@@_level_h_int \int_new:N \l_@@_keyans_level_int \int_new:N \l_@@_keyans_level_h_int \int_new:N \l_@@_keyans_pic_level_int % \end{macrocode} % \end{variable} % % \begin{variable}[int]{ % \l_@@_starred_bool, % \g_@@_starred_bool, % \l_@@_starred_first_bool, % \l_@@_standard_bool, % \g_@@_standard_bool, % \l_@@_standard_first_bool, % \l_@@_keyans_env_bool, % \g_@@_start_line_tl, % \g_@@_envir_name_tl, % \l_@@_envir_name_tl, % } % Internal variables used by functions \myhlc|\@@_is_not_nested:|, % \myhlc|\@@_is_on_first_level:| and \myhlc|\@@_keyans_name_and_start:| (\S\ref{subsubsec:utilities}). % \begin{macrocode} \bool_new:N \l_@@_starred_bool \bool_new:N \g_@@_starred_bool \bool_new:N \l_@@_starred_first_bool \bool_new:N \l_@@_standard_bool \bool_new:N \g_@@_standard_bool \bool_new:N \l_@@_standard_first_bool \bool_new:N \l_@@_keyans_env_bool \tl_new:N \g_@@_start_line_tl \tl_new:N \g_@@_envir_name_tl \tl_new:N \l_@@_envir_name_tl % \end{macrocode} % \end{variable} % % \subsubsection{Counters, labels and numbering} % % \begin{variable}[int]{\l_@@_current_widest_dim} % The dimension \myhlc|\l_@@_current_widest_dim| stores the current % label width. It is used by \mykey{widest} (\S\ref{key:start-widest}) and % \mykey{label} (\S\ref{key:label}) keys. % \begin{macrocode} \dim_new:N \l_@@_current_widest_dim % \end{macrocode} % \end{variable} % % \begin{variable}[int]{ % \l_@@_resume_count_bool, % \l_@@_resume_count_X_bool, % } % Internal variables shared by the \mykey{start} and \mykey{start*} keys % (\S\ref{key:start-widest}), the \mykey{resume}, \mykey{resume*} and % \mykey{series} keys (\S\ref{key:series}) and the environments. % \begin{macrocode} \bool_new:N \l_@@_resume_count_bool \cs_set_protected:Nn \@@_tmp:n { \bool_new:c { l_@@_resume_count_ #1 _bool } } \clist_map_inline:nn { i, ii, iii, iv, vii } { \@@_tmp:n {#1} } % \end{macrocode} % \end{variable} % % \begin{variable}[int]{ % \l_@@_start_X_int, % \l_@@_fake_item_indent_X_tl, % } % The integer \myhlc|\l_@@_start_X_int| is used by the \mykey{start} and % \mykey{start*} keys (\S\ref{key:start-widest}) and the token list % \myhlc|\l_@@_fake_item_indent_X_tl| is used by \mykey{itemindent} key % (\S\ref{subsubsec:fake-indent}). % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:n { \int_new:c { l_@@_start_ #1 _int } \tl_new:c { l_@@_fake_item_indent_ #1 _tl } } \clist_map_inline:nn { i, ii, iii, iv, v, vii, viii } { \@@_tmp:n {#1} } % \end{macrocode} % \end{variable} % % \begin{variable}[int]{ % \l_@@_wrap_label_X_bool, % \l_@@_wrap_label_opt_X_bool, % \l_@@_label_fill_left_X_tl, % \l_@@_label_fill_right_X_tl, % \l_@@_align_label_pos_X_str, % } % The bool vars \myhlc|\l_@@_wrap_label_X_bool| and % \myhlc|\l_@@_wrap_label_opt_X_bool| are used by \mykey{wrap-label} % and \mykey{wrap-label*} keys (\S\ref{key:label}). The variables % \myhlc|\l_@@_label_fill_left_X_tl|, \myhlc|\l_@@_label_fill_right_X_tl| and % \myhlc|\l_@@_align_label_pos_X_str| are used by the \mykey{align} key % (\S\ref{key:label}). % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:n { \bool_new:c { l_@@_wrap_label_ #1 _bool } \bool_new:c { l_@@_wrap_label_opt_ #1 _bool } \tl_new:c { l_@@_label_fill_left_ #1 _tl } \tl_new:c { l_@@_label_fill_right_ #1 _tl } } \clist_map_inline:nn { i, ii, iii, iv, v, vii, viii } { \@@_tmp:n {#1} } \cs_set_protected:Nn \@@_tmp:n { \str_new:c { l_@@_align_label_pos_ #1 _str } } \clist_map_inline:nn { i, ii, iii, iv, v } { \@@_tmp:n {#1} } % \end{macrocode} % \end{variable} % % \subsubsection{Horizontal and vertical spaces} % % \begin{variable}[int]{ % \l_@@_leftmargin_tmp_X_bool, % \l_@@_leftmargin_tmp_X_dim, % \l_@@_leftmargin_X_dim, % } % The boolean variable \myhlc|\l_@@_leftmargin_tmp_X_bool| and the % dimensional variable \myhlc|\l_@@_leftmargin_tmp_X_dim| % are used by the \mykey{list-indent} key (\S\ref{key:list-indent}). % The variable \myhlc|\l_@@_leftmargin_X_dim| is used and set by the function % \myhlc|\@@_calc_hspace:NNNNNNN| (\S\ref{subsubsec:leftmargin}). % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:n { \bool_new:c { l_@@_leftmargin_tmp_ #1 _bool } \dim_new:c { l_@@_leftmargin_tmp_ #1 _dim } \dim_new:c { l_@@_leftmargin_ #1 _dim } } \clist_map_inline:nn { i, ii, iii, iv, v, vi, vii, viii } { \@@_tmp:n {#1} } % \end{macrocode} % \end{variable} % % \begin{variable}[int]{ % \l_@@_multicols_above_X_skip, % \l_@@_multicols_below_X_skip, % } % Internal variables used by \mykey{columns} key (\S\ref{subsec:vspace-multicols}). % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:n { \skip_new:c { l_@@_multicols_above_ #1 _skip } \skip_new:c { l_@@_multicols_below_ #1 _skip } } \clist_map_inline:nn { i, ii, iii, iv, v } { \@@_tmp:n {#1} } % \end{macrocode} % \end{variable} % % \begin{variable}[int]{ % \g_@@_minipage_stat_int, % \g_@@_minipage_right_skip, % \l_@@_minipage_left_X_dim, % \l_@@_minipage_active_X_bool, % } % Internal variables used by \ics*{miniright} command (\S\ref{cmd:miniright}) % and the keys \mykey{mini-right}, \mykey{mini-right*}, \mykey{mini-env} % and \mykey{mini-sep} (\S\ref{key:mini-multi},~\S\ref{subsec:vspace-minipage}). % \begin{macrocode} \int_new:N \g_@@_minipage_stat_int \skip_new:N \g_@@_minipage_right_skip \cs_set_protected:Nn \@@_tmp:n { \dim_new:c { l_@@_minipage_left_ #1 _dim } \bool_new:c { l_@@_minipage_active_ #1 _bool } } \clist_map_inline:nn { i, ii, iii, iv, v, vii, viii } { \@@_tmp:n {#1} } % \end{macrocode} % \end{variable} % % \begin{variable}[int]{ % \l_@@_item_starred_X_bool, % \l_@@_item_break_X_bool, % \l_@@_item_column_pos_X_int, % \g_@@_item_count_all_X_int, % \l_@@_item_text_X_box, % \l_@@_joined_width_X_dim, % \g_@@_item_symbol_aux_X_tl, % \l_@@_align_label_X_str, % \g_@@_minipage_center_X_bool, % \g_@@_minipage_right_X_dim, % } % Internal variables used by \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} environments. % The boolean \myhlc|\l_@@_item_break_X_bool| is set by the key % \mykey[env]{item-break} (\S\ref{subsec:set-item-break}). % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:n { \bool_new:c { l_@@_item_starred_ #1 _bool } \bool_new:c { l_@@_item_break_ #1 _bool } \int_new:c { l_@@_item_column_pos_ #1 _int } \int_new:c { g_@@_item_count_all_ #1 _int } \box_new:c { l_@@_item_text_ #1 _box } \dim_new:c { l_@@_joined_width_ #1 _dim } \tl_new:c { g_@@_item_symbol_aux_ #1 _tl } \str_new:c { l_@@_align_label_ #1 _str } \bool_new:c { g_@@_minipage_center_ #1 _bool } \dim_new:c { g_@@_minipage_right_ #1 _dim } } \clist_map_inline:nn { vii, viii } { \@@_tmp:n {#1} } % \end{macrocode} % \end{variable} % % \subsubsection{Storing answers, checking and printing} % % \begin{variable}[int]{ % \l_@@_store_active_bool, % \l_@@_store_name_tl, % \g_@@_store_name_tl, % \l_@@_store_current_label_tl, % \l_@@_store_current_opt_arg_tl, % } % % The variable \myhlc|\l_@@_store_active_bool| set by % \mykey{save-ans} key (\S\ref{key:save-ans}) activates all the % mechanism related to \ics*{anskey}, \myenv*[no-index]{anskey*}, \myenv*[no-index]{keyans}, % \myenv*[no-index]{keyans*} and \myenv*[no-index]{keyanspic} environments. % % The variable \myhlc|\l_@@_store_name_tl| saves the \mymarg{store name} % set by the \mykey{save-ans} key of the \emph{sequence} and \emph{prop % list} where the content is stored. The variable \myhlc|\g_@@_store_name_tl| % is just a global copy of \mymarg{store name} used by different functions. % % The variables \myhlc|\l_@@_store_current_label_tl| and % \myhlc|\l_@@_store_current_opt_arg_tl| save the \emph{current label} and % \emph{optional argument} of \ics*{item*} (\S\ref{cmd:item-keyans}) and \ics*{anspic*} % (\S\ref{cmd:anspic}) for the \myenv*[no-index]{keyans}, \myenv*[no-index]{keyans*} and % \myenv*[no-index]{keyanspic} environments. % \begin{macrocode} \bool_new:N \l_@@_store_active_bool \tl_new:N \l_@@_store_name_tl \tl_new:N \g_@@_store_name_tl \tl_new:N \l_@@_store_current_label_tl \tl_new:N \l_@@_store_current_opt_arg_tl % \end{macrocode} % \end{variable} % % \begin{variable}[int]{ % \l_@@_check_answers_bool, % \g_@@_check_ans_key_bool, % \l_@@_check_start_line_env_tl, % \l_@@_item_wrap_key_bool, % \g_@@_check_starred_cmd_int, % \g_@@_item_anskey_int, % \g_@@_item_number_int, % \l_@@_item_number_bool, % \g_@@_item_answer_diff_int, % } % Internal variables used by \emph{\enquote{internal check answer}} mechanism % (\S\ref{subsubsec:check-answer}) used by the \mykey{check-ans}, \mykey{no-store}, \mykey{wrap-ans*} % keys and check for starred commands |\item*| in \myenv*[no-index]{keyans} and % \myenv*[no-index]{keyans*} environments and |\anspic*| % in \myenv*[no-index]{keyanspic} environment. % \begin{macrocode} \bool_new:N \l_@@_check_answers_bool \bool_new:N \g_@@_check_ans_key_bool \tl_new:N \l_@@_check_start_line_env_tl \bool_new:N \l_@@_item_wrap_key_bool \int_new:N \g_@@_check_starred_cmd_int \int_new:N \g_@@_item_anskey_int \int_new:N \g_@@_item_number_int \bool_new:N \l_@@_item_number_bool \int_new:N \g_@@_item_answer_diff_int % \end{macrocode} % \end{variable} % % \begin{variable}[int]{ % \l_@@_print_keyans_star_bool, % \l_@@_print_keyans_cmd_bool, % \l_@@_print_keyans_X_tl, % \l_@@_mark_position_str, % \l_@@_mark_position_v_str, % \l_@@_mark_position_viii_str, % } % The boolean \myhlc|\l_@@_print_keyans_cmd_bool| is true while the command % \ics*{printkeyans} (\S\ref{cmd:printkeyans}) is running and the environments % consult it, the boolean \myhlc|\l_@@_print_keyans_star_bool| is true when % the command receives the \emph{starred} argument and the token lists % \myhlc|\l_@@_print_keyans_X_tl| store the keys passed to each environment. % The strings \myhlc|\l_@@_mark_position_str|, \myhlc|\l_@@_mark_position_v_str| % and \myhlc|\l_@@_mark_position_viii_str| store the position of the marks % set by the \mykey{mark-pos} key (\S\ref{subsec:storage-system}). % \begin{macrocode} \bool_new:N \l_@@_print_keyans_star_bool \bool_new:N \l_@@_print_keyans_cmd_bool \str_new:N \l_@@_mark_position_str \str_new:N \l_@@_mark_position_v_str \str_new:N \l_@@_mark_position_viii_str \cs_set_protected:Nn \@@_tmp:n { \tl_new:c { l_@@_print_keyans_ #1 _tl } } \clist_map_inline:nn { i, ii, iii, iv, vii } { \@@_tmp:n {#1} } % \end{macrocode} % \end{variable} % % \subsubsection{\texttt{hyperref}, labels and references} % % \begin{variable}[int]{\l_@@_hyperref_bool, \l_@@_footnotes_key_bool} % The boolean variable \myhlc|\l_@@_hyperref_bool| will determine if the % \mypkg{hyperref} package is present or loaded in memory % (\S\ref{subsec:hyperref}). The boolean variable \myhlc|\l_@@_footnotes_key_bool| % determines if \mypkg[no-index]{hyperref} is loaded with the key |hyperfootnotes=true|. % \begin{macrocode} \bool_new:N \l_@@_hyperref_bool \bool_new:N \l_@@_footnotes_key_bool % \end{macrocode} % \end{variable} % % \begin{variable}[int]{ % \l_@@_newlabel_arg_one_tl, % \l_@@_newlabel_arg_two_tl, % \l_@@_write_aux_file_tl, % \l_@@_label_copy_X_tl, % } % Internal variables used by \mykey{save-ref} key (\S\ref{subsec:storage-system}). % The variables \myhlc|\l_@@_label_copy_X_tl| correspond to temporary % copies of the \mymeta{labels} defined by level on which operations will be performed. % % The variables \myhlc|\l_@@_newlabel_arg_one_tl| and \myhlc|\l_@@_newlabel_arg_two_tl| % will be used to form the arguments passed to the function % \myhlc|\@@_newlabel:nn| (\S\ref{fun:newlabel}) and the variable \myhlc|\l_@@_write_aux_file_tl| % will be in charge of executing the writing code in the |.aux| file. % \begin{macrocode} \tl_new:N \l_@@_newlabel_arg_one_tl \tl_new:N \l_@@_newlabel_arg_two_tl \tl_new:N \l_@@_write_aux_file_tl \cs_set_protected:Nn \@@_tmp:n { \tl_new:c { l_@@_label_copy_ #1 _tl } } \clist_map_inline:nn { i, ii, iii, iv, v, vi, vii, viii } { \@@_tmp:n {#1} } % \end{macrocode} % \end{variable} % % \subsubsection{Constants} % % \begin{variable}[int]{\c_@@_all_envs_clist} % An internal |clist-var| variable to run with \myhlc|\@@_tmp:n|. % \begin{macrocode} \clist_const:Nn \c_@@_all_envs_clist { {level-1}{i}, {level-2}{ii}, {level-3}{iii}, {level-4}{iv}, {keyans}{v}, {enumext*}{vii}, {keyans*}{viii} } % \end{macrocode} % \end{variable} % % \subsection{Some utility functions}\label{subsec:utility-functions} % % \subsubsection{Definition of messages for the internal hooks} % % These messages are not error messages, they only write information to the % |.log| file with the standard layout of the information messages. % % \begin{macro}[int]{prop-seq-int-hook, item-answer-hook} % Messages written to the |.log| file by the internal hooks that show the values of the % global variables of the storage. % \begin{macrocode} \msg_new:nnn { enumext } { prop-seq-int-hook } { Storage~'#1':~ \c_backslash_str g_@@_ #1 _prop~has~#2~elements,~ \c_backslash_str g_@@_ #1 _seq~has~#3~elements,~ \c_backslash_str g_@@_resume_ #1 _int~=~#4. } \msg_new:nnn { enumext } { item-answer-hook } { Items~=~#1,~answers~=~#2,~difference~=~#3. } % \end{macrocode} % \end{macro} % % \subsubsection{General utility functions} % % \begin{macro}[int]{\keys_precompile:neN, \seq_use:NV} % Non-standard kernel variants used by the |\printkeyans| command % (\S\ref{cmd:printkeyans}) and |\foreachkeyans| command (\S\ref{cmd:foreachkeyans}). % \begin{macrocode} \cs_generate_variant:Nn \keys_precompile:nnN { neN } \cs_generate_variant:Nn \seq_use:Nn { NV } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_at_begin_document:n} % A internal \emph{\enquote{hook}} function used for copying plain % \myenv[no-index]{list} and \myenv[no-index]{minipage} environments definition and % \mypkg[no-index]{hyperref} detection. % \begin{macrocode} \cs_new_protected:Nn \@@_at_begin_document:n { \hook_gput_code:nnn {begindocument} {enumext} {#1} } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_after_env:nn} % An internal \emph{\enquote{hook}} function to execute code \mykey[env]{mini-right} % and \mykey[env]{mini-right*} keys outside the \myenv*[no-index]{enumext*} and % \myenv*[no-index]{keyans*} environments and print \mykey[env]{check-ans} outside the % \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} environments. % \begin{macrocode} \cs_new_protected:Nn \@@_after_env:nn { \hook_gput_code:nnn {env/#1/after} {enumext} {#2} } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_level:} % Function for check current level in \myenv*[no-index]{enumext}. % \begin{macrocode} \cs_new:Nn \@@_level: { \int_to_roman:n { \l_@@_level_int } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_if_is_int:nT, \@@_if_is_int:nF, \@@_if_is_int:nTF} % A conditional function to determine whether the variable being passed is % an integer used by \mykey[env,foreachkeyans]{start} and \mykey[env]{widest} keys. % This function is taken directly from the answer given by Henri Menke % in \href{https://tex.stackexchange.com/a/427559}{How to test if an expl3 function argument is an integer expression?}. % \begin{macrocode} \prg_new_protected_conditional:Npnn \@@_if_is_int:n #1 { T, F, TF } { \regex_if_match:nnTF { ^[\+\-]?[\d]+$ } {#1} % $ { \prg_return_true: } { \prg_return_false: } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_show_length:nnn} % Internal function used by \mykey[env]{show-length} key to show % \emph{\enquote{all lengths}} calculated and used in % \myenv*[no-index]{enumext}, \myenv*[no-index]{enumext*}, \myenv*[no-index]{keyans} and % \myenv*[no-index]{keyans*} environments. % \begin{macrocode} \cs_new:Nn \@@_show_length:nnn { *~#2 \prg_replicate:nn { 14 - \str_count:n {#2} } {~} =~\use:c { #1 _use:c } { l_@@_ #2 _ #3 _ #1 } \\ } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_unskip_unkern:} % The function \myhlc|\@@_unskip_unkern:| will remove the last \mymeta{skip} % or \mymeta{kern} at execution time using the values \mydim{11} and % \mydim{12} of \myhlc|\lastnodetype| to apply \myhlc|\unskip| or \myhlc|\unkern| depending % on the case. In the \emph{outer} vertical mode \TeX{} can't take things % from the current page, because \myhlc|\unskip| and \myhlc|\unkern| are errors there, so a % negative \myhlc|\vskip| or \myhlc|\kern| is used instead, as \hologo{LaTeX} does in % |\removelastskip|. % \begin{macrocode} \cs_new_protected:Nn \@@_unskip_unkern: { \int_case:nn { \lastnodetype } { { 11 } { \mode_if_vertical:TF { \mode_if_inner:TF { \unskip } { \skip_vertical:n { -\lastskip } } } { \unskip } } { 12 } { \mode_if_vertical:TF { \mode_if_inner:TF { \unkern } { \kern -\lastkern \scan_stop: } } { \unkern } } } } % \end{macrocode} % \end{macro} % % \subsubsection{Utilities for environments and levels}\label{subsubsec:utilities} % % \begin{macro}[int]{\@@_is_not_nested:, \@@_is_on_first_level:} % The function \myhlc|\@@_is_not_nested:| sets the variables \myhlc|\g_@@_standard_bool| % and \myhlc|\g_@@_starred_bool| to |true| only if the % environments \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} are NOT nested % in each other and saves the environment name in \myhlc|\l_@@_envir_name_tl|. % \begin{macrocode} \cs_new_protected:Nn \@@_is_not_nested: { \str_case:en { \@currenvir } { {enumext} { \tl_set:Ne \l_@@_envir_name_tl { enumext } \bool_lazy_and:nnT { \bool_not_p:n { \g_@@_standard_bool } } { \int_compare_p:nNn { \l_@@_level_h_int } = { 0 } } { \bool_gset_true:N \g_@@_standard_bool } } {enumext*} { \tl_set:Ne \l_@@_envir_name_tl { enumext* } \bool_lazy_and:nnT { \bool_not_p:n { \g_@@_starred_bool } } { \int_compare_p:nNn { \l_@@_level_int } = { 0 } } { \bool_gset_true:N \g_@@_starred_bool } } } } % \end{macrocode} % The function \myhlc|\@@_is_on_first_level:| sets the variables % \myhlc|\l_@@_standard_first_bool| (\S\ref{key:save-ans}), % \myhlc|\l_@@_starred_first_bool| (\S\ref{key:save-ans}) to |true| % only if the environment is not nested and it is at the \emph{\enquote{first level}}. % They also save the \emph{start line number} of each environment % in the variable \myhlc|\g_@@_start_line_tl| and the \emph{name} of each % environment in the variable \myhlc|\g_@@_envir_name_tl| to use in messages % related to the \mykey[env]{check-ans} key and |.log| file. % \begin{macrocode} \cs_new_protected:Nn \@@_is_on_first_level: { \bool_lazy_all:nT { { \bool_if_p:N \g_@@_standard_bool } { \int_compare_p:nNn { \l_@@_level_int } = { 1 } } { \int_compare_p:nNn { \l_@@_level_h_int } = { 0 } } } { \bool_set_true:N \l_@@_standard_first_bool \tl_gset:Nn \g_@@_envir_name_tl { enumext } \tl_gset:Ne \g_@@_start_line_tl { on~line~\exp_not:V \inputlineno } } \bool_lazy_all:nT { { \bool_if_p:N \g_@@_starred_bool } { \int_compare_p:nNn { \l_@@_level_h_int } = { 1 } } { \int_compare_p:nNn { \l_@@_level_int } = { 0 } } } { \bool_set_true:N \l_@@_starred_first_bool \tl_gset:Nn \g_@@_envir_name_tl { enumext* } \tl_gset:Ne \g_@@_start_line_tl { on~line~\exp_not:V \inputlineno } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_keyans_name_and_start:} % The function \myhlc|\@@_keyans_name_and_start:| will save the start line % number and name of the environments \myenv*[no-index]{keyans}, \myenv*[no-index]{keyans*} and % \myenv*[no-index]{keyanspic} in the variables \myhlc|\l_@@_check_start_line_env_tl| % and \myhlc|\l_@@_envir_name_tl| to use in the \myhlc|\@@_check_starred_cmd:n| function. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_name_and_start: { \str_case:en { \@currenvir } { {keyans} { \tl_set:Ne \l_@@_envir_name_tl { keyans } \tl_set:Ne \l_@@_check_start_line_env_tl { in~'keyans'~start~on~line~\exp_not:V \inputlineno } } {keyans*} { \tl_set:Ne \l_@@_envir_name_tl { keyans* } \tl_set:Ne \l_@@_check_start_line_env_tl { in~'keyans*'~start~on~line~\exp_not:V \inputlineno } } {keyanspic} { \tl_set:Ne \l_@@_envir_name_tl { keyanspic } \tl_set:Ne \l_@@_check_start_line_env_tl { in~'keyanspic'~start~on~line~\exp_not:V \inputlineno } } } } % \end{macrocode} % \end{macro} % % \subsubsection{Utilities for log and terminal} % % \begin{macro}[int]{\@@_reset_global_vars:, \@@_reset_global_int:, % \@@_reset_global_bool:, \@@_reset_global_tl:} % The function \myhlc|\@@_reset_global_vars:| will be passed to the function % \myhlc|\@@_execute_after_env:| and will return the global variables to % their default values after being used. % \begin{macrocode} \cs_new_protected:Nn \@@_reset_global_vars: { \@@_reset_global_int: \@@_reset_global_bool: \@@_reset_global_tl: } \cs_new_protected:Nn \@@_reset_global_int: { \int_gzero:N \g_@@_item_number_int \int_gzero:N \g_@@_item_anskey_int \int_gzero:N \g_@@_item_answer_diff_int } \cs_new_protected:Nn \@@_reset_global_bool: { \bool_gset_false:N \g_@@_check_ans_key_bool \bool_gset_false:N \g_@@_standard_bool \bool_gset_false:N \g_@@_starred_bool } \cs_new_protected:Nn \@@_reset_global_tl: { \tl_gclear:N \g_@@_store_name_tl \tl_gclear:N \g_@@_start_line_tl \tl_gclear:N \g_@@_envir_name_tl } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_log_global_vars:, \@@_log_answer_vars:} % The function \myhlc|\@@_log_global_vars:| will be passed to the function % \myhlc|\@@_execute_after_env:| and write to the |.log| file the number of % elements saved in the \emph{prop list} and \emph{sequence} created by the % \mykey[env]{save-ans} key along with the value of the integer variable % created for the \mykey[env]{resume} key. % \begin{macrocode} \cs_new_protected:Nn \@@_log_global_vars: { \msg_info:nneeee { enumext } { prop-seq-int-hook } { \g_@@_store_name_tl } { \prop_count:c { g_@@_ \g_@@_store_name_tl _prop } } { \seq_count:c { g_@@_ \g_@@_store_name_tl _seq } } { \int_use:c { g_@@_resume_ \g_@@_store_name_tl _int } } } % \end{macrocode} % The function \myhlc|\@@_log_answer_vars:| will be passed to the function % \myhlc|\@@_execute_after_env:| and write to the |.log| file the number % of items and answers along with the difference between them. % \begin{macrocode} \cs_new_protected:Nn \@@_log_answer_vars: { \msg_info:nneee { enumext } { item-answer-hook } { \int_use:N \g_@@_item_number_int } { \int_use:N \g_@@_item_anskey_int } { \int_eval:n { \g_@@_item_number_int - \g_@@_item_anskey_int} } } % \end{macrocode} % \end{macro} % % \subsection{Copying \env{list} and \env{minipage} environments}\label{subsec:copy-envs} % % The \myenv[no-index]{list} environment provided by \hologo{LaTeX} has the % following plain form\cite{latex2e}: % % \iffalse %<*example> % \fi \begin{examplecode}[frame=none] \list`\mymarg{arg one}\mymarg{arg two}` \item`\myoarg{opt}` \endlist \end{examplecode} % \iffalse % % \fi % % And \myenv[no-index]{minipage} environment provided by \hologo{LaTeX} has the % following (simplified) plain form: % % \iffalse %<*example> % \fi \begin{examplecode}[frame=none] \minipage`\myoarg{pos}\myoarg{height}\myoarg{inner-pos}\mymarg{width}` `\mymeta{internal implement}` \endminipage \end{examplecode} % \iffalse % % \fi % % As a precaution they are copied using \myhlc|\@@_at_begin_document:n| in % case any package redefines the \myenv[no-index]{list} environment or a related % command. % % \begin{important} % For compatibility with \emph{tagged} \texttt{PDF}, |\NewCommandCopy| should be used and not \myhlc|\cs_new_eq:NN| for |\item|. When % \emph{tagged} \texttt{PDF} is active |\item| is redefined using % \mypkg{ltcmd} (see \mypkg{latex-lab-block}\cite{latexlab}). % \end{important} % % \begin{macro}[int]{\@@_start_list:nn, \@@_stop_list:, \@@_item_std:w, % \@@_minipage:w, \@@_endminipage:} % The functions \myhlc|\@@_start_list:nn| and \myhlc|\@@_stop_list:| correspond % to copies of |\list| and |\endlist| from plain definition of \myenv[no-index]{list} % environment, the function \myhlc|\@@_item_std:w| is a copy of the |\item| command. % \begin{macrocode} \@@_at_begin_document:n { \cs_new_eq:NN \@@_start_list:nn \list \cs_new_eq:NN \@@_stop_list: \endlist \NewCommandCopy \@@_item_std:w \item } % \end{macrocode} % The functions \myhlc|\@@_minipage:w| and \myhlc|\@@_endminipage:| correspond % to copies of |\minipage| and |\endminipage| from plain definition of % \myenv[no-index]{minipage} environment. % \begin{macrocode} \@@_at_begin_document:n { \cs_new_eq:NN \@@_minipage:w \minipage \cs_new_eq:NN \@@_endminipage: \endminipage } % \end{macrocode} % \end{macro} % % \subsection{Compatibility with hyperref and footnotehyper}\label{subsec:hyperref} % % \begin{macro}[int]{\@@_after_hyperref:, \@@_hypertarget:nn, \@@_phantomsection:} % First, the necessary rules are defined using \emph{\enquote{hooks}} to % determine if the \mypkg[no-index]{hyperref} package is loaded. % \begin{macrocode} \hook_gput_code:nnn { begindocument } { enumext } { \@@_after_hyperref: } \hook_gset_rule:nnnn { begindocument } { enumext } { after } { hyperref } % \end{macrocode} % The function \myhlc|\@@_after_hyperref:| sets the state of the boolean % variable \myhlc|\l_@@_hyperref_bool| to |true| if the package is % loaded. The public macro |\IfHyperBoolean| determines if the % |hyperfootnotes=true| key is present, and if so, the boolean variable % \myhlc|\l_@@_footnotes_key_bool| is set to |true|. % \begin{macrocode} \cs_new_protected:Nn \@@_after_hyperref: { \IfPackageLoadedT { hyperref } { \msg_info:nnn { enumext } { package-load } { hyperref } \bool_set_true:N \l_@@_hyperref_bool \IfHyperBoolean{hyperfootnotes} { \bool_set_true:N \l_@@_footnotes_key_bool } { } } % \end{macrocode} % If the variable \myhlc|\l_@@_footnotes_key_bool| is true, it checks % whether the package \mypkg{footnotehyper} is loaded; if it is not, % \myhlc|\l_@@_footnotes_key_bool| is set to false and |\footnote| is % redefined. % \begin{macrocode} \bool_if:NT \l_@@_footnotes_key_bool { \IfPackageLoadedTF { footnotehyper } { \msg_info:nnn { enumext } { package-load } { footnotehyper } } { \bool_set_false:N \l_@@_footnotes_key_bool } } % \end{macrocode} % The functions \myhlc|\@@_hypertarget:nn| and \myhlc|\@@_phantomsection:| % correspond to the internal copies of |\hypertarget| and % |\phantomsection|. If the boolean variable \myhlc|\l_@@_hyperref_bool| % is false the functions \myhlc|\@@_hypertarget:nn| and \myhlc|\@@_phantomsection:| % will be disabled. % \begin{macrocode} \bool_if:NTF \l_@@_hyperref_bool { \cs_new_eq:NN \@@_hypertarget:nn \hypertarget \cs_new_eq:NN \@@_phantomsection: \phantomsection } { \cs_new_eq:NN \@@_hypertarget:nn \use_none:nn \cs_new_eq:NN \@@_phantomsection: \prg_do_nothing: } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_newlabel:nn}\label{fun:newlabel} % The function \myhlc|\@@_newlabel:nn| writes the information to the |.aux| % file when using the \mykey[env]{save-ref} key. The arguments taken by the % function are: % % \begin{arguments} % \item \myhlc|\l_@@_newlabel_arg_one_tl| % \item \myhlc|\l_@@_newlabel_arg_two_tl| % \end{arguments} % % \begin{important}* % The trick here is to manage the number of arguments passed to % |\newlabel{#1}{#2}| according to the presence of the \mypkg[no-index]{hyperref} % package. % \end{important} % % \begin{macrocode} \cs_new_protected:Nn \@@_newlabel:nn { \protected@write \@auxout { } { \token_to_str:N \newlabel {#1} { {#2} \bool_if:NT \l_@@_hyperref_bool { { \thepage } {#2} {#1} } { } } } \@@_hypertarget:nn {#1} { } \@@_phantomsection: } % \end{macrocode} % \end{macro} % % \subsection{Internal redefining \cs{footnote} command}\label{subsec:footnote} % % To keep the correct numbering of |\footnote| and to make it work % correctly in the \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} environments % and \mykey{mini-env} key it is necessary to redefine the |\footnote| command. % This implementation is adapted from the answer given by Clea F. Rees (\texttt{@cfr}) % in \href{https://tex.stackexchange.com/a/700092}{footnotes in boxes compatible with hyperref}. % % \begin{variable}[int]{ % \g_@@_footnote_standard_int, % \g_@@_footnote_starred_int, % \g_@@_footnote_standard_arg_seq, % \g_@@_footnote_starred_arg_seq, % \g_@@_footnote_standard_int_seq, % \g_@@_footnote_starred_int_seq, % } % Internal variables used for redefinition of |\footnote| (\S\ref{subsec:footnote}). % \begin{macrocode} \int_new:N \g_@@_footnote_standard_int \int_new:N \g_@@_footnote_starred_int \seq_new:N \g_@@_footnote_standard_arg_seq \seq_new:N \g_@@_footnote_starred_arg_seq \seq_new:N \g_@@_footnote_standard_int_seq \seq_new:N \g_@@_footnote_starred_int_seq % \end{macrocode} % \end{variable} % % \begin{macro}[int]{\@@_footnotetext:nn, \@@_renew_footnote:, % \@@_print_footnote:, \@@_renew_footnote_mini:, % \@@_print_footnote_mini:} % Redefinition of the |\footnote| command using |\footnotetext| and % |\footnotemark| for the \mykey[env]{mini-env} key in the \myenv*[no-index]{enumext} and % \myenv*[no-index]{keyans} environments. % \begin{macrocode} \cs_new_protected:Nn \@@_footnotetext:nn { \footnotetext[#1]{#2} } \cs_new_protected:Nn \@@_renew_footnote: { \RenewDocumentCommand \footnote { o +m } { \tl_if_novalue:nTF {##1} { \stepcounter{footnote} \int_gset_eq:Nc \g_@@_footnote_standard_int { c@footnote } } { \int_gset:Nn \g_@@_footnote_standard_int {##1} } \footnotemark [ \g_@@_footnote_standard_int ] \seq_gput_right:Nn \g_@@_footnote_standard_arg_seq {##2} \seq_gput_right:NV \g_@@_footnote_standard_int_seq \g_@@_footnote_standard_int } } \cs_new_protected:Nn \@@_print_footnote: { \seq_if_empty:NF \g_@@_footnote_standard_int_seq { \seq_map_pairwise_function:NNN \g_@@_footnote_standard_int_seq \g_@@_footnote_standard_arg_seq \@@_footnotetext:nn } \seq_gclear:N \g_@@_footnote_standard_arg_seq \seq_gclear:N \g_@@_footnote_standard_int_seq } % \end{macrocode} % The \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} environments are implemented % using \myenv[no-index]{minipage}, so |\footnote| must also be redefined to keep % this numbering as if it were part of the document. % \begin{macrocode} \cs_new_protected:Nn \@@_renew_footnote_mini: { \RenewDocumentCommand \footnote { o +m } { \tl_if_novalue:nTF {##1} { \stepcounter{footnote} \int_gset_eq:Nc \g_@@_footnote_starred_int { c@footnote } } { \int_gset:Nn \g_@@_footnote_starred_int {##1} } \footnotemark [ \g_@@_footnote_starred_int ] \seq_gput_right:Nn \g_@@_footnote_starred_arg_seq {##2} \seq_gput_right:NV \g_@@_footnote_starred_int_seq \g_@@_footnote_starred_int } } \cs_new_protected:Nn \@@_print_footnote_mini: { \seq_if_empty:NF \g_@@_footnote_starred_int_seq { \seq_map_pairwise_function:NNN \g_@@_footnote_starred_int_seq \g_@@_footnote_starred_arg_seq \@@_footnotetext:nn } \seq_gclear:N \g_@@_footnote_starred_arg_seq \seq_gclear:N \g_@@_footnote_starred_int_seq } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_renew_footnote_standard:, \@@_print_footnote_standard:, % \@@_renew_footnote_starred:, \@@_print_footnote_starred:} % The redefinition of |\footnote| is encapsulated to pass it to the internal % \myhlc|\@@_mini_page| environment used by the \mykey[env]{mini-env} % key in the \myenv*[no-index]{enumext} and \myenv*[no-index]{keyans} environments. It is % executed when \emph{tagged} \texttt{PDF} is active or when % the \mypkg[no-index]{footnotehyper} package is not loaded. % \begin{macrocode} \cs_new_protected:Nn \@@_renew_footnote_standard: { \bool_if:NT \g_@@_standard_bool { \IfDocumentMetadataTF { \@@_renew_footnote: } { \bool_if:NF \l_@@_footnotes_key_bool { \@@_renew_footnote: } } } } \cs_new_protected:Nn \@@_print_footnote_standard: { \bool_if:NT \g_@@_standard_bool { \IfDocumentMetadataTF { \@@_print_footnote: } { \bool_if:NF \l_@@_footnotes_key_bool { \@@_print_footnote: } } } } % \end{macrocode} % The redefinition of |\footnote| is encapsulated to pass it to the % \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} environments. It is executed % when \emph{tagged} \texttt{PDF} is active or when the % \mypkg[no-index]{footnotehyper} package is not loaded. % \begin{macrocode} \cs_new_protected:Nn \@@_renew_footnote_starred: { \IfDocumentMetadataTF { \@@_renew_footnote_mini: } { \bool_if:NF \l_@@_footnotes_key_bool { \@@_renew_footnote_mini: } } } \cs_new_protected:Nn \@@_print_footnote_starred: { \IfDocumentMetadataTF { \@@_print_footnote_mini: } { \bool_if:NF \l_@@_footnotes_key_bool { \@@_print_footnote_mini: } } } % \end{macrocode} % In \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} environments it is necessary to use % \emph{\enquote{hooks}} to print |\footnote| with support for % \emph{tagged} \texttt{PDF}. % \begin{macrocode} \@@_after_env:nn { enumext* } { \@@_print_footnote_starred: } \@@_after_env:nn { keyans* } { \@@_print_footnote_starred: } % \end{macrocode} % \end{macro} % % \subsection{The internal \env{minipage} environment}\label{subsec:internal-minipage} % % \begin{macro}[int]{\@@_internal_mini_page:, \@@_mini_page} % The function \myhlc|\@@_internal_mini_page:| creates an internal % \myhlc|\@@_mini_page| environment (\emph{custom version} of % \myenv[no-index]{minipage}) setting the |\if@minipage| switch to |false| % to allow spaces at the \emph{\enquote{above}} of the environment, % plus \myhlc|\skip_vertical:N \c_zero_skip| is added to maintain alignment % on \emph{\enquote{top}} in the first part and \myhlc|\skip_vertical:N \c_zero_skip| % in the second part to allow spaces \emph{\enquote{below}}. This environment % will be used internally by the \mykey[env]{mini-env} key, it is NOT documented % in the user interface and is for internal use only. Within this environment % |\footnote| is redefined to make the notes look the same as if they were % elsewhere in the document. This implementation is adapted from the answer % given by Max Chernoff (\texttt{@MaxChernoff}) in \href{https://tex.stackexchange.com/a/720966/7832}{Customize \texttt{minipage} to support spaces below it}. % % \begin{important}* % This function is passed to the function \myhlc|\@@_safe_exec:| in the % \myenv*[no-index]{enumext} environment definition (\S\ref{env:enumext}) % and \myhlc|\@@_safe_exec_vii:| in the \myenv*[no-index]{enumext*} environment % definition (\S\ref{env:starred}). % \end{important} % \begin{macrocode} \cs_new_protected:Nn \@@_internal_mini_page: { \int_compare:nNnT { \l_@@_level_int } = { 0 } { \DeclareDocumentEnvironment{@@_mini_page}{ m } { \@@_renew_footnote_standard: \@@_minipage:w [ t ] {##1} \legacy_if_gset_false:n { @minipage } \skip_vertical:N \c_zero_skip } { \skip_vertical:N \c_zero_skip \@@_endminipage: \@@_print_footnote_standard: } } } % \end{macrocode} % \end{macro} % % \subsection{Definition of public dimension}\label{subsec:public-dimensions} % % The package \mypkg*[no-index]{enumext} only provides a single public dimension % |\itemwidth| and is intended for user convenience only and is not % for internal use as such. This dimension is set in all environments % and is only used by the \mykey{wrap-ans} key at its default value. % \begin{macrocode} \dim_zero_new:N \itemwidth % \end{macrocode} % % \subsection{Definition of counters}\label{subsec:counters} % % \subsubsection{Definition of variables} % % \begin{variable}[int]{ % \l_@@_counter_i_tl, % \l_@@_counter_ii_tl, % \l_@@_counter_iii_tl, % \l_@@_counter_iv_tl, % \l_@@_counter_v_tl, % \l_@@_counter_vi_tl, % \l_@@_counter_vii_tl, % \l_@@_counter_viii_tl, % } % % Variables to store the \emph{\enquote{name of the counters}} % \icounter{enumXi}, \icounter{enumXii}, \icounter{enumXiii} and % \icounter{enumXiv} for \myenv*[no-index]{enumext} environment, % \icounter{enumXv} for \myenv*[no-index]{keyans} environment and % \icounter{enumXvi} for the \myenv*[no-index]{keyanspic} environment. % The counters \icounter{enumXvii} and \icounter{enumXviii} are used % by \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} environments. % % The initial values of these variables are set by the function % \myhlc|\@@_define_counter:Nn| (\S\ref{subsec:counters}) and then modified by the function % \myhlc|\@@_label_style:Nnn| used by \mykey{label} key (\S\ref{key:label-ref}). % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:n { \tl_new:c { l_@@_counter_ #1 _tl } } \clist_map_inline:nn { i, ii, iii, iv, v, vi, vii, viii } { \@@_tmp:n {#1} } % \end{macrocode} % \end{variable} % % \subsubsection{Definition of error messages} % % \begin{macro}[int]{counters} % Message used in the creation of counters by \mypkg*[no-index]{enumext} package. % \begin{macrocode} \msg_new:nnnn { enumext } { counters } { The~counter~'#1'~is~already~defined~by~some~package~or~macro,~ it~cannot~be~continued. } { Another~package~or~macro~already~defines~the~counter~'#1'.~ Check~for~a~conflict~with~'enumext'. } % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions for the counters} % % \begin{macro}[int]{\@@_define_counter:Nn, enumXi, enumXii, enumXiii, % enumXiv, enumXv, enumXvi, enumXvii, enumXviii} % To create the necessary \emph{\enquote{counters}}, the function first % checks that they are not already defined by the user or a package % such as \mypkg{enumitem}; otherwise it returns an error and aborts % the package loading. The arguments taken by the function are: % % \begin{arguments} % \item A token list \myhlc|\l_@@_counter_X_tl| to \emph{\enquote{store}} the counter's name. % \item The counter's name. % \end{arguments} % % \begin{macrocode} \cs_new_protected:Nn \@@_define_counter:Nn { \cs_if_exist:cTF { c@ #2 } { \msg_fatal:nnn { enumext } { counters }{#2} } { \tl_set:Nn #1 {#2} \newcounter {#2} } } % \end{macrocode} % The counters created here are \icounter[no-index]{enumXi}, \icounter[no-index]{enumXii}, % \icounter[no-index]{enumXiii} and \icounter[no-index]{enumXiv} for \myenv*[no-index]{enumext} % environment, \icounter[no-index]{enumXv} for \myenv*[no-index]{keyans} environment, % \icounter[no-index]{enumXvi} for \myenv*[no-index]{keyanspic} environment, \icounter[no-index]{enumXvii} for % \myenv*[no-index]{enumext*} and \icounter[no-index]{enumXviii} for the \myenv*[no-index]{keyans*} % environments. % \begin{macrocode} \@@_define_counter:Nn \l_@@_counter_i_tl { enumXi } \@@_define_counter:Nn \l_@@_counter_ii_tl { enumXii } \@@_define_counter:Nn \l_@@_counter_iii_tl { enumXiii } \@@_define_counter:Nn \l_@@_counter_iv_tl { enumXiv } \@@_define_counter:Nn \l_@@_counter_v_tl { enumXv } \@@_define_counter:Nn \l_@@_counter_vi_tl { enumXvi } \@@_define_counter:Nn \l_@@_counter_vii_tl { enumXvii } \@@_define_counter:Nn \l_@@_counter_viii_tl { enumXviii } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\c@__@@_resume_i_int, \c@__@@_resume_ii_int, % \c@__@@_resume_iii_int, \c@__@@_resume_iv_int, % \c@__@@_resume_vii_int} % In version 1.6 the command |\resetenumext| (\S\ref{cmd:resetenumext}) % was added which internally uses |\counterwithin*| so for its correct % operation, \emph{\enquote{real counters}} are created instead of % the \emph{\enquote{integer variables}} for the keys \mykey[env]{resume} % and \mykey[env]{resume*}. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:n { \cs_if_exist:cTF { c@ @@_resume_ #1 _int } { \msg_fatal:nne { enumext } { counters }{ @@_resume_ #1 _int } } { \newcounter { @@_resume_ #1 _int } } } \clist_map_inline:nn {i,ii,iii,iv,vii} { \@@_tmp:n {#1} } % \end{macrocode} % \end{macro} % % \subsection{Definition of labels}\label{subsec:definition-labels} % % This part of the code is inspired by the \mypkg[no-index]{enumitem} package. The % idea is to be able to access the counters using \ilabel{arabic*}, % \ilabel{Alph*}, \ilabel{alph*}, \ilabel{Roman*} and \ilabel{roman*} % to use them in the \mykey{label} key. % % \begin{important}* % Direct support for this is provided since \hologo{LaTeX} release % 2025-06-01\cite{ltnews}, but the original implementation is kept % so as not to hinder the internal \emph{\enquote{label and ref}} system. % \end{important} % % % \begin{variable}[int]{ % \g_@@_counter_styles_tl, % \g_@@_widest_label_tl, % \l_@@_label_width_by_box, % } % The variable \myhlc|\g_@@_counter_styles_tl| stores the default % \mymeta{label style} and the variable \myhlc|\g_@@_widest_label_tl| the % label width. The box \myhlc|\l_@@_label_width_by_box| is used by the function % \myhlc|\@@_label_width_by_box:Nn| to measure the width of a label. % These variables are used by \mykey{widest} (\S\ref{key:start-widest}) and % \mykey{label} (\S\ref{key:label}) keys. % \begin{macrocode} \tl_new:N \g_@@_counter_styles_tl \tl_new:N \g_@@_widest_label_tl \box_new:N \l_@@_label_width_by_box % \end{macrocode} % \end{variable} % % \begin{macro}[int]{\@@_register_default_label_wd:Nn} % These \mymeta{counters} will be used as default \mymeta{labels} if % the \mykey[env]{label} key is not used for the different levels of the % \myenv*[no-index]{enumext}, \myenv*[no-index]{enumext*}, \myenv*[no-index]{keyans} and \myenv*[no-index]{keyans*} % environments, so it is necessary to get a default value for \mykey[env]{labelwidth} % from these \mymeta{labels} at the same time. % \begin{macrocode} \cs_new_protected:Nn \@@_register_default_label_wd:Nn { \tl_const:cn { c_@@_widest_ \cs_to_str:N #1 _tl } {#2} \tl_gput_right:Nn \g_@@_counter_styles_tl {#1} } \@@_register_default_label_wd:Nn \arabic { 0 } \@@_register_default_label_wd:Nn \Alph { M } \@@_register_default_label_wd:Nn \alph { m } \@@_register_default_label_wd:Nn \Roman { VIII } \@@_register_default_label_wd:Nn \roman { viii } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_label_width_by_box:Nn, \@@_label_width_by_box:cv} % The function \myhlc|\@@_label_width_by_box:Nn| sets the default |\labelwidth| % using a box width if no \mykey[env]{labelwidth} key is passed. % \begin{macrocode} \cs_new_protected:Nn \@@_label_width_by_box:Nn { \hbox_set:Nn \l_@@_label_width_by_box {#2} \dim_set:Nn #1 { \box_wd:N \l_@@_label_width_by_box } } \cs_generate_variant:Nn \@@_label_width_by_box:Nn { cv } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_label_style:Nnn, \@@_label_style:cvn} % The function \myhlc|\@@_label_style:Nnn| is used by the \mykey[env]{label} % key to create the variables containing the \mymeta{label style} % and allows using \ilabel[no-index]{arabic*}, \ilabel[no-index]{Alph*}, \ilabel[no-index]{alph*}, % \ilabel[no-index]{Roman*} and \ilabel[no-index]{roman*} as arguments. % % It loops through the defined counter styles in \myhlc|\g_@@_counter_styles_tl| % (|\arabic|, |\alph|, |\Alph|, |\roman| and |\Roman|) for example, % looking for \ilabel[no-index]{roman*} and replacing that by |\roman|\mymarg{counter}, % and doing the same for the \myhlc|\g_@@_widest_label_tl| to keep both in sync. % \begin{macrocode} \cs_new_protected:Nn \@@_label_style:Nnn { \tl_clear_new:N #1 \tl_put_right:Ne #1 { \tl_trim_spaces:n {#3} } \tl_gset_eq:NN \g_@@_widest_label_tl #1 \tl_map_inline:Nn \g_@@_counter_styles_tl { \tl_replace_all:Nne #1 { ##1* } { \exp_not:N ##1 {#2} } \tl_greplace_all:Nne \g_@@_widest_label_tl { ##1* } { \tl_use:c { c_@@_widest_ \cs_to_str:N ##1 _tl } } } \@@_label_width_by_box:Nn \l_@@_current_widest_dim { \tl_use:N \g_@@_widest_label_tl } \tl_set_eq:cN { the #2 } #1 } \cs_generate_variant:Nn \@@_label_style:Nnn { cvn } % \end{macrocode} % \end{macro} % % \subsection{Setting keys associated with label}\label{key:label} % % When \emph{tagged} \texttt{PDF} is active |\makelabel| is redefined using % |\makebox| to work correctly (\S\ref{cmd:item-enumext}). From % the user side it is convenient to have a key that allows using this % redefinition with |\makebox| without having \myhlc|\IfDocumentMetadataTF| active. % % \begin{macro}[int]{mode-box} % Defines the key \mykey[env]{mode-box} only for the \emph{\enquote{first level}} % of \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} environments. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:n { \keys_define:nn { enumext / #1 } { mode-box .bool_set:N = \l_@@_mode_box_bool, mode-box .initial:n = false, mode-box .value_forbidden:n = true, } } \clist_map_inline:nn { level-1, enumext* } { \@@_tmp:n {#1} } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{font, labelsep, labelwidth, wrap-label, wrap-label*} % Definition of keys \mykey[env]{font}, \mykey[env]{labelsep}, \mykey[env]{labelwidth}, % \mykey[env]{wrap-label} and \mykey[env]{wrap-label*} keys for \myenv*[no-index]{enumext} % and \myenv*[no-index]{keyans} environments. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:nn { \keys_define:nn { enumext / #1 } { font .tl_set:c = { l_@@_label_font_style_ #2 _tl }, font .value_required:n = true, labelsep .dim_set:c = { l_@@_labelsep_ #2 _dim }, labelsep .initial:n = {0.3333em}, labelsep .value_required:n = true, labelwidth .dim_set:c = { l_@@_labelwidth_ #2 _dim }, labelwidth .value_required:n = true, wrap-label .cs_set_protected:cp = { @@_wrapper_label_ #2 :n } ##1, wrap-label .initial:n = {##1}, wrap-label .value_required:n = true, wrap-label* .code:n = { \bool_set_true:c { l_@@_wrap_label_opt_ #2 _bool } \keys_set:nn { enumext / #1 } { wrap-label = {##1} } }, wrap-label* .value_required:n = true, } } \clist_map_inline:Nn \c_@@_all_envs_clist { \@@_tmp:nn #1 } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{align} % The \mykey[env]{align} key is implemented differently for \emph{\enquote{starred}} % and \emph{\enquote{non starred}} environments. For compatibility with % \emph{tagged} \texttt{PDF} it is necessary to set \myhlc|\l_@@_align_label_pos_X_str|. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:nn { \keys_define:nn { enumext / #1 } { align .choices:nn = { left , right , center } { \int_case:nn { \l_keys_choice_int } { {1} { \tl_clear:c { l_@@_label_fill_left_ #2 _tl } \tl_set:cn { l_@@_label_fill_right_ #2 _tl } { \hfill } \str_set:cn { l_@@_align_label_pos_ #2 _str } { l } } {2} { \tl_set:cn { l_@@_label_fill_left_ #2 _tl } { \hfill } \tl_clear:c { l_@@_label_fill_right_ #2 _tl } \str_set:cn { l_@@_align_label_pos_ #2 _str } { r } } {3} { \tl_set:cn { l_@@_label_fill_left_ #2 _tl } { \hfill } \tl_set:cn { l_@@_label_fill_right_ #2 _tl } { \hfill } \str_set:cn { l_@@_align_label_pos_ #2 _str } { c } } } }, align .initial:n = left, align .value_required:n = true, align / unknown .code:n = \msg_error:nneee { enumext } { unknown-choice } { align } { left,~right,~ center } { \exp_not:n {##1} }, } } \clist_map_inline:nn { {level-1}{i}, {level-2}{ii}, {level-3}{iii}, {level-4}{iv}, {keyans}{v} } { \@@_tmp:nn #1 } % \end{macrocode} % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:nn { \keys_define:nn { enumext / #1 } { align .choices:nn = { left , right , center } { \int_case:nn { \l_keys_choice_int } { {1} { \str_set:cn { l_@@_align_label_ #2 _str } { l } } {2} { \str_set:cn { l_@@_align_label_ #2 _str } { r } } {3} { \str_set:cn { l_@@_align_label_ #2 _str } { c } } } }, align .initial:n = left, align .value_required:n = true, align / unknown .code:n = \msg_error:nneee { enumext } { unknown-choice } { align } { left,~right,~ center } { \exp_not:n {##1} }, } } \clist_map_inline:nn { {enumext*}{vii}, {keyans*}{viii} } { \@@_tmp:nn #1 } % \end{macrocode} % \end{macro} % % \subsection{Setting \texttt{label} and \texttt{ref} keys}\label{key:label-ref} % % The implementation of the keys \mykey{label} and \mykey{ref} are part % of the core of the package \mypkg*[no-index]{enumext}, here the default values % for \mymeta{label}, the value of the variables \myhlc|\l_@@_label_X_tl|, % the default values for |\labelwidth| and the \emph{\enquote{label and ref}} system. % % \subsubsection{Definition of variables} % % \begin{variable}[int]{ % \l_@@_ref_key_arg_tl, % \l_@@_ref_the_count_tl, % \l_@@_renew_counter_X_tl, % \l_@@_the_counter_X_tl, % } % Internal variables used by \mykey{ref} key (\S\ref{key:label-ref}). % \begin{macrocode} \tl_new:N \l_@@_ref_key_arg_tl \tl_new:N \l_@@_ref_the_count_tl \cs_set_protected:Nn \@@_tmp:n { \tl_new:c { l_@@_renew_counter_ #1 _tl } \tl_new:c { l_@@_the_counter_ #1 _tl } \tl_set:ce { l_@@_the_counter_ #1 _tl } { \exp_not:c { theenumX #1 } } } \clist_map_inline:nn { i, ii, iii, iv, v, vi, vii, viii } { \@@_tmp:n {#1} } % \end{macrocode} % \end{variable} % % \subsubsection{Definition of error messages} % % \begin{macro}[int]{key-ref-empty} % Messages used by \mykey[env]{ref} key. % \begin{macrocode} \msg_new:nnnn { enumext } { key-ref-empty } { Key~'ref'~needs~a~value~in~'#1'~\msg_line_context:. } { Give~a~value~to~the~key~'ref'~or~remove~it. } % \end{macrocode} % \end{macro} % % \subsubsection{Define and set \texttt{label} and \texttt{ref} keys for \env{enumext} environment} % % \begin{macro}[int]{label, ref, \l_@@_label_i_tl, \l_@@_label_ii_tl, \l_@@_label_iii_tl, \l_@@_label_iv_tl} % Sets the default \mymeta{labels} of the \emph{four levels} of % \myenv*[no-index]{enumext} environment, along with the default values for % \mykey[env]{labelwidth}, \mykey[env]{widest} and \mykey[env]{ref} keys. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:nnn { \tl_const:cn { c_@@_default_label_ #2 _tl } {#3} \keys_define:nn { enumext / #1 } { label .code:n = { \@@_label_style:cvn { l_@@_label_ #2 _tl } { l_@@_counter_ #2 _tl } {##1} \dim_set_eq:cN { l_@@_labelwidth_ #2 _dim } \l_@@_current_widest_dim }, label .initial:n = #3, label .value_required:n = true, ref .code:n = { \@@_standard_ref:nn {#2} {##1} }, ref .value_required:n = true, } } \@@_tmp:nnn { level-1 } { i } { \arabic*.} \@@_tmp:nnn { level-2 } { ii } { (\alph*) } \@@_tmp:nnn { level-3 } { iii } { \roman*. } \@@_tmp:nnn { level-4 } { iv } { \Alph*. } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_standard_ref:nn, \@@_standard_ref:} % The \myhlc|\@@_standard_ref:nn| function will first pass the key % \emph{argument} \mykey{ref} to the variable % \myhlc|\l_@@_ref_key_arg_tl| and analyze its state, if it is not \emph{empty} % it will set a copy of the \emph{current counter style} saved in % \myhlc|\l_@@_the_counter_X_tl| to \myhlc|\l_@@_ref_the_count_tl| and % then set the variable \myhlc|\l_@@_renew_counter_X_tl| which will % modify |\theenumX|. % \begin{macrocode} \cs_new_protected:Nn \@@_standard_ref:nn { \tl_set:Nn \l_@@_ref_key_arg_tl {#2} \tl_if_empty:NTF \l_@@_ref_key_arg_tl { \msg_error:nnn { enumext } { key-ref-empty } { enumext } } { \tl_set_eq:Nc \l_@@_ref_the_count_tl { l_@@_the_counter_ #1 _tl } \tl_set:ce { l_@@_renew_counter_ #1 _tl } { \exp_not:N \renewcommand { \exp_not:V \l_@@_ref_the_count_tl } { \exp_not:V \l_@@_ref_key_arg_tl } } } } % \end{macrocode} % Finally the function \myhlc|\@@_standard_ref:| will execute the % modification for the reference system in the second argument of the % environment definition \myenv*[no-index]{enumext}. % \begin{macrocode} \cs_new_protected:Nn \@@_standard_ref: { \tl_if_empty:cF { l_@@_renew_counter_ \@@_level: _tl } { \tl_use:c { l_@@_renew_counter_ \@@_level: _tl } } } % \end{macrocode} % \end{macro} % % \subsubsection{Define and set \texttt{label} and \texttt{ref} keys for \env{enumext*} and \env{keyans*} environments} % % \begin{macro}[int]{label, ref, \l_@@_label_vii_tl, \l_@@_label_viii_tl} % Sets the default \mymeta{labels} for \myenv*[no-index]{enumext*} and % \myenv*[no-index]{keyans*} environments, along with the default value for % \mykey[env]{labelwidth} key and \mykey[env]{ref} key. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:nnn { \tl_const:cn { c_@@_default_label_ #2 _tl } {#3} \keys_define:nn { enumext / #1 } { label .code:n = { \@@_label_style:cvn { l_@@_label_ #2 _tl } { l_@@_counter_ #2 _tl } {##1} \dim_set_eq:cN { l_@@_labelwidth_ #2 _dim } \l_@@_current_widest_dim }, label .initial:n = #3, label .value_required:n = true, ref .code:n = { \@@_starred_ref:n {##1} }, ref .value_required:n = true, } } \@@_tmp:nnn { enumext* } { vii } { \arabic*.} \@@_tmp:nnn { keyans* } { viii } { \Alph*) } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_starred_ref:n, \@@_starred_ref:} % The implementation of \myhlc|\@@_starred_ref:n| is the same as that % used for the environment \myenv*[no-index]{enumext}. % \begin{macrocode} \cs_new_protected:Nn \@@_starred_ref:n { \tl_set:Nn \l_@@_ref_key_arg_tl {#1} \int_compare:nNnT { \l_@@_level_h_int } = { 1 } { \tl_if_empty:NTF \l_@@_ref_key_arg_tl { \msg_error:nnn { enumext } { key-ref-empty } { enumext* } } { \tl_set_eq:NN \l_@@_ref_the_count_tl \l_@@_the_counter_vii_tl \tl_set:Ne \l_@@_renew_counter_vii_tl { \exp_not:N \renewcommand { \exp_not:V \l_@@_ref_the_count_tl } { \exp_not:V \l_@@_ref_key_arg_tl } } } } \int_compare:nNnT { \l_@@_keyans_level_h_int } = { 1 } { \tl_if_empty:NTF \l_@@_ref_key_arg_tl { \msg_error:nnn { enumext } { key-ref-empty } { keyans* } } { \tl_set_eq:NN \l_@@_ref_the_count_tl \l_@@_the_counter_viii_tl \tl_set:Ne \l_@@_renew_counter_viii_tl { \exp_not:N \renewcommand { \exp_not:V \l_@@_ref_the_count_tl } { \exp_not:V \l_@@_ref_key_arg_tl } } } } } % \end{macrocode} % Finally the function \myhlc|\@@_starred_ref:| will execute the % modification for the reference system in the second argument of the % \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} environment definition. % \begin{macrocode} \cs_new_protected:Nn \@@_starred_ref: { \int_compare:nNnT { \l_@@_level_h_int } = { 1 } { \tl_if_empty:NF \l_@@_renew_counter_vii_tl { \tl_use:N \l_@@_renew_counter_vii_tl } } \int_compare:nNnT { \l_@@_keyans_level_h_int } = { 1 } { \tl_if_empty:NF \l_@@_renew_counter_viii_tl { \tl_use:N \l_@@_renew_counter_viii_tl } } } % \end{macrocode} % \end{macro} % % \subsubsection{Define and set \texttt{label} and \texttt{ref} keys for \env{keyans} and \env{keyanspic} environments} % % \begin{macro}[int]{label, ref, \l_@@_label_v_tl, \l_@@_label_vi_tl} % Sets the default \mymeta{label} for \myenv*[no-index]{keyans} % and \myenv*[no-index]{keyanspic} environment, along with the default value for % \mykey[env]{labelwidth} if it has not been established and \mykey[env]{ref} key. % The \myenv*[no-index]{keyanspic} environment use the same \mymeta{label} as % the \myenv*[no-index]{keyans} environment. % \begin{macrocode} \keys_define:nn { enumext / keyans } { label .code:n = { \@@_label_style:cvn { l_@@_label_v_tl } { l_@@_counter_v_tl } {#1} \@@_label_style:cvn { l_@@_label_vi_tl } { l_@@_counter_vi_tl } {#1} \dim_set_eq:NN \l_@@_labelwidth_v_dim \l_@@_current_widest_dim }, label .initial:n = \Alph*), label .value_required:n = true, ref .code:n = { \@@_keyans_ref:n {#1} }, ref .value_required:n = true, } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_keyans_ref:n, \@@_keyans_ref:} % The implementation of \myhlc|\@@_keyans_ref:n| is the same as that % used for the environment \myenv*[no-index]{enumext}. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_ref:n { \tl_set:Nn \l_@@_ref_key_arg_tl {#1} \tl_if_empty:NTF \l_@@_ref_key_arg_tl { \msg_error:nnn { enumext } { key-ref-empty } { keyans } } { \tl_set_eq:NN \l_@@_ref_the_count_tl \l_@@_the_counter_v_tl \tl_put_right:Ne \l_@@_renew_counter_v_tl { \exp_not:N \renewcommand { \exp_not:V \l_@@_ref_the_count_tl } { \exp_not:V \l_@@_ref_key_arg_tl } } } } % \end{macrocode} % Finally the function \myhlc|\@@_keyans_ref:| will execute the % modification for the reference system in the second argument of the % \myenv*[no-index]{keyans} environment definition. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_ref: { \tl_if_empty:NF \l_@@_renew_counter_v_tl { \tl_use:N \l_@@_renew_counter_v_tl } } % \end{macrocode} % \end{macro} % % \subsection{Setting \texttt{start}, \texttt{start*} and \texttt{widest} keys}\label{key:start-widest} % % \begin{macro}[int]{\@@_start_from:NNn, \@@_start_from:ccn, \@@_start_from:cce} % The function \myhlc|\@@_start_from:NNn| used by \mykey[env,foreachkeyans]{start} and \mykey[env]{start*} % keys takes three arguments: % % \begin{arguments} % \item \myhlc|\l_@@_label_X_tl| % \item \myhlc|\l_@@_start_X_int| % \item \meta{integer or string} % \end{arguments} % The argument `|#1|' is the \emph{\enquote{counter style}} set by % \mykey[env]{label} key, `|#2|' is returned by the function, % `|#3|' can be an \mymeta{integer} or \mymeta{string} of the % form |\Alph|, |\alph|, |\Roman| or |\roman|. This effectively % allows \mykey{start*}|=A| or \mykey{start}|=1| to be used. % % \begin{important}* % In version 1.6 it is allowed to pass the \mykey[env]{resume} key \emph{without % value} by means of the command |\setenumext|, for the correct operation % of this, the boolean variable \myhlc|\l_@@_resume_count_bool| % set by the \mykey{resume} key \emph{without value} must be set to |false| (\S\ref{key:series}). % This is necessary to be able to \enquote{reset} the \emph{start value} % by means of the \mykey{start} or \mykey{start*} keys. % \end{important} % % \begin{macrocode} \cs_new_protected:Nn \@@_start_from:NNn { \bool_set_false:N \l_@@_resume_count_bool \@@_if_is_int:nTF {#3} { \int_set:Nn #2 {#3} } { \regex_if_match:nVT { \c{Alph} | \c{alph} } #1 { \int_set:Nn #2 { \int_from_alph:n {#3} } } \regex_if_match:nVT { \c{Roman} | \c{roman} } #1 { \int_set:Nn #2 { \int_from_roman:n {#3} } } } } \cs_generate_variant:Nn \@@_start_from:NNn { ccn, cce } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_widest_from:nNNn, \@@_widest_from:nccn} % The function \myhlc|\@@_widest_from:nNNn| used by the \mykey[env]{widest} % key takes four arguments: % % \begin{arguments} % \item The counter associated with the environment level % \item \myhlc|\l_@@_label_X_tl| % \item \myhlc|\l_@@_labelwidth_X_dim| % \item \meta{integer or string} % \end{arguments} % % The arguments `|#2|' and `|#3|' are the values set by % \mykey[env]{label} and \mykey[env]{labelwidth} keys, `|#4|' can % be an \mymeta{integer} or \mymeta{string} of the % form |\Alph|, |\alph|, |\Roman| or |\roman|. % The value of `|#4|' is set temporarily for the % identified counter in this point (level), then the value is expanded % into a \emph{\enquote{box}} and the \emph{\enquote{width}} of the % \emph{\enquote{box}} is returned. % \begin{macrocode} \cs_new_protected:Nn \@@_widest_from:nNNn { \@@_if_is_int:nTF {#4} { \setcounter{enumX #1} {#4} } { \regex_if_match:nVT { \c{Alph} | \c{alph} } #2 { \setcounter{enumX #1} { \int_from_alph:n {#4} } } \regex_if_match:nVT { \c{Roman} | \c{roman} } #2 { \setcounter{enumX #1} { \int_from_roman:n {#4} } } } \@@_label_width_by_box:cv { l_@@_labelwidth_ #1 _dim } { l_@@_label_ #1 _tl } } \cs_generate_variant:Nn \@@_widest_from:nNNn { nccn } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{start, start*, widest} % Now define and set \mykey[env]{start*}, \mykey[env,foreachkeyans]{start} and \mykey[env]{widest} % keys for \myenv*[no-index]{enumext}, \myenv*[no-index]{enumext*}, \myenv*[no-index]{keyans} and % \myenv*[no-index]{keyans*} environments. % % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:nn { \keys_define:nn { enumext / #1 } { start* .code:n = { \@@_start_from:ccn { l_@@_label_ #2 _tl } { l_@@_start_ #2 _int } {##1} }, start* .value_required:n = true, start .code:n = { \@@_start_from:cce { l_@@_label_ #2 _tl } { l_@@_start_ #2 _int } { \int_eval:n {##1} } }, start .initial:n = 1, start .value_required:n = true, widest .code:n = { \@@_widest_from:nccn {#2} { l_@@_label_ #2 _tl } { l_@@_labelwidth_ #2 _dim } {##1} }, widest .value_required:n = true, } } \clist_map_inline:Nn \c_@@_all_envs_clist { \@@_tmp:nn #1 } % \end{macrocode} % \end{macro} % % \subsection{Setting keys for penalties}\label{subsec:set-penalties} % % \begin{macro}[int]{beginpenalty, midpenalty, endpenalty} % The three parameters \textcolor{red}{\texttt{\textbackslash}}|@beginparpenalty|, % \textcolor{red}{\texttt{\textbackslash}}|@itempenalty| and % \textcolor{red}{\texttt{\textbackslash}}|@endparpenalty| work together % to ensure that list environments look good, avoiding unsightly page % breaks that can break the flow of the \myenv[no-index]{list}, so it's a good % idea to have some \mymeta{keys} to access these. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:nn { \keys_define:nn { enumext / #1 } { beginpenalty .int_set:c = { l_@@_beginparpenalty_ #2 _int }, beginpenalty .initial:n = -51, beginpenalty .value_required:n = true, midpenalty .int_set:c = { l_@@_itempenalty_ #2 _int }, midpenalty .initial:n = -51, midpenalty .value_required:n = true, endpenalty .int_set:c = { l_@@_endparpenalty_ #2 _int }, endpenalty .initial:n = -51, endpenalty .value_required:n = true, } } \clist_map_inline:Nn \c_@@_all_envs_clist { \@@_tmp:nn #1 } % \end{macrocode} % \end{macro} % % \subsection{Setting keys for vertical spaces}\label{subsec:set-vspaces} % % \begin{macro}[int]{topsep, partopsep, parsep, itemsep, noitemsep, nosep} % Define and set \mykey[env]{topsep}, \mykey[env]{partopsep}, \mykey[env]{parsep}, % \mykey[env]{itemsep}, \mykey[env]{noitemsep} and \mykey[env]{nosep} keys for % \myenv*[no-index]{enumext}, \myenv*[no-index]{enumext*}, \myenv*[no-index]{keyans} and % \myenv*[no-index]{keyans*} environments. % % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:nnnnnn { \keys_define:nn { enumext / #1 } { topsep .skip_set:c = { l_@@_topsep_ #2 _skip }, topsep .initial:n = {#3}, topsep .value_required:n = true, partopsep .skip_set:c = { l_@@_partopsep_ #2 _skip }, partopsep .initial:n = {#4}, partopsep .value_required:n = true, parsep .skip_set:c = { l_@@_parsep_ #2 _skip }, parsep .initial:n = {#5}, parsep .value_required:n = true, itemsep .skip_set:c = { l_@@_itemsep_ #2 _skip }, itemsep .initial:n = {#6}, itemsep .value_required:n = true, noitemsep .meta:n = { itemsep = 0pt, parsep = 0pt }, noitemsep .value_forbidden:n = true, nosep .meta:n = { itemsep = 0pt, parsep = 0pt, topsep = 0pt, partopsep = 0pt }, nosep .value_forbidden:n = true, } } % \end{macrocode} % Now the values are set based on the standard \myclass{article} class in % \mydim{10pt}. % \begin{macrocode} \@@_tmp:nnnnnn { level-1 } { i } { 8.0pt plus 2.0pt minus 4.0pt } { 2.0pt plus 1.0pt minus 1.0pt } { 4.0pt plus 2.0pt minus 1.0pt } { 4.0pt plus 2.0pt minus 1.0pt } \@@_tmp:nnnnnn { level-2 } { ii } { 4.0pt plus 2.0pt minus 1.0pt } { 2.0pt plus 1.0pt minus 1.0pt } { 2.0pt plus 1.0pt minus 1.0pt } { 2.0pt plus 1.0pt minus 1.0pt } \@@_tmp:nnnnnn { level-3 } { iii } { 2.0pt plus 1.0pt minus 1.0pt } { 1.0pt minus 1.0pt }{ 0pt }{ 2.0pt plus 1.0pt minus 1.0pt } \@@_tmp:nnnnnn { level-4 } { iv } { 2.0pt plus 1.0pt minus 1.0pt } { 1.0pt minus 1.0pt }{ 0pt }{ 2.0pt plus 1.0pt minus 1.0pt } \@@_tmp:nnnnnn { keyans } { v }{ 4.0pt plus 2.0pt minus 1.0pt } { 2.0pt plus 1.0pt minus 1.0pt }{ 2.0pt plus 1.0pt minus 1.0pt } { 2.0pt plus 1.0pt minus 1.0pt } \@@_tmp:nnnnnn { enumext* } { vii } { 8.0pt plus 2.0pt minus 4.0pt } { 2.0pt plus 1.0pt minus 1.0pt } { 4.0pt plus 2.0pt minus 1.0pt } { 4.0pt plus 2.0pt minus 1.0pt } \@@_tmp:nnnnnn { keyans* } { viii } { 4.0pt plus 2.0pt minus 1.0pt } { 2.0pt plus 1.0pt minus 1.0pt } { 2.0pt plus 1.0pt minus 1.0pt } { 2.0pt plus 1.0pt minus 1.0pt } % \end{macrocode} % \end{macro} % % \subsection{Setting \texttt{base-fix} key}\label{key:base-fix} % % When nesting starting right after |\item| (without material between them) there % is a problem with the alignment of the \emph{baseline} between the two environments. % One way to get around this problem is to start the paragraph with % \myhlc|\mode_leave_vertical:|, apply a negative |\vspace| and set the keys % \mykey{topsep}, \mykey{above} and \mykey{above}|*| equal to \mydim{0pt} for % the \emph{\enquote{first level}} of the nested \myenv*[no-index]{enumext} environment. % % \begin{macro}[int]{base-fix} % Defines the key \mykey[env]{base-fix} only for the \emph{\enquote{first level}} % of \myenv*[no-index]{enumext} environment. % \begin{macrocode} \keys_define:nn { enumext / level-1 } { base-fix .bool_set:N = \l_@@_base_line_fix_bool, base-fix .initial:n = false, base-fix .value_forbidden:n = true, } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_nested_base_line_fix:} % The function \myhlc|\@@_nested_base_line_fix:| passed to the \myhlc|\@@_parse_keys:n| % function in the definition of the \myenv*[no-index]{enumext} environment (\S\ref{env:enumext}) % will be responsible for applying the \emph{baseline correction} and % adjusting the \mymeta{keys} for the \myenv*[no-index]{enumext} environment and % the |\printkeyans| with \emph{starred argument} `|*|' (\S\ref{cmd:printkeyans}). % % First, the function code is implemented from the user side of the % \mykey{base-fix} key, that is, only the user knows when it is necessary % to apply it within the document in which case the variable % \myhlc|\l_@@_print_keyans_star_bool| set by the |\printkeyans| command is % false and the variable \myhlc|\l_@@_base_line_fix_bool| is true. % % The negative \emph{\enquote{vertical space}} is a line of text plus the % value of \mykey{parsep} of the \myenv*[no-index]{enumext*} environment, since % this is the gap that \hologo{TeX} leaves between the label of the |\item| and % the first line of the nested list. With \mykey{columns} greater than one this % gap does not include the \mykey{parsep}, so only the line of text is removed. % The value of |\parsep| is not used, because inside \myenv*[no-index]{enumext*} % it is equal to \mykey{itemsep}. % % Sets the values of the keys \mykey[env]{topsep}, \mykey[env]{above} % and \mykey[env]{above*} for the \emph{\enquote{first level}} of \myenv*[no-index]{enumext} % environment equal to \mydim{0pt} and finally sets the variable \myhlc|\l_@@_base_line_fix_bool| % to false. % \begin{macrocode} \cs_new_protected:Nn \@@_nested_base_line_fix: { \bool_lazy_all:nT { { \bool_if_p:N \l_@@_starred_first_bool } { \bool_if_p:N \l_@@_base_line_fix_bool } { \bool_not_p:n { \l_@@_print_keyans_star_bool } } } { \mode_leave_vertical: \vspace { -\dim_eval:n { \baselineskip + \int_compare:nNnTF { \l_@@_columns_i_int } > { 1 } { 0pt } { \l_@@_parsep_vii_skip } } } \keys_set:nn { enumext / level-1 } { topsep = 0pt, above = 0pt, above* = 0pt, } } % \end{macrocode} % When the |\printkeyans| command is run with the \emph{starred % argument} `|*|' the variable \myhlc|\l_@@_print_keyans_star_bool| is true % the negative space is added with \myhlc|\skip_vertical:n|, the \mypkg*[no-index]{expl3} % interface of \myhlc|\vskip|, instead of |\vspace|. After \myhlc|\mode_leave_vertical:| % \hologo{TeX} is in \mymeta{horizontal mode}, where |\vspace| would only store % the skip in a \myhlc|\vadjust| to be applied after the current line, whereas \myhlc|\vskip| % ends the (still empty) paragraph and applies the skip immediately. % The skip is followed by \myhlc|\skip_vertical:N \c_zero_skip| so that the % negative space is not the last item of the vertical list. % \begin{macrocode} \bool_lazy_and:nnT { \bool_if_p:N \l_@@_starred_first_bool } { \bool_if_p:N \l_@@_print_keyans_star_bool } { \mode_leave_vertical: \skip_vertical:n { -\baselineskip } \skip_vertical:N \c_zero_skip \keys_set:nn { enumext / level-1 } { topsep = 0pt, above = 0pt, above* = 0pt, } } \bool_set_false:N \l_@@_base_line_fix_bool } % \end{macrocode} % \end{macro} % % \subsection{Setting keys for horizontal spaces}\label{key:list-indent} % % \begin{macro}[int]{itemindent, rightmargin, listparindent, list-offset, list-indent} % Define and set \mykey[env]{itemindent}, \mykey[env]{rightmargin}, \mykey[env]{listparindent}, \mykey[env]{list-offset} % and \mykey[env]{list-indent} keys for \myenv*[no-index]{enumext}, \myenv*[no-index]{enumext*}, \myenv*[no-index]{keyans} and % \myenv*[no-index]{keyans*} environments. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:nn { \keys_define:nn { enumext / #1 } { itemindent .dim_set:c = { l_@@_fake_item_indent_ #2 _dim }, itemindent .value_required:n = true, rightmargin .dim_set:c = { l_@@_rightmargin_ #2 _dim }, rightmargin .value_required:n = true, listparindent .dim_set:c = { l_@@_listparindent_ #2 _dim }, listparindent .value_required:n = true, list-offset .dim_set:c = { l_@@_listoffset_ #2 _dim }, list-offset .value_required:n = true, list-indent .code:n = { \bool_set_true:c { l_@@_leftmargin_tmp_ #2 _bool } \dim_set:cn { l_@@_leftmargin_tmp_ #2 _dim } {##1} }, list-indent .value_required:n = true, } } \clist_map_inline:nn { {level-1}{i}, {level-2}{ii}, {level-3}{iii}, {level-4}{iv}, {keyans}{v} } { \@@_tmp:nn #1 } % \end{macrocode} % % For \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} environments the situation % is a bit different, the \mykey{list-indent} key behaves like the \mykey{list-offset} key. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:nn { \keys_define:nn { enumext / #1 } { itemindent .dim_set:c = { l_@@_fake_item_indent_ #2 _dim }, itemindent .value_required:n = true, rightmargin .dim_set:c = { l_@@_rightmargin_ #2 _dim }, rightmargin .value_required:n = true, listparindent .dim_set:c = { l_@@_listparindent_ #2 _dim }, listparindent .value_required:n = true, list-offset .dim_set:c = { l_@@_listoffset_ #2 _dim }, list-offset .value_required:n = true, list-indent .meta:n = { list-offset = ##1 }, list-indent .value_required:n = true, } } \clist_map_inline:nn { {enumext*}{vii}, {keyans*}{viii} } { \@@_tmp:nn #1 } % \end{macrocode} % \end{macro} % % \subsubsection{Functions for setting the fake \texttt{itemindent}}\label{subsubsec:fake-indent} % % \begin{macro}[int]{\@@_fake_item_indent:, \@@_keyans_fake_item_indent:, % \@@_fake_item_indent_vii:, \@@_fake_item_indent_viii:} % % The \mykey[env]{itemindent} key does not set the value of |\itemindent|, it only % sets the value of the \emph{horizontal space} applied using \myhlc|\skip_horizontal:N|. This % value is stored in the variable and only applied when it is greater % than \mydim{0pt}. Here it is necessary to place % \myhlc|\mode_leave_vertical:| and the plain \hologo{TeX} macro % \myhlc|\ignorespaces| to avoid unwanted extra space when using the % \mykey{itemindent} key. % \begin{macrocode} \cs_set_protected:Nn \@@_fake_item_indent: { \dim_compare:nNnT { \dim_use:c { l_@@_fake_item_indent_ \@@_level: _dim } } > { \c_zero_dim } { \tl_set:ce { l_@@_fake_item_indent_ \@@_level: _tl } { \exp_not:N \mode_leave_vertical: \exp_not:n { \skip_horizontal:n } { \dim_use:c { l_@@_fake_item_indent_ \@@_level: _dim } } \exp_not:N \ignorespaces } } } \cs_set_protected:Nn \@@_keyans_fake_item_indent: { \dim_compare:nNnT { \l_@@_fake_item_indent_v_dim } > { \c_zero_dim } { \tl_set:Ne \l_@@_fake_item_indent_v_tl { \exp_not:N \mode_leave_vertical: \exp_not:N \skip_horizontal:N \l_@@_fake_item_indent_v_dim \exp_not:N \ignorespaces } } } \cs_set_protected:Nn \@@_fake_item_indent_vii: { \dim_compare:nNnT { \l_@@_fake_item_indent_vii_dim } > { \c_zero_dim } { \tl_set:Ne \l_@@_fake_item_indent_vii_tl { \exp_not:N \skip_horizontal:N \l_@@_fake_item_indent_vii_dim \exp_not:N \ignorespaces } } } \cs_set_protected:Nn \@@_fake_item_indent_viii: { \dim_compare:nNnT { \l_@@_fake_item_indent_viii_dim } > { \c_zero_dim } { \tl_set:Ne \l_@@_fake_item_indent_viii_tl { \exp_not:N \skip_horizontal:N \l_@@_fake_item_indent_viii_dim \exp_not:N \ignorespaces } } } % \end{macrocode} % \end{macro} % % \subsection{Setting \texttt{show-length} key}\label{subsec:set-show-length} % % \begin{macro}[int]{show-length} % Define and set \mykey[env]{show-length} key for \myenv*[no-index]{enumext}, % \myenv*[no-index]{enumext*}, \myenv*[no-index]{keyans} and \myenv*[no-index]{keyans*} environments. % The function sets the boolean variable \myhlc|\l_@@_show_length_X_bool| % used in the definition of all environments to |true| % and calls the function \myhlc|\@@_show_length:nnn| which prints all the % values of the \emph{\enquote{vertical}} and \emph{\enquote{horizontal}} % parameters calculated and used. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:nn { \keys_define:nn { enumext / #1 } { show-length .bool_set:c = { l_@@_show_length_ #2 _bool }, show-length .initial:n = false, show-length .value_required:n = true, } } \clist_map_inline:Nn \c_@@_all_envs_clist { \@@_tmp:nn #1 } % \end{macrocode} % \end{macro} % % \subsection{Setting \texttt{item-break} key}\label{subsec:set-item-break} % % \begin{macro}[int]{item-break} % Define and set \mykey[env]{item-break} key for \myenv*[no-index]{enumext*} and % \myenv*[no-index]{keyans*} environments. The key sets the boolean variable % \myhlc|\l_@@_item_break_X_bool|, which is |false| by default, and is % used when each \myhlc|\item| starts (\S\ref{env:starred}). % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:nn { \keys_define:nn { enumext / #1 } { item-break .bool_set:c = { l_@@_item_break_ #2 _bool }, item-break .initial:n = false, item-break .value_required:n = true, } } \clist_map_inline:nn { {enumext*}{vii}, {keyans*}{viii} } { \@@_tmp:nn #1 } % \end{macrocode} % \end{macro} % % \subsection{Setting \texttt{before}, \texttt{after} and \texttt{first} keys}\label{key:before} % % \begin{macro}[int]{before, before*, after, first} % Define and set \mykey[env,foreachkeyans]{before}, \mykey[env]{before*}, \mykey[env,foreachkeyans]{after} and \mykey[env]{first} keys % for \myenv*[no-index]{enumext}, \myenv*[no-index]{enumext*}, \myenv*[no-index]{keyans} and \myenv*[no-index]{keyans*} environments. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:nn { \keys_define:nn { enumext / #1 } { before .tl_set:c = { l_@@_before_no_starred_key_ #2 _tl }, before .value_required:n = true, before* .tl_set:c = { l_@@_before_starred_key_ #2 _tl }, before* .value_required:n = true, after .tl_set:c = { l_@@_after_stop_list_ #2 _tl }, after .value_required:n = true, first .tl_set:c = { l_@@_after_list_args_ #2 _tl }, first .value_required:n = true, } } \clist_map_inline:Nn \c_@@_all_envs_clist { \@@_tmp:nn #1 } % \end{macrocode} % \end{macro} % % \subsubsection{Functions for \texttt{before}, \texttt{after} and \texttt{first} keys in \env{enumext}} % % \begin{macro}[int]{\@@_before_args_exec:, \@@_before_keys_exec:, % \@@_after_stop_list:, \@@_after_args_exec:} % The function \myhlc|\@@_before_args_exec:| executes the \mymarg{code} set by the % \mykey[env]{before*} key \emph{\enquote{before}} the \myenv*[no-index]{enumext} % environment is started. The \mymarg{code} is executed \emph{\enquote{without}} % knowing any definition of the \mymarg{arg two} of the list: % \mymarg[cbc=module_name,ac=araracolor]{code}|\list|\mymarg{arg one}\mymarg{arg two}. % \begin{macrocode} \cs_new_protected:Nn \@@_before_args_exec: { \tl_use:c { l_@@_before_starred_key_ \@@_level: _tl } } % \end{macrocode} % The function \myhlc|\@@_before_keys_exec:| executes the \mymarg{code} set by the % \mykey[env,foreachkeyans]{before} key \emph{\enquote{before}} the \myenv*[no-index]{enumext} % environment is started in \emph{second argument} of the list. The % \mymarg{code} is executed \emph{\enquote{knowing}} % all the definitions and values provided by the \mymeta{keys}: % |\list|\mymarg{arg one}|{|\mymeta{arg two}\mymarg[cbc=module_name,ac=araracolor]{code}|}| % \begin{macrocode} \cs_new_protected:Nn \@@_before_keys_exec: { \tl_use:c { l_@@_before_no_starred_key_ \@@_level: _tl } } % \end{macrocode} % The function \myhlc|\@@_after_stop_list:| executes the \mymarg{code} set by the % \mykey[env,foreachkeyans]{after} key \emph{\enquote{after}} the \myenv*[no-index]{enumext} % environment has finished: |\endlist|\mymarg[cbc=module_name,ac=araracolor]{code}. % \begin{macrocode} \cs_new_protected:Nn \@@_after_stop_list: { \tl_use:c { l_@@_after_stop_list_ \@@_level: _tl } } % \end{macrocode} % The function \myhlc|\@@_after_args_exec:| executes the \mymarg{code} set by the % \mykey[env]{first} key after the end of the second argument of the list % defining the \myenv*[no-index]{enumext} environment, just before the first % occurrence of |\item|: |\list|\mymarg{arg one}\mymarg{arg two}\mymarg[cbc=module_name,ac=araracolor]{code}|\item|. % \begin{macrocode} \cs_new_protected:Nn \@@_after_args_exec: { \tl_use:c { l_@@_after_list_args_ \@@_level: _tl } } % \end{macrocode} % \end{macro} % % \subsubsection{Functions for \texttt{before}, \texttt{after} and \texttt{first} keys in \env{keyans}} % % \begin{macro}[int]{\@@_before_args_exec_v:, \@@_before_keys_exec_v:, % \@@_after_stop_list_v:, \@@_after_args_exec_v:} % Same implementation as the one used in the \myenv*[no-index]{enumext} environment. % \begin{macrocode} \cs_new_protected:Nn \@@_before_args_exec_v: { \tl_use:N \l_@@_before_starred_key_v_tl } \cs_new_protected:Nn \@@_before_keys_exec_v: { \tl_use:N \l_@@_before_no_starred_key_v_tl } \cs_new_protected:Nn \@@_after_stop_list_v: { \tl_use:N \l_@@_after_stop_list_v_tl } \cs_new_protected:Nn \@@_after_args_exec_v: { \tl_use:N \l_@@_after_list_args_v_tl } % \end{macrocode} % \end{macro} % % \subsubsection{Functions for \texttt{before}, \texttt{after} and \texttt{first} keys in \env{enumext*} and \env{keyans*}} % % \begin{macro}[int]{\@@_before_args_exec_vii:, \@@_before_args_exec_viii:, % \@@_before_keys_exec_vii:, \@@_before_keys_exec_viii:, % \@@_after_stop_list_vii:, \@@_after_stop_list_viii:} % Same implementation as the one used in the \myenv*[no-index]{enumext} environment, % except that there are no \myhlc|\@@_after_args_exec_vii:| and % \myhlc|\@@_after_args_exec_viii:| functions: the \mymarg{code} set by the % \mykey[env]{first} key is used directly by \myhlc|\@@_start_item_vii:w| and % \myhlc|\@@_start_item_viii:w|, inside the \env{minipage} of each \cs{item}. % \begin{macrocode} \cs_new_protected:Nn \@@_before_args_exec_vii: { \tl_use:N \l_@@_before_starred_key_vii_tl } \cs_new_protected:Nn \@@_before_args_exec_viii: { \tl_use:N \l_@@_before_starred_key_viii_tl } \cs_new_protected:Nn \@@_before_keys_exec_vii: { \tl_use:N \l_@@_before_no_starred_key_vii_tl } \cs_new_protected:Nn \@@_before_keys_exec_viii: { \tl_use:N \l_@@_before_no_starred_key_viii_tl } \cs_new_protected:Nn \@@_after_stop_list_vii: { \tl_use:N \l_@@_after_stop_list_vii_tl } \cs_new_protected:Nn \@@_after_stop_list_viii: { \tl_use:N \l_@@_after_stop_list_viii_tl } % \end{macrocode} % \end{macro} % % \subsection{Setting keys for \env{multicols} and \env{minipage}}\label{key:mini-multi} % % \begin{macro}[int]{mini-env, mini-sep, columns-sep, columns, mini-right, mini-right*} % The default value of the \mykey[env]{columns-sep} key is zero; when the % value is zero it is calculated in the internal definition of the % environments from the dimension variable \myhlc|\l_@@_columns_sep_X_dim|. % Define and set \mykey[env]{mini-env}, \mykey[env]{mini-sep}, \mykey{columns-sep} % and \mykey[env]{columns} keys for \myenv*[no-index]{enumext}, \myenv*[no-index]{enumext*}, \myenv*[no-index]{keyans} and % \myenv*[no-index]{keyans*} environments. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:nn { \keys_define:nn { enumext / #1 } { mini-env .dim_set:c = { l_@@_minipage_right_ #2 _dim }, mini-env .value_required:n = true, mini-sep .dim_set:c = { l_@@_minipage_hsep_ #2 _dim }, mini-sep .initial:n = 0.3333em, mini-sep .value_required:n = true, columns-sep .dim_set:c = { l_@@_columns_sep_ #2 _dim }, columns-sep .value_required:n = true, columns .int_set:c = { l_@@_columns_ #2 _int }, columns .initial:n = 1, columns .value_required:n = true, } } \clist_map_inline:Nn \c_@@_all_envs_clist { \@@_tmp:nn #1 } % \end{macrocode} % % For \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} environments the situation % is a bit different, the command |\miniright| is not available, so the % keys \mykey[env]{mini-right} and \mykey[env]{mini-right*} are added to implement support for % \myenv[no-index]{minipage} environment. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:nn { \keys_define:nn { enumext / #1 } { mini-right .tl_gset:c = { g_@@_miniright_code_ #2 _tl }, mini-right .value_required:n = true, mini-right* .code:n = { \bool_gset_true:c { g_@@_minipage_center_ #2 _bool } \keys_set:nn { enumext / #1 } { mini-right = {##1} } }, mini-right* .value_required:n = true, } } \clist_map_inline:nn { {enumext*}{vii}, {keyans*}{viii} } { \@@_tmp:nn #1 } % \end{macrocode} % \end{macro} % % \subsection{Adjustment of vertical spaces for \env{multicols}} \label{subsec:vspace-multicols} % % When nesting a \emph{\enquote{list environment}} inside the \myenv[no-index]{multicols} environment, % the values of the \emph{\enquote{vertical spaces}} are lost, basically the % \myenv[no-index]{multicols} environment takes control over them. Graphically, this can be seen in figure~\ref{fig:six}. % % \begin{figure}[!htbp] % \centering % \begin{tikzpicture}[line cap=round,line join=round,x=0.8cm,y=0.8cm,every node/.style={font=\footnotesize}] % \draw[color=white] (7.0,6.10) rectangle (17.5,6.50) node[pos=.5,text=black] { \textcolor{blue}{\texttt{\textbackslash{}multicolsep [±\textbackslash{}topskip]}} };% space above % \draw[color=white] (7.0,4.85) rectangle (17.5,5.25) node[pos=.5,text=black] { \textcolor{blue}{\texttt{\textbackslash{}multicolsep [±\textbackslash{}prevdepth?]}} };% space below % \draw[color=white] (2.0,6.10) rectangle (5,6.50) node[pos=.5,text=keyname,font=\footnotesize\ttfamily] { topsep };% topsep above % \draw[color=white] (2.0,4.85) rectangle (5,5.25) node[pos=.5,text=keyname,font=\footnotesize\ttfamily] { topsep };% topsep below % \draw[<->,color=gray] (2.0,7.0) --node[above,text=keyname]{\vphantom{p}\texttt{labelwidth}} (5.0,7.0); % \draw[<->,color=gray] (5.0,7.0) --node[above,text=keyname]{\texttt{labelsep}} (7.0,7.0); % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (2.0,6.5) rectangle (5.0,6.85);% labelwidth % \draw[->,color=lightgray,shorten >=3pt] (4.5,6.3) -- (7.0,6.3); % glue space = topsep (above) % \draw[->,color=lightgray,shorten >=3pt] (4.5,5.05) -- (7.0,5.05); % glue space = topsep (above) % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (5.0,6.5) rectangle (7.0,6.85);% labelsep % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,6.5) rectangle (17.5,6.85);% item width % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,5.25) rectangle (11.5,6.10) node[pos=.5,text=black] % {\begin{tabular}{c} % \texttt{column one} \\ % \textcolor{blue}{\emph{nested list or items}} % \end{tabular}}; % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (13.5,5.25) rectangle (17.5,6.10) node[pos=.5,text=black] % {\begin{tabular}{c} % \texttt{column two} \\ % \textcolor{blue}{\emph{nested list or items}} % \end{tabular}}; % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (2.0,4.5) rectangle (5.0,4.85);% labelwidth % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (5.0,4.5) rectangle (7.0,4.85);% labelsep % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,4.5) rectangle (17.5,4.85);% item width % \end{tikzpicture} % \caption{Representation of the vertical space in \myenv[no-index]{multicols} for a nested level.} % \label{fig:six} % \end{figure} % % To keep the desired spaces \emph{above} and \emph{below} in the \emph{\enquote{list environment}} % (|\topsep + [\partopsep]|) it is necessary to \emph{\enquote{adjust}} the spaces added % by the \myenv[no-index]{multicols} environment. % The most appropriate option in this case is to use a \emph{\enquote{context sensitive}} % vertical space with |\addvspace|. % % \begin{important}* % It should be made clear that the implementation here is a \emph{\enquote{bit % questionable}}. At first glance doing |\multicolsep=\topsep| seemed right, but the results % were not always as expected. An almost \emph{imperceptible} detail is that in some cases the % |\itemsep| values are \emph{\enquote{stretched}}, possibly due to % the use of |\raggedcolumns| and this affects the lower space when % closing the environment, which is \emph{\enquote{smaller}} than % expected. My attempts to find the correct values using |\showoutput| and % \myhlc|\showboxdepth| absolutely failed. % \end{important} % % \subsubsection{Adjustment of vertical spaces for \env{multicols} in \env{enumext}} % % % \begin{macro}[int]{\@@_multi_set_vskip:} % The function \myhlc|\@@_multi_set_vskip:| will take care of determining the % \emph{\enquote{adjusted spaces}} applied \emph{\enquote{above}} and % \emph{\enquote{below}} the \myenv[no-index]{multicols} environment in % \myenv*[no-index]{enumext}. % % The default values are set taking into account that \hologo{TeX} is % in \mymeta{horizontal mode}, then the settings for the % \mymeta{vertical mode}, in which |\partopsep| comes into play, are made. % % Set the values of \myhlc|\l_@@_multicols_above_X_skip| and \myhlc|\l_@@_multicols_below_X_skip| % equal to the value of |\topsep| in the \emph{current level}. % \begin{macrocode} \cs_new_protected:Nn \@@_multi_set_vskip: { \skip_set:cn { l_@@_multicols_above_ \@@_level: _skip } { \skip_use:c { l_@@_topsep_ \@@_level: _skip } } \skip_set:cn { l_@@_multicols_below_ \@@_level: _skip } { \skip_use:c { l_@@_topsep_ \@@_level: _skip } } \@@_add_pre_parsep: } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_add_pre_parsep:} % The function \myhlc|\@@_add_pre_parsep:| \emph{\enquote{adjusts}} the value % of \myhlc|\l_@@_multicols_above_X_skip| detecting the value of % |\parsep| from the previous level. This is necessary since % |\parsep| from the previous level affects the \emph{vertical spaces}. % \begin{macrocode} \cs_new_protected:Nn \@@_add_pre_parsep: { \int_case:nn { \l_@@_level_int } { { 2 } { \skip_if_eq:nnF { \l_@@_parsep_i_skip } { \c_zero_skip } { \skip_add:Nn \l_@@_multicols_above_ii_skip { \l_@@_parsep_i_skip } } } { 3 } { \skip_if_eq:nnF { \l_@@_parsep_ii_skip } { \c_zero_skip } { \skip_add:Nn \l_@@_multicols_above_iii_skip { \l_@@_parsep_ii_skip } } } { 4 } { \skip_if_eq:nnF { \l_@@_parsep_iii_skip } { \c_zero_skip } { \skip_add:Nn \l_@@_multicols_above_iv_skip { \l_@@_parsep_iii_skip } } } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_multi_addvspace:} % The function \myhlc|\@@_multi_addvspace:| will apply the spaces set using % |\addvspace| \emph{\enquote{above}} the \myenv[no-index]{multicols} environment % in \myenv*[no-index]{enumext}, taking into account whether \hologo{TeX} is in % \mymeta{horizontal mode} or \mymeta{vertical mode}. % \begin{macrocode} \cs_new_protected:Nn \@@_multi_addvspace: { \@@_multi_set_vskip: \mode_if_vertical:T { \skip_add:cn { l_@@_multicols_above_ \@@_level: _skip } { \skip_use:c { l_@@_partopsep_ \@@_level: _skip } } \skip_add:cn { l_@@_multicols_below_ \@@_level: _skip } { \skip_use:c { l_@@_partopsep_ \@@_level: _skip } } } \par\nopagebreak \addvspace{ \skip_use:c { l_@@_multicols_above_ \@@_level: _skip } } } % \end{macrocode} % \end{macro} % % \subsubsection{Adjustment of vertical spaces for \env{multicols} in \env{keyans}} % % \begin{macro}[int]{\@@_keyans_multi_set_vskip:, \@@_keyans_multi_addvspace:} % The function \myhlc|\@@_keyans_multi_set_vskip:| will take care of determining the % \emph{\enquote{adjusted spaces}} applied \emph{\enquote{above}} and % \emph{\enquote{below}} the \myenv[no-index]{multicols} environment in % \myenv*[no-index]{keyans}. The implementation of this function is the same % as the one used in \myenv*[no-index]{enumext}, including the value of % |\parsep| of the previous level, which is added to the space \emph{\enquote{above}}. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_multi_set_vskip: { \skip_set:Nn \l_@@_multicols_above_v_skip { \l_@@_topsep_v_skip } \skip_set:Nn \l_@@_multicols_below_v_skip { \l_@@_topsep_v_skip } \skip_if_eq:nnF { \l_@@_parsep_i_skip } { \c_zero_skip } { \skip_add:Nn \l_@@_multicols_above_v_skip { \l_@@_parsep_i_skip } } } \cs_new_protected:Nn \@@_keyans_multi_addvspace: { \@@_keyans_multi_set_vskip: \mode_if_vertical:T { \skip_add:Nn \l_@@_multicols_above_v_skip { \skip_use:N \l_@@_partopsep_v_skip } \skip_add:Nn \l_@@_multicols_below_v_skip { \skip_use:N \l_@@_partopsep_v_skip } } \par\nopagebreak \addvspace{ \l_@@_multicols_above_v_skip } } % \end{macrocode} % \end{macro} % % \subsection{Adjustment of vertical spaces for \env{minipage}}\label{subsec:vspace-minipage} % % When nesting a \emph{\enquote{list environment}} within the \myenv[no-index]{minipage} environment, % the values of the \emph{\enquote{vertical spaces}} are lost. Graphically it can % be seen like in the figure~\ref{fig:seven}. % % \begin{figure}[!htbp] % \centering % \begin{tikzpicture}[line cap=round,line join=round,x=0.8cm,y=0.8cm,every node/.style={font=\footnotesize}] % \draw[color=white] (7.0,6.10) rectangle (12.5,6.5) node[pos=.5,text=black]% % { \textcolor{blue}{\texttt{space above left}} };% space above left % \draw[color=white] (13.5,6.10) rectangle (17.5,6.5) node[pos=.5,text=black]% % { \textcolor{blue}{\texttt{space above right}} };% space above right % \draw[color=white] (7.0,4.85) rectangle (17.5,5.25) node[pos=.5,text=black]% % { \textcolor{blue}{\texttt{space below minipage's}} };% space below after second % \draw[color=white] (2.0,6.10) rectangle (5,6.50) node[pos=.5,text=keyname,font=\footnotesize\ttfamily] { topsep };% topsep above % \draw[color=white] (2.0,4.85) rectangle (5,5.25) node[pos=.5,text=keyname,font=\footnotesize\ttfamily] { topsep };% topsep below % \draw[->,color=lightgray,shorten >=3pt] (4.5,6.3) -- (7.0,6.3); % glue space = topsep (above) % \draw[->,color=lightgray,shorten >=3pt] (4.5,5.05) -- (7.0,5.05); % glue space = topsep (above) % \draw[<->,color=gray] (2.0,7.0) --node[above,text=keyname]{\vphantom{p}\texttt{labelwidth}} (5.0,7.0); % \draw[<->,color=gray] (5.0,7.0) --node[above,text=keyname]{\texttt{labelsep}} (7.0,7.0); % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (2.0,6.5) rectangle (5.0,6.85);% labelwidth % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (5.0,6.5) rectangle (7.0,6.85);% labelsep % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,6.5) rectangle (17.5,6.85);% item width % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,5.25) rectangle (12.5,6.10) node[pos=.5,text=black]% % {\begin{tabular}{c} % \texttt{minipage left [t]} \\ % \textcolor{blue}{\emph{nested list}} % \end{tabular}}; % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (13.5,5.25) rectangle (17.5,6.10) node[pos=.5,text=black]% % {\begin{tabular}{c} % \texttt{minipage right [t]} \\ % \textcolor{blue}{\emph{drawing or tabular}} % \end{tabular}}; % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (2.0,4.5) rectangle (5.0,4.85);% labelwidth % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (5.0,4.5) rectangle (7.0,4.85);% labelsep % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,4.5) rectangle (17.5,4.85);% item width % \end{tikzpicture} % \caption{Representation of the \myenv[no-index]{minipage} spacing adjustment for a nested level.} % \label{fig:seven} % \end{figure} % % To keep the \emph{\enquote{left}} and \emph{\enquote{right}} % environments \emph{\enquote{aligned on top}}, preserving the \myhlc|\baselineskip| % and keeping the desired \emph{\enquote{spaces}} (|\topsep + [\partopsep]|) it is necessary % to \emph{\enquote{adjust}} the \emph{\enquote{vertical spaces}} % for \myenv[no-index]{minipage} environments. % % Here there are several complications that must be circumvented: the % \myenv[no-index]{minipage} environment eliminates the \enquote{top} spaces, the \myenv[no-index]{multicols} % environment can be nested in the \myenv[no-index]{minipage} environment, the \enquote{top} and % \enquote{bottom} spaces are affected when |topsep=|\mydim{0pt} and to this is added the % |\partopsep| parameter that comes into action according to whether \hologo{TeX} % is in \mymeta{horizontal mode} or \mymeta{vertical mode}. Depending on these cases, the % spaces are computed and added with |\addvspace| to % obtain the \emph{\enquote{desired vertical spacing}}. % % \begin{important}* % The \enquote{top} and \enquote{bottom} spaces cannot be read directly from the % \emph{glue} produced by the \myenv[no-index]{minipage} environment, and % when \myenv[no-index]{multicols} is nested the depth of its last line is % lost when it ends. For this reason the spaces on the \emph{\enquote{left side}} are % not obtained from fixed fractions of |\strutbox|: % the space \emph{\enquote{above}} is computed from \myhlc|\prevdepth| and the % current \myhlc|\baselineskip|, which is the same \emph{glue} that \hologo{TeX} inserts % between two lines, and the space \emph{\enquote{below}} is stored together with % the depth of the last line when the environment on the \emph{\enquote{left side}} % ends, to be applied once the environment on the \emph{\enquote{right side}} % is closed. In this way the spaces follow the size of the font % used in the document. % \end{important} % % \subsubsection{Definition of variables} % % \begin{variable}[int]{ % \l_@@_minipage_right_skip, % \l_@@_mini_prev_dim, % \l_@@_mini_gap_dim, % \l_@@_mini_last_box, % \g_@@_mini_dp_dim, % \g_@@_mini_end_skip, % \g_@@_mini_end_bool, % } % Internal variables used by the keys \mykey{mini-env} and \mykey{mini-sep} % (\S\ref{subsec:vspace-minipage}). The variable \myhlc|\l_@@_minipage_right_skip| % holds the space applied \emph{\enquote{above}} the \myhlc|\@@_mini_page| % environment on the \emph{\enquote{right side}} and \emph{\enquote{below}} % the \myenv[no-index]{multicols} environment. The variables % \myhlc|\l_@@_mini_prev_dim|, \myhlc|\l_@@_mini_gap_dim| and % \myhlc|\l_@@_mini_last_box| are used to compute the space % \emph{\enquote{above}} and to recover the last box of the \myenv[no-index]{multicols} % environment. The variables \myhlc|\g_@@_mini_dp_dim| and % \myhlc|\g_@@_mini_end_skip| store the depth of the last line and the % space \emph{\enquote{below}}, while \myhlc|\g_@@_mini_end_bool| indicates % that both are pending to be applied. % \begin{macrocode} \skip_new:N \l_@@_minipage_right_skip \dim_new:N \l_@@_mini_prev_dim \dim_new:N \l_@@_mini_gap_dim \box_new:N \l_@@_mini_last_box \dim_new:N \g_@@_mini_dp_dim \skip_new:N \g_@@_mini_end_skip \bool_new:N \g_@@_mini_end_bool % \end{macrocode} % \end{variable} % % \subsubsection{Definition of error messages} % % \begin{macro}[int]{wrong-miniright-place, wrong-miniright-use, % wrong-miniright-starred, many-miniright-used} % Messages used by |\miniright| command. % \begin{macrocode} \msg_new:nnnn { enumext } { wrong-miniright-place } { Wrong~place~for~'\token_to_str:N \miniright'~\msg_line_context:. } { Works~in~'enumext'~and~'keyans'~with~key~'mini-env'. } \msg_new:nnnn { enumext } { wrong-miniright-use } { Wrong~use~for~'\token_to_str:N \miniright'~\msg_line_context:. } { '\token_to_str:N \miniright'~needs~a~key~'mini-env'. } \msg_new:nnnn { enumext } { wrong-miniright-starred } { Can't~use~'\token_to_str:N \miniright'~in~starred~environments~ \msg_line_context:. } { In~'enumext*'~and~'keyans*'~use~the~keys~'mini-right'~or~ 'mini-right*'~instead. } \msg_new:nnnn { enumext } { many-miniright-used } { Can't~use~'\token_to_str:N \miniright'~more~than~once~ \msg_line_context:. } { '\token_to_str:N \miniright'~can~be~used~only~once~in~each~ environment. } % \end{macrocode} % \end{macro} % % \subsubsection{Computation of the vertical spaces for \env{minipage}} % % \begin{macro}[int]{\@@_mini_baselineskip:} % The function \myhlc|\@@_mini_baselineskip:| adds with |\addvspace| the space % that \hologo{TeX} would insert between the previous line and a line of text % whose height is that of the letter \enquote{l}, that is, % \myhlc|\baselineskip| minus \myhlc|\prevdepth| minus that height, never less than % \myhlc|\lineskip|. If there is no previous line (\myhlc|\prevdepth| is |-1000pt|) the space % is zero. The \myhlc|\nointerlineskip| command is executed before the space is % added, to prevent the \emph{glue} of the baseline from being added % again between this space and the next box. % \begin{macrocode} \cs_new_protected:Nn \@@_mini_baselineskip: { \dim_set:Nn \l_@@_mini_prev_dim { \prevdepth } \nointerlineskip \dim_compare:nNnTF { \l_@@_mini_prev_dim } < { -999pt } { \dim_zero:N \l_@@_mini_gap_dim } { \dim_set:Nn \l_@@_mini_gap_dim { \baselineskip - \l_@@_mini_prev_dim - \fontcharht\font`l } \dim_compare:nNnT { \l_@@_mini_gap_dim } < { \lineskip } { \dim_set_eq:NN \l_@@_mini_gap_dim \lineskip } } \addvspace{ \l_@@_mini_gap_dim } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_mini_capture_end:, \@@_mini_capture_multicols:, \@@_mini_apply_end:} % The function \myhlc|\@@_mini_capture_end:| stores in \myhlc|\g_@@_mini_dp_dim| the % value of \myhlc|\prevdepth|, removes the last \emph{glue} (if any) saving its value in % \myhlc|\g_@@_mini_end_skip| and sets \myhlc|\g_@@_mini_end_bool| to |true|. % The function \myhlc|\@@_mini_capture_multicols:| does the same after a % \myenv[no-index]{multicols} environment, where \myhlc|\prevdepth| is not reliable: % the last box is recovered with \myhlc|\lastbox|, its depth is stored and the box % is put back, and the stored space is \myhlc|\l_@@_minipage_right_skip|. % The function \myhlc|\@@_mini_apply_end:| is called after closing the % environment on the \emph{\enquote{right side}}: if there is something stored, it % restores \myhlc|\prevdepth| and adds the stored space with |\addvspace|, so that the % space \emph{\enquote{below}} is measured from the last line of the environment % on the \emph{\enquote{left side}}. % \begin{macrocode} \cs_new_protected:Nn \@@_mini_capture_end: { \dim_gset:Nn \g_@@_mini_dp_dim { \prevdepth } \skip_gzero:N \g_@@_mini_end_skip \int_compare:nNnT { \lastnodetype } = { 11 } { \skip_gset:Nn \g_@@_mini_end_skip { \lastskip } \unskip } \bool_gset_true:N \g_@@_mini_end_bool } \cs_new_protected:Nn \@@_mini_capture_multicols: { \int_compare:nNnTF { \lastnodetype } = { 1 } { \box_set_to_last:N \l_@@_mini_last_box \dim_gset:Nn \g_@@_mini_dp_dim { \box_dp:N \l_@@_mini_last_box } \nointerlineskip \box_use_drop:N \l_@@_mini_last_box } { \dim_gset:Nn \g_@@_mini_dp_dim { \prevdepth } } \skip_gset_eq:NN \g_@@_mini_end_skip \l_@@_minipage_right_skip \bool_gset_true:N \g_@@_mini_end_bool } \cs_new_protected:Nn \@@_mini_apply_end: { \bool_if:NT \g_@@_mini_end_bool { \par \dim_compare:nNnF { \g_@@_mini_dp_dim } < { -999pt } { \dim_set_eq:NN \prevdepth \g_@@_mini_dp_dim } \addpenalty { \@endparpenalty } \addvspace { \g_@@_mini_end_skip } \bool_gset_false:N \g_@@_mini_end_bool } } % \end{macrocode} % \end{macro} % % \subsubsection{Adjustment of vertical spaces for \env{minipage} in \env{enumext}} % % \begin{macro}[int]{\@@_minipage_set_skip:, \@@_minipage_add_space:} % The function \myhlc|\@@_minipage_set_skip:| will take care of determining the % value of \myhlc|\l_@@_minipage_right_skip|, the space applied % \emph{\enquote{above}} the \myhlc|\@@_mini_page| environment on the % \emph{\enquote{right side}} and \emph{\enquote{below}} the % \myenv[no-index]{multicols} environment in \myenv*[no-index]{enumext}. % % First it sets the value of \myhlc|\l_@@_minipage_right_skip| equal to % |\topsep|, then checks if \hologo{TeX} is in \mymeta{vertical mode} and, if so, % adds |\partopsep|. % \begin{macrocode} \cs_new_protected:Nn \@@_minipage_set_skip: { \skip_set:Nn \l_@@_minipage_right_skip { \skip_use:c { l_@@_topsep_ \@@_level: _skip } } \mode_if_vertical:T { \skip_add:Nn \l_@@_minipage_right_skip { \skip_use:c { l_@@_partopsep_ \@@_level: _skip } } } % \end{macrocode} % Sets the value of \myhlc|\l_@@_multicols_above_X_skip| equal to % \myhlc|\l_@@_minipage_right_skip|. % \begin{macrocode} \skip_set_eq:cN { l_@@_multicols_above_ \@@_level: _skip } \l_@@_minipage_right_skip % \end{macrocode} % If the environment \myenv[no-index]{multicols} is active, it sets |\topskip=|\mydim{0pt} % and then makes |\multicolsep| have the same value as \myhlc|\l_@@_multicols_above_X_skip|. % \begin{macrocode} \int_compare:nNnT { \int_use:c { l_@@_columns_ \@@_level: _int } } > { 1 } { \skip_zero:N \topskip \skip_set_eq:Nc \multicolsep { l_@@_multicols_above_ \@@_level: _skip } } } % \end{macrocode} % The function \myhlc|\@@_minipage_add_space:| will apply the spaces on the \emph{\enquote{left side}} using % |\addvspace| \emph{\enquote{above}} the \myhlc|\@@_mini_page| % environment, taking into account whether \hologo{TeX} is in % \mymeta{horizontal mode} or \mymeta{vertical mode}. First the last % \mymeta{skip} or \mymeta{kern} is removed; in \mymeta{vertical mode} only % |\nopagebreak| is added, while in \mymeta{horizontal mode} the paragraph is % ended and |\partopsep| is set to zero, since this parameter comes into % play according to the mode and this affects the \emph{vertical spacing}. % The space is then added with the function \myhlc|\@@_mini_baselineskip:|. % \begin{macrocode} \cs_new_protected:Nn \@@_minipage_add_space: { \@@_minipage_set_skip: \@@_unskip_unkern: \mode_if_vertical:TF { \nopagebreak } { \par\nopagebreak \skip_zero:c { l_@@_partopsep_ \@@_level: _skip } } \@@_mini_baselineskip: } % \end{macrocode} % \end{macro} % % \subsubsection{Adjustment of vertical spaces for \env{minipage} in \env{keyans}} % % \begin{macro}[int]{\@@_keyans_minipage_set_skip:, \@@_keyans_minipage_add_space:} % The function \myhlc|\@@_keyans_minipage_set_skip:| will take care of determining the % value of \myhlc|\l_@@_minipage_right_skip| in \myenv*[no-index]{keyans}. The % implementation of this function is the same as the one used in % \myenv*[no-index]{enumext}. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_minipage_set_skip: { \skip_zero:N \l_@@_minipage_right_skip \skip_set:Nn \l_@@_minipage_right_skip { \l_@@_topsep_v_skip } \mode_if_vertical:T { \skip_add:Nn \l_@@_minipage_right_skip { \l_@@_partopsep_v_skip } } \skip_set_eq:NN \l_@@_multicols_above_v_skip \l_@@_minipage_right_skip \int_compare:nNnT { \l_@@_columns_v_int } > { 1 } { \skip_zero:N \topskip \skip_set_eq:NN \multicolsep \l_@@_minipage_right_skip } } \cs_new_protected:Nn \@@_keyans_minipage_add_space: { \@@_keyans_minipage_set_skip: \@@_unskip_unkern: \mode_if_vertical:TF { \nopagebreak } { \par\nopagebreak \skip_zero:N \l_@@_partopsep_v_skip } \@@_mini_baselineskip: } % \end{macrocode} % \end{macro} % % \subsubsection{Adjustment of vertical spaces for \env{minipage} in \env{enumext*} and \env{keyans*}} % % \begin{macro}[int]{\@@_mini_set_vskip_vii:, \@@_mini_set_vskip_viii:} % The functions \myhlc|\@@_mini_set_vskip_vii:| and \myhlc|\@@_mini_set_vskip_viii:| will take care of determining the % space applied \emph{\enquote{above}} the \myhlc|\@@_mini_page| environment on the % \emph{\enquote{right side}} in \myenv*[no-index]{enumext*} and % \myenv*[no-index]{keyans*}. It is stored in \myhlc|\g_@@_minipage_right_skip| % and has the same value as the |\topsep| of the environment, which is % the space that the list adds above the environment on the \emph{\enquote{left side}}. % \begin{macrocode} \cs_new_protected:Nn \@@_mini_set_vskip_vii: { \skip_gset:Nn \g_@@_minipage_right_skip { \l_@@_topsep_vii_skip } } \cs_new_protected:Nn \@@_mini_set_vskip_viii: { \skip_gset:Nn \g_@@_minipage_right_skip { \l_@@_topsep_viii_skip } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_mini_addvspace_vii:, \@@_mini_addvspace_viii:} % The functions \myhlc|\@@_mini_addvspace_vii:| and % \myhlc|\@@_mini_addvspace_viii:| will apply the vertical space % \emph{\enquote{only above}} the \myhlc|\@@_mini_page| environment on % the \emph{left side} when the \mykey[env]{mini-right} key is active in the % \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} environments, % using the function \myhlc|\@@_mini_baselineskip:|. % % Here it does NOT take into account whether \hologo{TeX} is in % \mymeta{horizontal mode} or \mymeta{vertical mode}, since |\partopsep| % is equal to \mydim{0pt} in both environments. % \begin{macrocode} \cs_new_protected:Nn \@@_mini_addvspace_vii: { \@@_mini_set_vskip_vii: \par\nopagebreak \@@_mini_baselineskip: } \cs_new_protected:Nn \@@_mini_addvspace_viii: { \@@_mini_set_vskip_viii: \par\nopagebreak \@@_mini_baselineskip: } % \end{macrocode} % \end{macro} % % \subsubsection{The command \cs{miniright}}\label{cmd:miniright} % % The command |\miniright| will close the \myhlc|\@@_mini_page| % environment on the \emph{\enquote{left side}}, open the \myhlc|\@@_mini_page| % environment on the \emph{\enquote{right side}} adding the \emph{adjusted vertical space}. % By default |\centering| is added when starting the \emph{\enquote{right side}} % environment. The \emph{starred argument} `|*|' inhibits the use of |\centering| % command i.e. the usual \hologo{LaTeX} justification is maintained in % the \myhlc|\@@_mini_page| on the \emph{\enquote{right side}}. % % \begin{macro}{\miniright} % The command accepts a \emph{starred argument} `|*|' in `|#1|'. First, some checks prevent the command from being executed outside the % \myenv*[no-index]{enumext} environment or somewhere inappropriate. Only the % first error found is reported and the command does nothing else. Then the % internal functions are called to execute it in the \myenv*[no-index]{enumext} and % \myenv*[no-index]{keyans} environments. % \begin{macrocode} \NewDocumentCommand \miniright { s } { % outside \bool_lazy_or:nnTF { \int_compare_p:nNn { \l_@@_keyans_pic_level_int } = { 1 } } { \bool_lazy_and_p:nn { \int_compare_p:nNn { \l_@@_level_int } = { 0 } } { \int_compare_p:nNn { \l_@@_level_h_int } = { 0 } } } { \msg_error:nn { enumext } { wrong-miniright-place } } { % starred env \bool_lazy_and:nnTF { \bool_if_p:N \g_@@_starred_bool } { \bool_not_p:n { \l_@@_standard_bool } } { \msg_error:nn { enumext } { wrong-miniright-starred } } { % exec \int_compare:nNnTF { \l_@@_keyans_level_int } = { 1 } { \@@_keyans_mini_right_cmd:n {#1} } { \@@_mini_right_cmd:n {#1} } } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_mini_right_cmd:n} % The function \myhlc|\@@_mini_right_cmd:n| takes as argument the \emph{starred} `|*|' % of the |\miniright| command in the \myenv*[no-index]{enumext} environment. % It checks if the \mykey[env]{mini-env} key is active via the variable % \myhlc|\l_@@_minipage_right_X_dim|; if so, it closes the % \myenv[no-index]{multicols} environment with the \myhlc|\@@_mini_page| % environment on the \emph{\enquote{left side}}, then opens the % \myhlc|\@@_mini_page| environment on the \emph{\enquote{right % side}}, applies the adjusted \emph{\enquote{vertical space}} above it, followed by % adding the |\centering| command when the \emph{starred argument} `|*|' is not % present, and sets \myhlc|\g_@@_minipage_stat_int| to zero; otherwise it returns an error. % Before closing the environment on the \emph{\enquote{left side}} the space % \emph{\enquote{below}} is stored with \myhlc|\@@_mini_capture_end:| (or % with \myhlc|\@@_mini_capture_multicols:| when \myenv[no-index]{multicols} is % active), to be applied after the environment on the \emph{\enquote{right side}}. % \begin{macrocode} \cs_new_protected:Nn \@@_mini_right_cmd:n { \dim_compare:nNnTF { \dim_use:c { l_@@_minipage_right_ \@@_level: _dim } } > { \c_zero_dim } { \@@_multicols_stop: \int_compare:nNnT { \int_use:c { l_@@_columns_ \@@_level: _int } } = { 1 } { \par \@@_mini_capture_end: } \end@@_mini_page \hfill \@@_mini_page{ \dim_use:c { l_@@_minipage_right_ \@@_level: _dim } } \par\nointerlineskip \addvspace { \l_@@_minipage_right_skip } \bool_if:nF {#1} { \centering } \int_gzero:N \g_@@_minipage_stat_int } { \msg_error:nn { enumext } { wrong-miniright-use } } % paranoia \RenewDocumentCommand \miniright { s } { \msg_error:nn { enumext } { many-miniright-used } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_keyans_mini_right_cmd:n} % The function \myhlc|\@@_keyans_mini_right_cmd:n| takes as argument the \emph{starred} `|*|' % of the |\miniright| command in the \myenv*[no-index]{keyans} % environment. The implementation of this function is the same as that of % the \myhlc|\@@_mini_right_cmd:n| function of the \myenv*[no-index]{enumext} % environment. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_mini_right_cmd:n { \dim_compare:nNnTF { \l_@@_minipage_right_v_dim } > { \c_zero_dim } { \@@_keyans_multicols_stop: \int_compare:nNnT { \l_@@_columns_v_int } = { 1 } { \par \@@_mini_capture_end: } \end@@_mini_page \hfill \@@_mini_page{ \l_@@_minipage_right_v_dim } \par\nointerlineskip \addvspace { \l_@@_minipage_right_skip } \bool_if:nF {#1} { \centering } \int_gzero:N \g_@@_minipage_stat_int } { \msg_error:nn { enumext } { wrong-miniright-use } } % paranoia \RenewDocumentCommand \miniright { s } { \msg_error:nn { enumext } { many-miniright-used } } } % \end{macrocode} % \end{macro} % % \subsection{Setting \texttt{above} and \texttt{below} keys}\label{subsec:set-above-below} % % While having controlled the \emph{vertical spaces} within % the \myenv*[no-index]{enumext} and \myenv*[no-index]{keyans} environments when using the % \mykey{columns} or \mykey{mini-env} keys, sometimes the % \emph{\enquote{vertical spaces above}} or \emph{\enquote{vertical spaces below}} the environments are % not as expected and it is necessary to be able to apply a % \emph{\enquote{fine correction}} to these. Since these \emph{glitches} cannot be % corrected completely, the best option is to provide a couple of % \mymeta{keys} dedicated to this purpose, in this case it is best to use % |\vspace| or |\vspace*| when convenient. % % \begin{variable}[int]{ % \l_@@_vspace_a_star_X_bool, % \l_@@_vspace_b_star_X_bool, % } % The boolean vars \myhlc|\l_@@_vspace_a_star_X_bool| and % \myhlc|\l_@@_vspace_b_star_X_bool| are used by \mykey{above}, % \mykey{above*}, \mykey{below} and \mykey{below*} keys. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:n { \bool_new:c { l_@@_vspace_a_star_ #1 _bool } \bool_new:c { l_@@_vspace_b_star_ #1 _bool } } \clist_map_inline:nn { i, ii, iii, iv, v, vii, viii } { \@@_tmp:n {#1} } % \end{macrocode} % \end{variable} % % \begin{macro}[int]{above, above*, below, below*} % Define \mykey[env]{above}, \mykey[env]{above*}, \mykey[env]{below} and \mykey[env]{below*} keys for % \myenv*[no-index]{enumext} and \myenv*[no-index]{keyans} environments. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:nn { \keys_define:nn { enumext / #1 } { above .skip_set:c = { l_@@_vspace_above_ #2 _skip }, above .value_required:n = true, above* .code:n = { \bool_set_true:c { l_@@_vspace_a_star_ #2 _bool } \keys_set:nn { enumext / #1 } { above = {##1} } }, above* .value_required:n = true, below .skip_set:c = { l_@@_vspace_below_ #2 _skip }, below .value_required:n = true, below* .code:n = { \bool_set_true:c { l_@@_vspace_b_star_ #2 _bool } \keys_set:nn { enumext / #1 } { below = {##1} } }, below* .value_required:n = true, } } \clist_map_inline:Nn \c_@@_all_envs_clist { \@@_tmp:nn #1 } % \end{macrocode} % \end{macro} % % \subsubsection{Functions for \texttt{above} and \texttt{below} keys in \env{enumext}} % % \begin{macro}[int]{\@@_vspace_above:} % The function \myhlc|\@@_vspace_above:| applies the \emph{vertical space above} % the \myenv*[no-index]{enumext} environment set by the \mykey[env]{above*} and \mykey[env]{above} keys. % \begin{macrocode} \cs_new_protected:Nn \@@_vspace_above: { \skip_if_eq:nnF { \skip_use:c { l_@@_vspace_above_ \@@_level: _skip } } { \c_zero_skip } { \bool_if:cTF { l_@@_vspace_a_star_ \@@_level: _bool } { \vspace*{ \skip_use:c { l_@@_vspace_above_ \@@_level: _skip } } } { \vspace { \skip_use:c { l_@@_vspace_above_ \@@_level: _skip } } } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_vspace_below:} % The function \myhlc|\@@_vspace_below:| applies the \emph{vertical space below} % the \myenv*[no-index]{enumext} environment set by the \mykey[env]{below*} and \mykey[env]{below} keys. % \begin{macrocode} \cs_new_protected:Nn \@@_vspace_below: { \skip_if_eq:nnF { \skip_use:c { l_@@_vspace_below_ \@@_level: _skip } } { \c_zero_skip } { \bool_if:cTF { l_@@_vspace_b_star_ \@@_level: _bool } { \vspace*{ \skip_use:c { l_@@_vspace_below_ \@@_level: _skip } } } { \vspace { \skip_use:c { l_@@_vspace_below_ \@@_level: _skip } } } } } % \end{macrocode} % \end{macro} % % \subsubsection{Functions for \texttt{above} and \texttt{below} keys in \env{keyans}} % % \begin{macro}[int]{\@@_vspace_above_v:} % The function \myhlc|\@@_vspace_above_v:| applies the \emph{vertical space above} % the \myenv*[no-index]{keyans} environment set by the \mykey[env]{above} and \mykey[env]{above*} keys. % \begin{macrocode} \cs_new_protected:Nn \@@_vspace_above_v: { \skip_if_eq:nnF { \l_@@_vspace_above_v_skip } { \c_zero_skip } { \bool_if:NTF \l_@@_vspace_a_star_v_bool { \vspace*{ \l_@@_vspace_above_v_skip } } { \vspace { \l_@@_vspace_above_v_skip } } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_vspace_below_v:} % The function \myhlc|\@@_vspace_below_v:| applies the \emph{vertical space below} % the \myenv*[no-index]{keyans} environment set by the \mykey[env]{below*} and \mykey[env]{below} keys. % \begin{macrocode} \cs_new_protected:Nn \@@_vspace_below_v: { \skip_if_eq:nnF { \l_@@_vspace_below_v_skip } { \c_zero_skip } { \bool_if:NTF \l_@@_vspace_b_star_v_bool { \vspace*{ \l_@@_vspace_below_v_skip } } { \vspace { \l_@@_vspace_below_v_skip } } } } % \end{macrocode} % \end{macro} % % \subsubsection{Functions for \texttt{above} and \texttt{below} keys in \env{enumext*} \env{keyans*}} % % \begin{macro}[int]{\@@_vspace_above_vii:, \@@_vspace_above_viii:} % The functions \myhlc|\@@_vspace_above_vii:| and \myhlc|\@@_vspace_above_viii:| apply the \emph{vertical space above} % the \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} environments set by the \mykey[env]{above} and \mykey[env]{above*} keys. % \begin{macrocode} \cs_new_protected:Nn \@@_vspace_above_vii: { \skip_if_eq:nnF { \l_@@_vspace_above_vii_skip } { \c_zero_skip } { \bool_if:NTF \l_@@_vspace_a_star_vii_bool { \vspace*{ \l_@@_vspace_above_vii_skip } } { \vspace { \l_@@_vspace_above_vii_skip } } } } \cs_new_protected:Nn \@@_vspace_above_viii: { \skip_if_eq:nnF { \l_@@_vspace_above_viii_skip } { \c_zero_skip } { \bool_if:NTF \l_@@_vspace_a_star_viii_bool { \vspace*{ \l_@@_vspace_above_viii_skip } } { \vspace { \l_@@_vspace_above_viii_skip } } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_vspace_below_vii:, \@@_vspace_below_viii:} % The functions \myhlc|\@@_vspace_below_vii:| and \myhlc|\@@_vspace_below_viii:| % apply the \emph{vertical space below} the \myenv*[no-index]{enumext*} and % \myenv*[no-index]{keyans*} environments set by the \mykey[env]{below*} and \mykey[env]{below} keys. % \begin{macrocode} \cs_new_protected:Nn \@@_vspace_below_vii: { \skip_if_eq:nnF { \l_@@_vspace_below_vii_skip } { \c_zero_skip } { \bool_if:NTF \l_@@_vspace_b_star_vii_bool { \vspace*{ \l_@@_vspace_below_vii_skip } } { \vspace { \l_@@_vspace_below_vii_skip } } } } \cs_new_protected:Nn \@@_vspace_below_viii: { \skip_if_eq:nnF { \l_@@_vspace_below_viii_skip } { \c_zero_skip } { \bool_if:NTF \l_@@_vspace_b_star_viii_bool { \vspace*{ \l_@@_vspace_below_viii_skip } } { \vspace { \l_@@_vspace_below_viii_skip } } } } % \end{macrocode} % \end{macro} % % \subsection{Setting \texttt{series}, \texttt{resume} and \texttt{resume*} keys}\label{key:series} % % The \mykey{series} key is responsible for the whole process of the % \mykey{resume} and \mykey{resume*} keys. The idea behind this is to be % able to absorb the \mymeta{keys} passed to the \emph{optional argument} % of the environments \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*}, but, discarding % some specific \mymeta{keys}. % % \subsubsection{Definition of variables} % % \begin{variable}[int]{ % \l_@@_series_name_tl, % \l_@@_resume_series_X_bool, % \l_@@_resume_star_key_X_bool, % \g_@@_resume_last_keys_X_tl, % } % Internal variables used by \mykey{resume}, \mykey{resume*} and % \mykey{series} keys (\S\ref{key:series}). % \begin{macrocode} \tl_new:N \l_@@_series_name_tl \cs_set_protected:Nn \@@_tmp:n { \bool_new:c { l_@@_resume_series_ #1 _bool } \bool_new:c { l_@@_resume_star_key_ #1 _bool } \tl_new:c { g_@@_resume_last_keys_ #1 _tl } } \clist_map_inline:nn { i, ii, iii, iv, vii } { \@@_tmp:n {#1} } % \end{macrocode} % \end{variable} % % \subsubsection{Definition of error messages} % % \begin{macro}[int]{unknown-series-starred, unknown-series-standard} % Messages used by \mykey[env]{resume} key. % \begin{macrocode} \msg_new:nnnn { enumext } { unknown-series-starred } { The~series~'#1'~for~the~resume~key~does~not~exist~in~the~ enumext*~environment~\msg_line_context:. } { Define~the~series~with~the~key~'series'~in~a~previous~ 'enumext*'~environment~and~check~the~name. } \msg_new:nnnn { enumext } { unknown-series-standard } { The~series~'#1'~for~the~resume~key~does~not~exist~at~level~ \int_use:N \l_@@_level_int \c_space_tl of~enumext~environment~\msg_line_context:. } { Define~the~series~with~the~key~'series'~at~that~level~in~ a~previous~'enumext'~environment~and~check~the~name. } % \end{macrocode} % \end{macro} % % \subsubsection{Definition of keys for \texttt{series}, \texttt{resume} and \texttt{resume*}} % % \begin{macro}[int]{series, resume, resume*} % Defines the keys \mykey[env]{series}, \mykey[env]{resume} % and \mykey[env]{resume*} for the \emph{\enquote{all levels}} % of \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*}. % Both keys do nothing while |\printkeyans| is running, otherwise the % \emph{start value} of the environments would be increased when using % \mykey{resume} or \mykey{resume}|*| keys. % % In version 1.6 it is allowed to pass the key \mykey{resume} \emph{without % value} by means of the command |\setenumext|, for the correct operation % of this, the boolean variable \myhlc|\l_@@_resume_count_bool| % set by the key \mykey{resume} \emph{without value} must be set to |true| to % be later processed by the function \myhlc|\@@_parse_series:n| in the definition % of the environments \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*}. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:nn { \keys_define:nn { enumext / #1 } { series .str_set:N = \l_@@_series_name_str, series .value_required:n = true, resume .code:n = { \bool_if:NF \l_@@_print_keyans_cmd_bool { \tl_set:Nn \l_@@_series_name_tl {##1} \tl_if_empty:NTF \l_@@_series_name_tl { \bool_set_true:c { l_@@_resume_count_ #2 _bool } \bool_set_eq:Nc \l_@@_resume_count_bool { l_@@_resume_count_ #2 _bool } } { \@@_resume:n {##1} } } }, resume* .code:n = { \bool_if:NF \l_@@_print_keyans_cmd_bool { \bool_set_true:c { l_@@_resume_count_ #2 _bool } \bool_set_eq:Nc \l_@@_resume_count_bool { l_@@_resume_count_ #2 _bool } \bool_set_true:c { l_@@_resume_star_key_ #2 _bool } \@@_resume_star: } }, resume* .value_forbidden:n = true, } } \clist_map_inline:nn { {level-1}{i}, {level-2}{ii}, {level-3}{iii}, {level-4}{iv},{enumext*}{vii}, } { \@@_tmp:nn #1 } % \end{macrocode} % \end{macro} % % \subsubsection{Internal function to save counter and integer values} % % \begin{macro}[int]{\@@_standard_save_counter:, \@@_standard_save_counter_aux:, % \@@_starred_save_counter:, \@@_starred_save_counter_aux:} % The \myhlc|\@@_standard_save_counter:| and \myhlc|\@@_starred_save_counter:| % functions will save the last counter value to \myhlc|\g_@@_series_#1_X_int| % with the name given to the key \mykey[env]{series}|=|\mymarg{series name} % if it has been passed, to \myhlc|\c@ @@_resume_X_int| if none of the keys % \mykey[env]{series}, \mykey[env]{resume}|=|\mymarg{series name} and % \mykey[env]{save-ans} has been passed (the case of the key % \mykey[env]{resume} \emph{without value}), to % \myhlc|\g_@@_series_#1_X_int| with the name given to the key % \mykey{resume}|=|\mymarg{series name} if it has been passed and, in the % \emph{\enquote{first level}}, to \myhlc|\g_@@_resume_#1_int| with the % \mymarg{store name} if the key \mykey[env]{save-ans}|=|\mymarg{store name} % has been passed. % % \begin{important}* % The variables \myhlc|\l_@@_series_name_str| and \myhlc|\l_@@_series_name_tl| % contain the same \mymarg{series name} but are executed at different % moments, the integer variable with \myhlc|\l_@@_series_name_str| sets the value % when executing \mykey{series}|=|\mymarg{series name} and the % integer variable with \myhlc|\l_@@_series_name_tl| sets the subsequent % values when using \mykey{resume}|=|\mymarg{series name}. % This function is passed to the \myenv*[no-index]{enumext} environment definition (\S\ref{env:enumext}) % and the \myenv*[no-index]{enumext*} environment definition (\S\ref{env:starred}). % \end{important} % \begin{macrocode} \cs_new_protected:Nn \@@_standard_save_counter: { \bool_if:NTF \g_@@_standard_bool { \@@_standard_save_counter_aux: \int_compare:nNnT { \l_@@_level_int } = { 1 } { \int_if_exist:cT { g_@@_resume_ \l_@@_store_name_tl _int } { \int_gset_eq:cN { g_@@_resume_ \l_@@_store_name_tl _int } \value{enumXi} } } } { \@@_standard_save_counter_aux: } } \cs_new_protected:Nn \@@_standard_save_counter_aux: { \str_if_empty:NF \l_@@_series_name_str { \int_gset_eq:cc { g_@@_series_ \l_@@_series_name_str _ \@@_level: _int } { c@enumX \@@_level: } } \tl_if_empty:NTF \l_@@_series_name_tl { \str_if_empty:NT \l_@@_series_name_str { \tl_if_empty:NT \l_@@_store_name_tl { \int_gset_eq:cc { c@ @@_resume_ \@@_level: _int } { c@enumX \@@_level: } } } } { \int_if_exist:cT { g_@@_series_ \l_@@_series_name_tl _ \@@_level: _int } { \int_gset_eq:cc { g_@@_series_ \l_@@_series_name_tl _ \@@_level: _int } { c@enumX \@@_level: } } } } \cs_new_protected:Nn \@@_starred_save_counter: { \bool_if:NTF \g_@@_starred_bool { \@@_starred_save_counter_aux: \int_if_exist:cT { g_@@_resume_ \l_@@_store_name_tl _int } { \int_gset_eq:cN { g_@@_resume_ \l_@@_store_name_tl _int } \value{enumXvii} } } { \@@_starred_save_counter_aux: } } \cs_new_protected:Nn \@@_starred_save_counter_aux: { \str_if_empty:NF \l_@@_series_name_str { \int_gset_eq:cN { g_@@_series_ \l_@@_series_name_str _vii_int } \value{enumXvii} } \tl_if_empty:NTF \l_@@_series_name_tl { \str_if_empty:NT \l_@@_series_name_str { \tl_if_empty:NT \l_@@_store_name_tl { \int_gset_eq:cc { c@ @@_resume_vii_int } { c@enumXvii } } } } { \int_if_exist:cT { g_@@_series_ \l_@@_series_name_tl _vii_int } { \int_gset_eq:cN { g_@@_series_ \l_@@_series_name_tl _vii_int } \value{enumXvii} } } } % \end{macrocode} % \end{macro} % % \subsubsection{Internal function for resume counters} % % \begin{macro}[int]{\@@_resume_counter:} % The \myhlc|\@@_resume_counter:| function is executed by the \mykey[env]{resume*} % key and \mykey[env]{resume} key \emph{without value}, only the % \emph{\enquote{counters}} for the \emph{\enquote{levels}} of the % environments in which it is executed will be set. If the % \mykey[env]{save-ans} key is active it will set the \emph{\enquote{counter}} % according to the value of the integer variable created by that key. % \begin{macrocode} \cs_new_protected:Nn \@@_resume_counter: { \cs_set:Nn \@@_tmp:n { \bool_if:cT { l_@@_resume_count_ \int_to_roman:n {##1} _bool } { \exp_args:Ne \int_set:cn { l_@@_start_ \int_to_roman:n {##1} _int } { \int_use:c { c@ @@_resume_ \int_to_roman:n {##1} _int } + 1 } } } \int_compare:nNnT { \l_@@_level_int } > { 0 } { \bool_lazy_and:nnTF { \bool_if_p:N \l_@@_standard_first_bool } { \bool_if_p:N \l_@@_store_active_bool } { \int_set:Nn \l_@@_start_i_int { \int_use:c { g_@@_resume_ \l_@@_store_name_tl _int } + 1 } } { \int_step_function:nN { \l_@@_level_int } \@@_tmp:n } } \int_compare:nNnT { \l_@@_level_h_int } = { 1 } { \bool_lazy_and:nnTF { \bool_if_p:N \l_@@_starred_first_bool } { \bool_if_p:N \l_@@_store_active_bool } { \int_set:Nn \l_@@_start_vii_int { \int_use:c { g_@@_resume_ \l_@@_store_name_tl _int } + 1 } } { \bool_if:NT \l_@@_resume_count_vii_bool { \int_set:Nn \l_@@_start_vii_int { \int_use:c { c@ @@_resume_vii_int } + 1 } } } } } % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions for \texttt{series} key} % % \begin{macro}[int]{\@@_filter_series:n, \@@_filter_series_key:n, \@@_filter_series_pair:nn} % The function \myhlc|\@@_filter_series:n| will be in charge of filtering the % \mymeta{keys} to be stored, where `|#1|' represents the \emph{optional argument} % passed to the environment. This implementation is adapted directly from % the code provided by Jonathan P. Spratte (\texttt{@Skillmon}) in \href{https://chat.stackexchange.com/transcript/41?m=65647962#65647962}{chat-TeX-SX} % \begin{macrocode} \cs_new:Nn \@@_filter_series:n { \use:e { \keyval_parse:NNn \@@_filter_series_key:n \@@_filter_series_pair:nn {#1} } } % \end{macrocode} % The function \myhlc|\@@_filter_series_key:n| will be responsible for % filtering the \mymeta{keys} that are passed \emph{\enquote{without value}} by % excluding the \mykey[env]{resume}, \mykey[env]{resume*}, \mykey[env]{reset}, \mykey[env]{reset*} % and \mykey[env]{base-fix} keys. % \begin{macrocode} \cs_new:Nn \@@_filter_series_key:n { \str_case:nnF {#1} { { resume } { } { resume* } { } { reset } { } { reset* } { } { base-fix } { } } { , { \exp_not:n {#1} } } } % \end{macrocode} % The function \myhlc|\@@_filter_series_pair:nn| will be responsible for % filtering the \mymeta{keys} that are passed \emph{\enquote{with value}} by % excluding the \mykey[env]{series}, \mykey{resume}, \mykey[env,foreachkeyans]{start}, \mykey[env]{start*}, \mykey[env]{save-ans} and % \mykey[env]{save-key} keys. % \begin{macrocode} \cs_new:Nn \@@_filter_series_pair:nn { \str_case:nnF {#1} { { series } { } { resume } { } { start } { } { start* } { } { save-ans } { } { save-key } { } } { , { \exp_not:n {#1} } = { \exp_not:n {#2} } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_save_last_keys:n, \@@_resume_last_counter:} % The function \myhlc|\@@_save_last_keys:n| will be in charge of saving the % filtering \mymeta{keys} when the keys \mykey[env]{series}|=|\mymarg{series name} % or \mykey[env]{resume}|=|\mymarg{series name} or \mykey{resume}|*| are NOT % active and will save them in the variable \myhlc|\g_@@_resume_last_keys_X_tl| for the % \myenv*[no-index]{enumext} environment and in the variable \myhlc|\g_@@_resume_last_keys_vii_tl| % for the \myenv*[no-index]{enumext*} environment. % % \begin{important}* % The boolean variable \myhlc|\l_@@_resume_series_X_bool| % is set to |true| by the key \mykey{resume}|=|\mymarg{series name}, % the boolean variable \myhlc|\l_@@_resume_star_key_X_bool| % is set to |true| by the key \mykey{resume}|*|, in this case % both variables must be set to |false| so that % they don't override the default filtered \mymeta{keys}. % \end{important} % \begin{macrocode} \cs_new_protected:Nn \@@_save_last_keys:n { \int_compare:nNnT { \l_@@_level_int } > { 0 } { \bool_if:cF { l_@@_resume_series_ \@@_level: _bool } { \bool_if:cF { l_@@_resume_star_key_ \@@_level: _bool } { \tl_gclear:c { g_@@_resume_last_keys_ \@@_level: _tl } \tl_gset:ce { g_@@_resume_last_keys_ \@@_level: _tl } { \@@_filter_series:n {#1} } } } } \int_compare:nNnT { \l_@@_level_h_int } = { 1 } { \bool_if:NF \l_@@_resume_series_vii_bool { \tl_gclear:N \g_@@_resume_last_keys_vii_tl \tl_gset:Ne \g_@@_resume_last_keys_vii_tl { \@@_filter_series:n {#1} } } } } % \end{macrocode} % The \myhlc|\@@_resume_last_counter:| function will be in charge of setting % the \emph{\enquote{counters}} when the keys \mykey{series}|=|\mymarg{series name} % or \mykey{resume}|=|\mymarg{series name} are NOT active and the % \mykey{resume} key is being used \emph{without value} either in the % \emph{optional argument} of the environments or through the % |\setenumext| command. % % \begin{important}* % The boolean variable \myhlc|\l_@@_resume_count_bool| % is set to |true| by the keys \mykey{resume} \emph{without value} % and \mykey{resume}|*|; and set to |false| by the keys % \mykey[env,foreachkeyans]{start} and \mykey[env]{start*} (\S\ref{key:start-widest}). % \end{important} % \begin{macrocode} \cs_new_protected:Nn \@@_resume_last_counter: { \bool_lazy_and:nnT { \bool_if_p:N \l_@@_resume_count_bool } { \tl_if_empty_p:N \l_@@_series_name_tl } { \@@_resume_counter: } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_parse_series:n} % The \myhlc|\@@_parse_series:n| function handled by the \mykey[env]{series} key % will be responsible for \emph{storing} the \emph{filtered} % \mymeta{keys} from the \emph{optional arguments} of the % \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} environments for the % \mykey[env]{resume} and \mykey{resume}|*| keys. % If the \mykey{series} key is NOT active it will call the % \myhlc|\@@_save_last_keys:n| function to \emph{store} the \emph{filtered} % \mymeta{keys} that will be used by the \mykey[env]{resume*} key and then the % \myhlc|\@@_resume_last_counter:| function used by the \mykey{resume} key % \emph{without value} if it is active, otherwise \emph{store} the % \emph{filtered} \mymeta{keys} in the global variable \myhlc|\g_@@_series_#1_X_tl| % along with the creation of the integer variable \myhlc|\g_@@_series_#1_X_int| % used by the \mykey{resume} key \emph{with value}. % % \begin{important}* % This function is passed to the function \myhlc|\@@_parse_keys:n| % in the \myenv*[no-index]{enumext} environment definition (\S\ref{env:enumext}) % and to the function \myhlc|\@@_parse_keys_vii:n| in the \myenv*[no-index]{enumext*} % environment definition (\S\ref{env:starred}). % \end{important} % \begin{macrocode} \cs_new_protected:Nn \@@_parse_series:n { \str_if_empty:NTF \l_@@_series_name_str { \int_compare:nNnT { \l_@@_level_int } > { 0 } { \@@_save_last_keys:n {#1} \@@_resume_last_counter: } \int_compare:nNnT { \l_@@_level_h_int } = { 1 } { \@@_save_last_keys:n {#1} \@@_resume_last_counter: } } { \int_compare:nNnT { \l_@@_level_int } > { 0 } { \tl_gclear_new:c { g_@@_series_ \l_@@_series_name_str _ \@@_level: _tl } \tl_gset:ce { g_@@_series_ \l_@@_series_name_str _ \@@_level: _tl } { \@@_filter_series:n {#1} } \int_if_exist:cF { g_@@_series_ \l_@@_series_name_str _ \@@_level: _int } { \int_new:c { g_@@_series_ \l_@@_series_name_str _ \@@_level: _int } } } \int_compare:nNnT { \l_@@_level_h_int } = { 1 } { \tl_gclear_new:c { g_@@_series_ \l_@@_series_name_str _vii_tl } \tl_gset:ce { g_@@_series_ \l_@@_series_name_str _vii_tl } { \@@_filter_series:n {#1} } \int_if_exist:cF { g_@@_series_ \l_@@_series_name_str _vii_int } { \int_new:c { g_@@_series_ \l_@@_series_name_str _vii_int } } } } } % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions for \texttt{resume} key with value} % % \begin{macro}[int]{\@@_resume:n} % The function \myhlc|\@@_resume:n| will handle the \emph{argument} \mymarg{series name} % passed to the \mykey[env]{resume} key in \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} environments. % First it checks if the global variable \myhlc|\g_@@_series_#1_X_tl| % exists; if so, it calls the function \myhlc|\@@_resume_series:n| and passes the \mymeta{keys} % stored in \myhlc|\g_@@_series_#1_X_tl| to the environments, % otherwise it returns an error. % \begin{macrocode} \cs_new_protected:Nn \@@_resume:n { \int_compare:nNnT { \l_@@_level_int } > { 0 } { \tl_if_exist:cTF { g_@@_series_ \tl_to_str:n {#1} _ \@@_level: _tl } { \@@_resume_series:n {#1} \exp_args:Ne \keys_set:nv { enumext / level-\int_use:N \l_@@_level_int } { g_@@_series_ \tl_to_str:n {#1} _ \@@_level: _tl } } { \msg_error:nnn { enumext } { unknown-series-standard } {#1} } } \int_compare:nNnT { \l_@@_level_h_int } = { 1 } { \tl_if_exist:cTF { g_@@_series_ \tl_to_str:n {#1} _vii_tl } { \@@_resume_series:n {#1} \keys_set:nv { enumext / enumext* } { g_@@_series_ \tl_to_str:n {#1} _vii_tl } } { \msg_error:nnn { enumext } { unknown-series-starred } {#1} } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_resume_series:n, \@@_resume_integer_series:} % The function \myhlc|\@@_resume_series:n| will set the variable % \myhlc|\l_@@_resume_series_X_bool| to |true| and pass the \mymarg{argument} % to the variable \myhlc|\l_@@_series_name_tl| then call the function % \myhlc|\@@_resume_integer_series:|. % \begin{macrocode} \cs_new_protected:Nn \@@_resume_series:n { \int_compare:nNnT { \l_@@_level_int } > { 0 } { \bool_set_true:c { l_@@_resume_series_ \@@_level: _bool } \tl_clear:N \l_@@_series_name_tl \tl_set:Nn \l_@@_series_name_tl {#1} \@@_resume_integer_series: } \int_compare:nNnT { \l_@@_level_h_int } = { 1 } { \bool_set_true:N \l_@@_resume_series_vii_bool \tl_clear:N \l_@@_series_name_tl \tl_set:Nn \l_@@_series_name_tl {#1} \@@_resume_integer_series: } } % \end{macrocode} % The function \myhlc|\@@_resume_integer_series:| will be executed when the % \mykey[env]{resume}|=|\mymarg{series name} key is active, setting the \emph{start value} % for the \emph{\enquote{counter}} of the \emph{\enquote{current level}} of the environments % in which it is run according to the value of the \emph{\enquote{integer variables}} created by the % \mykey[env]{series} key. If the \mykey[env]{save-ans} key is active it will % set the \emph{start value} for the \emph{\enquote{counter}} according % to the value of the integer variable created by that key. % \begin{macrocode} \cs_new_protected:Nn \@@_resume_integer_series: { \cs_set:Nn \@@_tmp:n { \int_if_exist:cT { g_@@_series_ \l_@@_series_name_tl _ \int_to_roman:n {##1} _int } { \exp_args:Ne \int_set:cn { l_@@_start_ \int_to_roman:n {##1} _int } { \int_use:c { g_@@_series_ \l_@@_series_name_tl _ \int_to_roman:n {##1} _int } + 1 } } } \int_compare:nNnT { \l_@@_level_int } > { 0 } { \bool_lazy_and:nnTF { \bool_if_p:N \l_@@_standard_first_bool } { \bool_if_p:N \l_@@_store_active_bool } { \int_set:Nn \l_@@_start_i_int { \int_use:c { g_@@_resume_ \l_@@_store_name_tl _int } + 1 } } { \int_step_function:nN { \l_@@_level_int } \@@_tmp:n } } \int_compare:nNnT { \l_@@_level_h_int } = { 1 } { \bool_lazy_and:nnTF { \bool_if_p:N \l_@@_starred_first_bool } { \bool_if_p:N \l_@@_store_active_bool } { \int_set:Nn \l_@@_start_vii_int { \int_use:c { g_@@_resume_ \l_@@_store_name_tl _int } + 1 } } { \int_set:Nn \l_@@_start_vii_int { \int_use:c { g_@@_series_ \l_@@_series_name_tl _vii_int } + 1 } } } } % \end{macrocode} % \end{macro} % % \subsubsection{Internal function for \texttt{resume*} key} % % \begin{macro}[int]{\@@_resume_star:} % The function \myhlc|\@@_resume_star:| will handle the \mykey[env]{resume*} % key in the \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} environments. This % function will execute the filtered \mymeta{keys} in the last one and % will continue with the numbering and \mymeta{keys} according to the % last execution of the environment \myenv*[no-index]{enumext} or \myenv*[no-index]{enumext*} % in which the keys \mykey[env]{resume}|=|\mymarg{series name} or \mykey[env]{series}|=|\mymarg{series name} % were NOT active. % \begin{macrocode} \cs_new_protected:Nn \@@_resume_star: { \cs_set:Nn \@@_tmp:n { \tl_if_empty:cTF { g_@@_resume_last_keys_ \int_to_roman:n {##1} _tl } { \@@_resume_counter: } { \@@_resume_counter: \exp_args:Ne \keys_set:nv { enumext / level-\int_use:N \l_@@_level_int } { g_@@_resume_last_keys_ \int_to_roman:n {##1} _tl } } } \int_compare:nNnT { \l_@@_level_int } > { 0 } { \int_step_function:nN { \l_@@_level_int } \@@_tmp:n } \int_compare:nNnT { \l_@@_level_h_int } = { 1 } { \tl_if_empty:NTF \g_@@_resume_last_keys_vii_tl { \@@_resume_counter: } { \@@_resume_counter: \keys_set:nV { enumext / enumext* } \g_@@_resume_last_keys_vii_tl } } } % \end{macrocode} % \end{macro} % % \subsection{The \cs{resetenumext} command}\label{cmd:resetenumext} % % Sometimes it is necessary to be able to reset the \emph{\enquote{counters}} % of the environments according to some value, for example |\chapter|. Since % \emph{\enquote{internal counters}} are used for the \mykey{resume} and \mykey{resume*} % keys which set the \emph{start value}, but are not accessible by the user, % it is necessary to provide a public command for this. This implementation is an % adaptation of the answers given by Clea F. Rees (\texttt{@cfr}) and % Jonathan P. Spratte (\texttt{@Skillmon}) in \href{https://tex.stackexchange.com/q/746644}{Correct % implementation of optional argument (comma-separated) in expl3}. % % \begin{macro}[int]{out-of-range} % Message used by |\resetenumext| command. % \begin{macrocode} \msg_new:nnnn { enumext } { out-of-range } { The~number~must~be~exactly~1,~2,~3~or~4. } { Received:~'#1'. } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_standard_reset:nn, \@@_starred_reset:n, % \@@_reset_count_resume:nn, \@@_reset_count_resume:en, % \@@_reset_count_resume_all:n, \@@_reset_count_resume_levels:n} % Internal functions used by the \ics*{resetenumext} command. % \begin{macrocode} \cs_new_protected:Npn \@@_standard_reset:nn #1 %#2 { \@@_reset_count_resume:en { \int_to_roman:n {#1} } %{#2} } \cs_new_protected:Nn \@@_starred_reset:n { \@@_reset_count_resume:nn { vii } {#1} } \cs_new_protected:Nn \@@_reset_count_resume:nn { \counterwithin*{enumX #1}{#2} \counterwithin*{@@_resume_ #1 _int}{#2} } \cs_generate_variant:Nn \@@_reset_count_resume:nn { e } \cs_new_protected:Nn \@@_reset_count_resume_all:n { \clist_map_inline:nn { i,ii,iii,iv,vii } { \@@_reset_count_resume:nn {##1} {#1} } } \cs_new_protected:Nn \@@_reset_count_resume_levels:n { \clist_map_inline:nn { i,ii,iii,iv } { \@@_reset_count_resume:nn {##1} {#1} } } % \end{macrocode} % \end{macro} % % \begin{macro}{\resetenumext} % The \ics*{resetenumext} command \emph{\enquote{resets}} the \emph{start value} % of the \emph{\enquote{counters}} for the \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} % environments along with the \emph{\enquote{internal counters}} used by % the keys \mykey[env]{resume} \emph{without value} and \mykey[env]{resume*} % according to the value of \mymarg{some counter}. It accepts a \emph{starred argument} % `|*|' in `|#1|', an optional argument in `|#2|' with the level from 1 to 4 or the % character `|*|', and the mandatory \mymarg{some counter} in `|#3|'. % \begin{macrocode} \NewDocumentCommand \resetenumext { s o m } { \bool_if:nTF {#1} { \@@_reset_count_resume_all:n {#3} } { \tl_if_novalue:nTF {#2} { \@@_reset_count_resume_levels:n {#3} } { \str_if_eq:nnTF {#2} { * } { \@@_starred_reset:n {#3} } { \bool_lazy_and:nnTF { \int_compare_p:nNn {#2} > { 0 } } { \int_compare_p:nNn {#2} < { 5 } } { \@@_standard_reset:nn {#2} {#3} } { \msg_error:nne { enumext } { out-of-range } { \int_eval:n {#2} } } } } } } % \end{macrocode} % \end{macro} % % \subsection{The \texttt{reset} and \texttt{reset*} keys}\label{key:reset} % % The |\resetenumext| command does not work, for example, after an % unnumbered chapter, so it is preferable to provide a pair of \mymeta{keys} that % adjust the internal variables if necessary. % % \begin{macro}[int]{reset, reset*} % Defines the keys \mykey[env]{reset} and \mykey[env]{reset*} for the \emph{\enquote{all levels}} % of \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*}. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:n { \keys_define:nn { enumext / #1 } { reset .code:n = { \@@_standard_reset_key: }, reset .value_forbidden:n = true, reset* .code:n = { \@@_standard_reset_key_star: }, reset* .value_forbidden:n = true, } } \clist_map_inline:nn {level-1, level-2, level-3, level-4} { \@@_tmp:n {#1} } \keys_define:nn { enumext / enumext* } { reset .code:n = { \@@_starred_reset_key: }, reset .value_forbidden:n = true, reset* .code:n = { \@@_starred_reset_key: }, reset* .value_forbidden:n = true, } % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions for \texttt{reset} and \texttt{reset*} keys} % % \begin{macro}[int]{\@@_standard_reset_key:, \@@_standard_reset_key_star:, \@@_starred_reset_key:} % The function \myhlc|\@@_standard_reset_key:| will be handled by the % \mykey[env]{reset} key and will \emph{\enquote{reset}} the counter \myhlc|\c@ @@_resume_X_int| % to \emph{\enquote{zero}} according to the \emph{level} at % which it is executed within the \myenv*[no-index]{enumext} environment. % \begin{macrocode} \cs_new_protected:Nn \@@_standard_reset_key: { \int_compare:nNnT { \l_@@_level_int } > { 0 } { \int_if_exist:cT { c@ @@_resume_ \int_to_roman:n { \l_@@_level_int } _int } { \int_gzero:c { c@ @@_resume_ \int_to_roman:n { \l_@@_level_int } _int } } } } % \end{macrocode} % The function \myhlc|\@@_standard_reset_key_star:| will be handled by the % \mykey[env]{reset*} key and will \emph{\enquote{reset}} the counters \myhlc|\c@ @@_resume_X_int| % to \emph{\enquote{zero}} from the \emph{level} at which it % is executed within the \myenv*[no-index]{enumext} environment to the \emph{lower levels}. % \begin{macrocode} \cs_new_protected:Nn \@@_standard_reset_key_star: { \cs_set:Nn \@@_tmp:n { \int_if_exist:cT { c@ @@_resume_ \int_to_roman:n {##1} _int } { \int_gzero:c { c@ @@_resume_ \int_to_roman:n {##1} _int } } } \int_compare:nNnT { \l_@@_level_int } > { 0 } { \int_step_function:nnN { \l_@@_level_int } { 4 } \@@_tmp:n } } % \end{macrocode} % The function \myhlc|\@@_starred_reset_key:| will be handled by % \mykey{reset} keys and \mykey{reset*} will \emph{\enquote{reset}} the % counter \myhlc|\c@ @@_resume_vii_int| to \emph{\enquote{zero}} when % executed in the \myenv*[no-index]{enumext*} environment. % \begin{macrocode} \cs_new_protected:Nn \@@_starred_reset_key: { \int_gzero:c { c@ @@_resume_vii_int } } % \end{macrocode} % \end{macro} % % \subsection{Setting \texttt{save-ans}, \texttt{check-ans} and \texttt{no-store} keys}\label{subsec:set-save-check-nostore} % % The key \mykey{save-ans} is directly associated with the keys % \mykey{check-ans}, \mykey{no-store}, \mykey{resume} and % \mykey{resume*}, this will activate the entire \emph{\enquote{storage % system}} in the \mypkg*[no-index]{enumext} package. % % \subsubsection{Definition of error messages} % % \begin{macro}[int]{save-ans-empty} % Message used by \mykey[env]{save-ans} key. % \begin{macrocode} \msg_new:nnnn { enumext } { save-ans-empty } { Key~'save-ans'~needs~a~value~in~'#1'~\msg_line_context:. } { Give~a~name~to~the~storage,~for~example~'save-ans=name'. } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{missing-starred, many-starred} % Messages used by the internal system to check for % \emph{\enquote{starred}} |\item*| and |\anspic*| commands. % \begin{macrocode} \msg_new:nnn { enumext } { missing-starred } { Missing~'\c_backslash_str #1*'~#2. } \msg_new:nnn { enumext } { many-starred } { Many~'\c_backslash_str #1*'~#2. } % \end{macrocode} % \end{macro} % % \subsubsection{Definition of messages for the storage system} % % These messages are not error messages, they report to the |.log| file what the % \emph{\enquote{storage system}} is doing. % % \begin{macro}[int]{save-ans-log, save-ans-log-hook} % Messages written to the |.log| file when the \mykey[env]{save-ans} key starts and stops. % \begin{macrocode} \msg_new:nnn { enumext } { save-ans-log } { Start~'#1'~with~'save-ans=#2'~\msg_line_context:. } \msg_new:nnn { enumext } { save-ans-log-hook } { Stop~'#1'~with~'save-ans=#2'~\msg_line_context:. } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{store-prop, store-seq, store-int} % Messages written to the |.log| file when the \emph{prop list}, \emph{sequence} and % integer variables used by the \mykey[env]{save-ans} key are created. % \begin{macrocode} \msg_new:nnn { enumext } { store-prop } { Creating~\c_backslash_str g_@@_ #1 _prop~\msg_line_context:. } \msg_new:nnn { enumext } { store-seq } { Creating~\c_backslash_str g_@@_ #1 _seq~\msg_line_context:. } \msg_new:nnn { enumext } { store-int } { Creating~\c_backslash_str g_@@_resume_ #1 _int~\msg_line_context:. } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{items-same-answer, item-greater-answer, item-less-answer} % Messages used by the internal system to check answer used by % \mykey[env]{check-ans} key. % \begin{macrocode} \msg_new:nnn { enumext } { items-same-answer } { Answers~in~'#1'~(#2):~OK,~items~=~answers.\\ Started~#3~and~closed~\msg_line_context:. } \msg_new:nnn { enumext } { item-greater-answer } { Answers~in~'#1'~(#2):~NOT~OK,~items~>~answers.\\ Started~#3~and~closed~\msg_line_context:. } \msg_new:nnn { enumext } { item-less-answer } { Answers~in~'#1'~(#2):~NOT~OK,~items~<~answers.\\ Started~#3~and~closed~\msg_line_context:. } % \end{macrocode} % \end{macro} % % \subsubsection{Setting \texttt{save-ans} key}\label{key:save-ans} % % \begin{macro}[int]{save-ans} % Defines the key \mykey[env]{save-ans} only for the \emph{\enquote{first level}} % of \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*}. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:n { \keys_define:nn { enumext / #1 } { save-ans .code:n = { \@@_storing_set:n {##1} }, save-ans .value_required:n = true, } } \clist_map_inline:nn { level-1, enumext* } { \@@_tmp:n {#1} } % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions for \texttt{save-ans} key} % % \begin{macro}[int]{\@@_start_save_ans_msg:, \@@_stop_save_ans_msg:} % The functions \myhlc|\@@_start_save_ans_msg:| and \myhlc|\@@_stop_save_ans_msg:| % will write in the |.log| file the environment in which % the \mykey[env]{save-ans} key was executed along with the line at the % beginning and end of it. The function \myhlc|\@@_start_save_ans_msg:| will % be passed to \myhlc|\@@_storing_set:n| and the function % \myhlc|\@@_stop_save_ans_msg:| will be passed to the function % \myhlc|\@@_execute_after_env:|. % \begin{macrocode} \cs_new_protected:Nn \@@_start_save_ans_msg: { \msg_info:nnVV { enumext } { save-ans-log } \g_@@_envir_name_tl \l_@@_store_name_tl } \cs_new_protected:Nn \@@_stop_save_ans_msg: { \msg_info:nnVV { enumext } { save-ans-log-hook } \g_@@_envir_name_tl \g_@@_store_name_tl } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_storing_set:n, \@@_storing_exec:} % The function \myhlc|\@@_storing_set:n| first passes the value of the % \mykey[env]{save-ans} key to the variable \myhlc|\l_@@_store_name_tl| % which contains the \mymarg{store name} of the \emph{sequence} % and \emph{prop list} to be used. If \myhlc|\l_@@_store_name_tl| is % \emph{empty} it returns an error message, otherwise it returns the % appropriate message \myhlc|\@@_start_save_ans_msg:| and proceeds to execute % the function \myhlc|\@@_storing_exec:| for \myenv*[no-index]{enumext} and % \myenv*[no-index]{enumext*} environments. % \begin{macrocode} \cs_new_protected:Nn \@@_storing_set:n { \tl_set:Ne \l_@@_store_name_tl {#1} \tl_if_empty:NTF \l_@@_store_name_tl { \bool_lazy_or:nnT { \l_@@_standard_first_bool } { \l_@@_starred_first_bool } { \msg_error:nnV { enumext } { save-ans-empty } \g_@@_envir_name_tl } } { \bool_lazy_or:nnT { \l_@@_standard_first_bool } { \l_@@_starred_first_bool } { \@@_start_save_ans_msg: \@@_storing_exec: } } } % \end{macrocode} % The function \myhlc|\@@_storing_exec:| will set to true the variable % \myhlc|\l_@@_store_active_bool| which activates the use of the % |\anskey| command and the \myenv*[no-index]{anskey*}, \myenv*[no-index]{keyans}, % \myenv*[no-index]{keyans*} and \myenv*[no-index]{keyanspic} environments and will set % to |true| the variable \myhlc|\l_@@_check_answers_bool| used for % internal checking answers mechanism set by the \mykey[env]{check-ans} and \mykey[env]{no-store} % keys, and copies the \mymarg{store name} into the variable \myhlc|\g_@@_store_name_tl|. % \begin{macrocode} \cs_new_protected:Nn \@@_storing_exec: { \bool_set_true:N \l_@@_store_active_bool \bool_set_true:N \l_@@_check_answers_bool \tl_gset:NV \g_@@_store_name_tl \l_@@_store_name_tl % \end{macrocode} % The \emph{prop list} \myhlc|\g_@@_series_#1_prop| and the \emph{sequence} \myhlc|\g_@@_series_#1_seq| % will be created globally to \emph{\enquote{store content}} in case % they do not exist together with the integer variable % \myhlc|\g_@@_series_#1_int| used by the keys % \mykey[env]{resume} and \mykey[env]{resume*}. % \begin{macrocode} \prop_if_exist:cF { g_@@_ \l_@@_store_name_tl _prop } { \msg_info:nnV { enumext } { store-prop } \l_@@_store_name_tl \prop_new:c { g_@@_ \l_@@_store_name_tl _prop } } \seq_if_exist:cF { g_@@_ \l_@@_store_name_tl _seq } { \msg_info:nnV { enumext } { store-seq } \l_@@_store_name_tl \seq_new:c { g_@@_ \l_@@_store_name_tl _seq } } \int_if_exist:cF { g_@@_resume_ \l_@@_store_name_tl _int } { \msg_info:nnV { enumext } { store-int } \l_@@_store_name_tl \int_new:c { g_@@_resume_ \l_@@_store_name_tl _int } } } % \end{macrocode} % \end{macro} % % \subsubsection{The check answer mechanism}\label{subsubsec:check-answer} % % The internal mechanism for \emph{\enquote{checking answers}} follows this % logic: % % \begin{quote} % If the line begins with |\item| or |\item*| and does NOT % \emph{open a nested environment}, each |\item| or |\item*| must contain a % \emph{single} execution of the |\anskey| command, i.e. the counter of the % executions of the |\anskey| command must be equal to the counter % associated with the sum of executions of |\item| and |\item*|. % % If the line begins with |\item| or |\item*| and \emph{opens a nested % environment} each |\item| or |\item*| in the nested environment must % have a \emph{single} execution of the |\anskey| command and the counter % associated to the sum of |\item| and |\item*| executions must be decremented % by \emph{\enquote{one}} to maintain equality. % % \end{quote} % % In order for the mechanism for the check-answer to work (not counting % \myenv*[no-index]{keyans}, \myenv*[no-index]{keyans*} and \myenv*[no-index]{keyanspic}) it is necessary to: % % \begin{enumerate}[left=0pt,noitemsep, partopsep=0pt, topsep=5pt] % \item Keep track of the total number of |\item| and |\item*| (enumerated) that appear within % the environment including the nested levels. % \item Keep track of the total number of |\item| and |\item*| (enumerated) that appear per % level of nesting. % \item Keep track of the number of times the environment nests. % \end{enumerate} % % % The integer variable associated to the sum of each |\item| and |\item*| % in the environment \myhlc|\g_@@_item_number_int| must match the % integer variable \myhlc|\g_@@_item_anskey_int| associated % to the execution of the command |\anskey|. The cases are analyzed below: % % \begin{enumerate}[label=\alph*),left=0pt,noitemsep, partopsep=0pt, topsep=5pt] % \item If the list only has one level the number of |\item + \item*| = |\anskey| % % \item If the list has \emph{nested levels}, for each level of nesting the count % is decremented by one (for the |\item| or |\item*| that opens the nest) so that the account % remains the same. % \end{enumerate} % % With \myenv*[no-index]{keyans}, \myenv*[no-index]{keyans*} and \myenv*[no-index]{keyanspic} it is % enough to increase in one the integer of |\anskey|. The integers % created must be global if they are not lost in the interior levels of % nesting and to execute the test a \emph{\enquote{hook}} % function is used after closing the \emph{first level} of the environment. % % \subsubsection{Setting \texttt{check-ans} and \texttt{no-store} keys}\label{key:check-ans} % % \begin{macro}[int]{check-ans, no-store} % Defines the keys \mykey[env]{check-ans} and \mykey[env]{no-store} for all % levels of \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} environments. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:n { \keys_define:nn { enumext / #1 } { check-ans .bool_set:N = \l_@@_check_ans_key_bool, check-ans .initial:n = false, check-ans .value_required:n = true, no-store .code:n = { \bool_set_false:N \l_@@_check_answers_bool \bool_set_false:N \l_@@_check_ans_key_bool }, no-store .value_forbidden:n = true, } } \clist_map_inline:nn { level-1, level-2, level-3, level-4, enumext* } { \@@_tmp:n {#1} } % \end{macrocode} % \end{macro} % % \subsubsection{Set-up check answer mechanism}\label{subsubsec:set-check-answer} % % \begin{macro}[int]{\@@_check_ans_active:, \@@_check_ans_level:} % The function \myhlc|\@@_check_ans_active:| will first check the state of % the variable \myhlc|\l_@@_store_name_tl|, that is, the \mykey[env]{save-ans} key % is active, if so it will check the state of the variable % \myhlc|\l_@@_check_answers_bool| handled by the key \mykey[env]{no-store} and % will execute the function \myhlc|\@@_check_ans_level:| only if % |true|, i.e. the key \mykey{no-store} is not active. % \begin{macrocode} \cs_new_protected:Nn \@@_check_ans_active: { \tl_if_empty:NF \l_@@_store_name_tl { \bool_if:NT \l_@@_check_answers_bool { \@@_check_ans_level: } } } % \end{macrocode} % The function \myhlc|\@@_check_ans_level:| will decrement by \emph{\enquote{one}} % the value of the variable \myhlc|\g_@@_item_number_int| which keeps track % of the executions of |\item| and |\item*| for each level of nesting % of the environment \myenv*[no-index]{enumext}, taking into account whether it % is nested within \myenv*[no-index]{enumext*} or the opposite and set \myhlc|\l_@@_item_number_bool| % to |false|. % \begin{macrocode} \cs_new_protected:Nn \@@_check_ans_level: { \int_case:nn { \l_@@_level_int } { { 1 } { \bool_lazy_all:nT { { \bool_if_p:N \g_@@_starred_bool } { \int_compare_p:nNn { \l_@@_level_h_int } = { 1 } } } { \int_gdecr:N \g_@@_item_number_int \bool_set_false:N \l_@@_item_number_bool } } { 2 } { \int_gdecr:N \g_@@_item_number_int \bool_set_false:N \l_@@_item_number_bool } { 3 } { \int_gdecr:N \g_@@_item_number_int \bool_set_false:N \l_@@_item_number_bool } { 4 } { \int_gdecr:N \g_@@_item_number_int \bool_set_false:N \l_@@_item_number_bool } } % \end{macrocode} % This is executed only if \myenv*[no-index]{enumext*} is nested in the % \emph{\enquote{first level}} of \myenv*[no-index]{enumext}, for the rest of the % cases the value of \myhlc|\g_@@_item_number_int| is already decreased. % \begin{macrocode} \int_case:nn { \l_@@_level_h_int } { { 1 } { \bool_lazy_all:nT { { \bool_if_p:N \g_@@_standard_bool } { \int_compare_p:nNn { \l_@@_level_int } = { 1 } } } { \int_gdecr:N \g_@@_item_number_int \bool_set_false:N \l_@@_item_number_bool } } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_check_ans_key_hook:} % The function \myhlc|\@@_check_ans_key_hook:| will \emph{export} the status % of the local variable \myhlc|\l_@@_check_ans_key_bool| to the global variable % \myhlc|\g_@@_check_ans_key_bool| only if the key \mykey[env]{check-ans} is active. % \begin{macrocode} \cs_new_protected:Nn \@@_check_ans_key_hook: { \bool_lazy_and:nnT { \bool_if_p:N \l_@@_check_ans_key_bool } { \bool_if_p:N \g_@@_standard_bool } { \bool_gset_true:N \g_@@_check_ans_key_bool } \bool_lazy_and:nnT { \bool_if_p:N \l_@@_check_ans_key_bool } { \bool_if_p:N \g_@@_starred_bool } { \bool_gset_true:N \g_@@_check_ans_key_bool } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_item_answer_diff:} % The function \myhlc|\@@_item_answer_diff:| will set the value of the % variable \myhlc|\g_@@_item_answer_diff_int| which is used by the functions % \myhlc|\@@_check_ans_show:| for the key \mykey[env]{save-ans} and by the % function \myhlc|\@@_check_ans_log:| by the internal \emph{\enquote{check answer}} % mechanism. This function will be passed to the function % \myhlc|\@@_execute_after_env:|. % \begin{macrocode} \cs_new_protected:Nn \@@_item_answer_diff: { \int_gset:Nn \g_@@_item_answer_diff_int { \int_sign:n { \g_@@_item_number_int - \g_@@_item_anskey_int } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_check_ans_show:, \@@_check_ans_msg_less:, % \@@_check_ans_msg_same_ok:, \@@_check_ans_msg_greater:} % The function \myhlc|\@@_check_ans_show:| will be executed within the % function \myhlc|\@@_execute_after_env:| when the key \mykey[env]{check-ans} is % active, that is, when \myhlc|\g_@@_check_ans_key_bool| is |true| % and will return the appropriate message according to the value of % \myhlc|\g_@@_item_answer_diff_int| set by the function \myhlc|\@@_item_answer_diff:|. % \begin{macrocode} \cs_new_protected:Nn \@@_check_ans_show: { \int_case:nn { \g_@@_item_answer_diff_int } { { -1 }{ \@@_check_ans_msg_less: } { 0 }{ \@@_check_ans_msg_same_ok: } { 1 }{ \@@_check_ans_msg_greater: } } } \cs_new_protected:Nn \@@_check_ans_msg_less: { \msg_warning:nneee { enumext } { item-less-answer } { \g_@@_store_name_tl } { \g_@@_envir_name_tl } { \g_@@_start_line_tl } } \cs_new_protected:Nn \@@_check_ans_msg_same_ok: { \msg_info:nneee { enumext } { items-same-answer } { \g_@@_store_name_tl } { \g_@@_envir_name_tl } { \g_@@_start_line_tl } } \cs_new_protected:Nn \@@_check_ans_msg_greater: { \msg_warning:nneee { enumext } { item-greater-answer } { \g_@@_store_name_tl } { \g_@@_envir_name_tl } { \g_@@_start_line_tl } } % \end{macrocode} % \end{macro} % \begin{macro}[int]{\@@_check_ans_log:, \@@_check_ans_log_msg_less:, % \@@_check_ans_log_msg_same_ok:, \@@_check_ans_log_msg_greater:} % The function \myhlc|\@@_check_ans_log:| will be executed within the % function \myhlc|\@@_execute_after_env:| when the key \mykey[env]{check-ans} is % not active, that is, when \myhlc|\g_@@_check_ans_key_bool| is |false| % and write in the log the appropriate message according to the value of % \myhlc|\g_@@_item_answer_diff_int| set by the function % \myhlc|\@@_item_answer_diff:|. % \begin{macrocode} \cs_new_protected:Nn \@@_check_ans_log: { \int_case:nn { \g_@@_item_answer_diff_int } { { -1 }{ \@@_check_ans_log_msg_less: } { 0 }{ \@@_check_ans_log_msg_same_ok: } { 1 }{ \@@_check_ans_log_msg_greater: } } } \cs_new_protected:Nn \@@_check_ans_log_msg_less: { \msg_info:nneee { enumext } { item-less-answer } { \g_@@_store_name_tl } { \g_@@_envir_name_tl } { \g_@@_start_line_tl } } \cs_new_protected:Nn \@@_check_ans_log_msg_same_ok: { \msg_info:nneee { enumext } { items-same-answer } { \g_@@_store_name_tl } { \g_@@_envir_name_tl } { \g_@@_start_line_tl } } \cs_new_protected:Nn \@@_check_ans_log_msg_greater: { \msg_info:nneee { enumext } { item-greater-answer } { \g_@@_store_name_tl } { \g_@@_envir_name_tl } { \g_@@_start_line_tl } } % \end{macrocode} % \end{macro} % % \subsubsection{Check for \cs{item*} and \cs{anspic*} commands} % % \begin{macro}[int]{\@@_check_starred_cmd:n} % The function \myhlc|\@@_check_starred_cmd:n| performs an \emph{extra check} % for the \myenv*[no-index]{keyans}, \myenv*[no-index]{keyans*} and \myenv*[no-index]{keyanspic} environments. % Unlike the \emph{check} executed by \mykey[env]{check-ans} key this one % is not controlled by any key, it is intended to prevent the forgetting % of |\item*| or |\anspic*| in these environments. % \begin{macrocode} \cs_new_protected:Nn \@@_check_starred_cmd:n { \int_compare:nNnT { \g_@@_check_starred_cmd_int } = { 0 } { \msg_warning:nnnV { enumext } { missing-starred }{#1} \l_@@_check_start_line_env_tl } \int_compare:nNnT { \g_@@_check_starred_cmd_int } > { 1 } { \msg_warning:nnnV { enumext } { many-starred }{#1} \l_@@_check_start_line_env_tl } \int_gzero:N \g_@@_check_starred_cmd_int \tl_clear:N \l_@@_check_start_line_env_tl } % \end{macrocode} % \end{macro} % % \subsection{Keys and functions associated with storage}\label{subsec:storage-system} % % \subsubsection{Definition of variables} % % \begin{variable}[int]{ % \l_@@_store_save_key_X_tl, % \l_@@_store_save_key_X_bool, % } % Internal variables used by \mykey{save-key} key (\S\ref{key:save-key}) and % the \emph{\enquote{storing structure}}. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:n { \tl_new:c { l_@@_store_save_key_ #1 _tl } \bool_new:c { l_@@_store_save_key_ #1 _bool } } \clist_map_inline:nn { i, ii, iii, iv, vii } { \@@_tmp:n {#1} } % \end{macrocode} % \end{variable} % % \subsubsection{Keys for \texttt{marks}, \texttt{wrap} and \texttt{show}} % % The \mypkg*[no-index]{enumext} package provides a set of \mymeta{keys} for % manipulating \emph{\enquote{symbol marks}} associated with \emph{\enquote{answers}} % and how they are displayed and stored in the \emph{sequence} and \emph{prop list} % as well as an internal \emph{\enquote{label and ref}} system. % % \begin{macro}[int]{mark-ans*, mark-pos*, mark-sep*, wrap-ans*, wrap-opt, % save-sep, show-ans, show-pos} % For the \myenv*[no-index]{keyans} and \myenv*[no-index]{keyans*} environments only the keys % \mykey[env]{mark-ans*}, \mykey[env]{mark-pos*}, \mykey[env]{mark-sep*}, % \mykey[env]{wrap-ans*}, \mykey[env]{wrap-opt}, \mykey[env]{save-sep}, \mykey[env]{show-ans} % and \mykey[env]{show-pos} are added. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:nn { \keys_define:nn { enumext / #1 } { mark-ans* .tl_set:c = { l_@@_mark_answer_sym_ #2 _tl }, mark-ans* .initial:n = \textasteriskcentered, mark-ans* .value_required:n = true, mark-pos* .choices:nn = { left , right , center } { \int_case:nn { \l_keys_choice_int } { {1} { \str_set:cn { l_@@_mark_position_ #2 _str } { l } } {2} { \str_set:cn { l_@@_mark_position_ #2 _str } { r } } {3} { \str_set:cn { l_@@_mark_position_ #2 _str } { c } } } }, mark-pos* .initial:n = right, mark-pos* .value_required:n = true, mark-pos* / unknown .code:n = \msg_error:nneee { enumext } { unknown-choice } { mark-pos* } { left,~right,~center } { \exp_not:n {##1} }, mark-sep* .dim_set:c = { l_@@_mark_sym_sep_ #2 _dim }, mark-sep* .value_required:n = true, wrap-ans* .cs_set_protected:cp = { @@_keyans_wrapper_item_ #2 :n } ##1, wrap-ans* .value_required:n = true, wrap-opt .cs_set_protected:cp = { @@_keyans_wrapper_opt_ #2 :n } ##1, wrap-opt .initial:n = [{##1}], wrap-opt .value_required:n = true, save-sep .tl_set:c = { l_@@_store_keyans_item_opt_sep_ #2 _tl }, save-sep .initial:n = {,~}, save-sep .value_required:n = true, show-ans .bool_set:N = \l_@@_show_answer_bool, show-ans .initial:n = false, show-ans .value_required:n = true, show-pos .bool_set:N = \l_@@_show_position_bool, show-pos .initial:n = false, show-pos .value_required:n = true, } } \clist_map_inline:nn { {keyans}{v}, {keyans*}{viii} } { \@@_tmp:nn #1 } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{mark-ref, save-ref, show-ans, show-pos, mark-ans, % mark-pos, mark-sep, wrap-ans, mark-ans*, mark-pos*, % mark-sep*, wrap-ans*, wrap-opt, save-sep} % Adds the \mymeta{keys} \mykey[env]{mark-ref} and \mykey[env]{save-ref} related to the % \emph{\enquote{storage system}} and internal mechanism of % \emph{\enquote{label and ref}} along with the \mymeta{keys} \mykey[env]{show-ans}, % \mykey[env]{show-pos} and the \mymeta{keys} \mykey[env]{mark-ans}, \mykey[env]{mark-pos}, % \mykey[env]{mark-sep} and \mykey[env]{wrap-ans} for the command |\anskey|, % the environment \myenv*[no-index]{anskey*} and the \mymeta{keys} for environments % \myenv*[no-index]{keyans} and \myenv*[no-index]{keyans*} only at the \emph{first level} % of \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*}. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:n { \keys_define:nn { enumext / #1 } { mark-ref .tl_set:N = \l_@@_mark_ref_sym_tl, mark-ref .initial:n = \textreferencemark, mark-ref .value_required:n = true, save-ref .bool_set:N = \l_@@_store_ref_key_bool, save-ref .initial:n = false, save-ref .value_required:n = true, show-ans .bool_set:N = \l_@@_show_answer_bool, show-ans .initial:n = false, show-ans .value_required:n = true, show-pos .bool_set:N = \l_@@_show_position_bool, show-pos .initial:n = false, show-pos .value_required:n = true, mark-ans .tl_set:N = \l_@@_mark_answer_sym_tl, mark-ans .initial:n = \textasteriskcentered, mark-ans .value_required:n = true, mark-sep .dim_set:N = \l_@@_mark_sym_sep_dim, mark-sep .value_required:n = true, mark-pos .choices:nn = { left , right , center } { \int_case:nn { \l_keys_choice_int } { {1} { \str_set:Nn \l_@@_mark_position_str { l } } {2} { \str_set:Nn \l_@@_mark_position_str { r } } {3} { \str_set:Nn \l_@@_mark_position_str { c } } } }, mark-pos .initial:n = right, mark-pos .value_required:n = true, mark-pos / unknown .code:n = \msg_error:nneee { enumext } { unknown-choice } { mark-pos } { left,~right,~center } { \exp_not:n {##1} }, wrap-ans .cs_set_protected:Np = \@@_anskey_wrapper:n ##1, wrap-ans .initial:n = { \fbox{\parbox[t]{\dimeval{\itemwidth -2\fboxsep -2\fboxrule}}{##1}} }, wrap-ans .value_required:n = true, mark-ans* .code:n = { \keys_set:nn { enumext / keyans } { mark-ans* = {##1} } \keys_set:nn { enumext / keyans* } { mark-ans* = {##1} } }, mark-ans* .value_required:n = true, mark-pos* .code:n = { \keys_set:nn { enumext / keyans } { mark-pos* = {##1} } \keys_set:nn { enumext / keyans* } { mark-pos* = {##1} } }, mark-pos* .value_required:n = true, mark-sep* .code:n = { \keys_set:nn { enumext / keyans } { mark-sep* = {##1} } \keys_set:nn { enumext / keyans* } { mark-sep* = {##1} } }, mark-sep* .value_required:n = true, wrap-ans* .code:n = { \keys_set:nn { enumext / keyans } { wrap-ans* = {##1} } \keys_set:nn { enumext / keyans* } { wrap-ans* = {##1} } }, wrap-ans* .value_required:n = true, wrap-opt .code:n = { \keys_set:nn { enumext / keyans } { wrap-opt = {##1} } \keys_set:nn { enumext / keyans* } { wrap-opt = {##1} } }, wrap-opt .value_required:n = true, save-sep .code:n = { \keys_set:nn { enumext / keyans } { save-sep = {##1} } \keys_set:nn { enumext / keyans* } { save-sep = {##1} } }, save-sep .value_required:n = true, } } \clist_map_inline:nn { level-1, enumext* } { \@@_tmp:n {#1} } % \end{macrocode} % \end{macro} % % \subsubsection{Storing structure of the environments} % % The idea behind \emph{\enquote{storing structure}} in the \emph{sequence} is % to have a copy of the \emph{structure of the environment} in which the key % \mykey{save-ans} is being executed, so the \emph{optional % argument} passed to the levels of the environment in which it is % executed must be captured and \emph{\enquote{stored}} in the \emph{sequence}. % % \begin{macro}[int]{\@@_store_active_keys:n, \@@_store_active_keys_vii:n} % The functions \myhlc|\@@_store_active_keys:n| and \myhlc|\@@_store_active_keys_vii:n| % will be responsible for the \emph{\enquote{storing keys}} filtered % from the \emph{optional argument} of the environment in which the % key \mykey[env]{save-ans} is executed and the levels within this for the \myenv*[no-index]{enumext} and % \myenv*[no-index]{enumext*} environments. This function is executed only if % the variable \myhlc|\l_@@_store_save_key_X_bool| is false, that is, the key % \mykey[env]{save-key} is not active, establishing the variable % \myhlc|\l_@@_store_save_key_X_tl| with the filtered \mymeta{keys}. % \begin{macrocode} \cs_new_protected:Nn \@@_store_active_keys:n { \bool_if:cF { l_@@_store_save_key_ \@@_level: _bool } { \tl_clear:c { l_@@_store_save_key_ \@@_level: _tl } \tl_set:ce { l_@@_store_save_key_ \@@_level: _tl } { \@@_filter_save_key:n {#1} } } } \cs_new_protected:Nn \@@_store_active_keys_vii:n { \bool_if:NF \l_@@_store_save_key_vii_bool { \tl_clear:N \l_@@_store_save_key_vii_tl \tl_set:Ne \l_@@_store_save_key_vii_tl { \@@_filter_save_key:n {#1} } } } % \end{macrocode} % \end{macro} % % \subsubsection{Setting \texttt{save-key} key}\label{key:save-key} % % Since this \emph{\enquote{storing structure}} in the \emph{sequence} % established by the \mykey{save-ans} key when executing |\anskey| or \myenv*[no-index]{anskey*}, % it cannot be modified. The best option here is to have a key % that allows modifying the \emph{optional argument} of the \emph{\enquote{storing structure}} in % the \emph{sequence}. % % \begin{macro}[int]{save-key} % The values set by this key passed in the \emph{optional argument} of the % \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} environments will override the % values of the \myhlc|\l_@@_store_save_key_X_tl| variable set by the % functions \myhlc|\@@_store_active_keys:n| and \myhlc|\@@_store_active_keys_vii:n|. % Now define the key \mykey[env]{save-key} for all levels of % \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} environments. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:n { \keys_define:nn { enumext / enumext* } { save-key .code:n = { \@@_parse_save_key_vii:n {##1} }, save-key .value_required:n = true, } \keys_define:nn { enumext / #1 } { save-key .code:n = { \@@_parse_save_key:n {##1} }, save-key .value_required:n = true, } } \clist_map_inline:nn { level-1, level-2, level-3, level-4 } { \@@_tmp:n {#1} } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_parse_save_key:n, \@@_parse_save_key_vii:n} % The functions \myhlc|\@@_parse_save_key:n| and \myhlc|\@@_parse_save_key_vii:n| % will be responsible for \emph{\enquote{storing keys}} in the variable % \myhlc|\l_@@_store_save_key_X_tl| for \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*}. % \begin{macrocode} \cs_new_protected:Nn \@@_parse_save_key:n { \bool_set_true:c { l_@@_store_save_key_ \@@_level: _bool } \tl_set:ce { l_@@_store_save_key_ \@@_level: _tl } { \@@_filter_save_key:n {#1} } } \cs_new_protected:Nn \@@_parse_save_key_vii:n { \bool_set_true:N \l_@@_store_save_key_vii_bool \tl_clear:N \l_@@_store_save_key_vii_tl \tl_set:Ne \l_@@_store_save_key_vii_tl { \@@_filter_save_key:n {#1} } } % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions to store optional arguments} % % \begin{macro}[int]{\@@_filter_save_key:n, \@@_filter_save_key_key:n, % \@@_filter_save_key_pair:nn} % The function \myhlc|\@@_filter_save_key:n| will be in charge of % \emph{\enquote{filtering keys}} to be \emph{stored} in % \emph{sequence} where |{#1}| represents the \emph{optional argument} % passed to the environment. % \begin{macrocode} \cs_new:Nn \@@_filter_save_key:n { \use:e { \keyval_parse:NNn \@@_filter_save_key_key:n \@@_filter_save_key_pair:nn {#1} } } % \end{macrocode} % The function \myhlc|\@@_filter_save_key_key:n| will be responsible for % \emph{\enquote{filtering keys}} that are passed \emph{\enquote{without value}} % by excluding the \mykey[env]{resume}, \mykey[env]{resume*}, \mykey[env]{reset}, \mykey[env]{reset*}, % \mykey[env]{no-store} and \mykey[env]{base-fix} keys. % \begin{macrocode} \cs_new:Nn \@@_filter_save_key_key:n { \str_case:nnF {#1} { { resume } { } { resume* } { } { reset } { } { reset* } { } { no-store } { } { base-fix } { } } { , { \exp_not:n {#1} } } } % \end{macrocode} % The function \myhlc|\@@_filter_save_key_pair:nn| will be responsible for % \emph{\enquote{filtering keys}} that are passed \emph{\enquote{with value}} by % excluding the \mykey[env]{series}, \mykey{resume}, \mykey[env]{save-ans}, \mykey[env]{save-ref}, % \mykey[env]{save-key}, \mykey[env]{check-ans}, \mykey[env]{show-ans}, \mykey[env]{show-pos}, % \mykey[env]{mark-ans}, \mykey[env]{mark-pos}, \mykey[env]{mark-sep}, \mykey[env]{wrap-ans}, % \mykey[env]{mark-ans*}, \mykey[env]{mark-pos*}, \mykey[env]{mark-sep*}, \mykey[env]{wrap-ans*}, % \mykey[env]{wrap-opt}, \mykey[env]{save-sep}, \mykey[env]{mark-ref}, \mykey[env]{mini-env}, % \mykey[env]{mini-sep}, \mykey[env]{mini-right} and \mykey[env]{mini-right*} keys. % \begin{macrocode} \cs_new:Nn \@@_filter_save_key_pair:nn { \str_case:nnF {#1} { { series } { } { resume } { } { save-ans } { } { save-ref } { } { save-key } { } { check-ans } { } { show-ans } { } { show-pos } { } { mark-ans } { } { mark-pos } { } { mark-sep } { } { wrap-ans } { } { mark-ans* } { } { mark-pos* } { } { mark-sep* } { } { wrap-ans* } { } { wrap-opt } { } { save-sep } { } { mark-ref } { } { mini-env } { } { mini-sep } { } { mini-right } { } { mini-right* } { } } { , { \exp_not:n {#1} } = { \exp_not:n {#2} } } } % \end{macrocode} % \end{macro} % % \subsubsection{Function for storing content in prop list} % % \begin{macro}[int]{\@@_store_addto_prop:n, \@@_store_addto_prop:V} % The function \myhlc|\@@_store_addto_prop:n| stores the \mymarg{content} in % \emph{prop list} defined by \mykey[env]{save-ans} key. The \emph{\enquote{stored % content}} is retrieved by means of the |\getkeyans| command. % % The form in which the \mymarg{content} is \emph{\enquote{stored}} in the % \emph{prop list} is \mymarg{position}\mymarg{content}. This % function is used by |\anskey| in \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} % environments, |\item*| in \myenv*[no-index]{keyans} and \myenv*[no-index]{keyans*} % environments and |\anspic*| in \myenv*[no-index]{keyanspic} environment. % If there is no \emph{store name}, because it was used outside the % \mykey[env]{save-ans} key and the error has already been reported, it does % nothing. % \begin{macrocode} \cs_new_protected:Nn \@@_store_addto_prop:n { \tl_if_empty:NF \l_@@_store_name_tl { \prop_gput_if_not_in:cen { g_@@_ \l_@@_store_name_tl _prop } { \int_eval:n { \prop_count:c { g_@@_ \l_@@_store_name_tl _prop } + 1 } } {#1} } } \cs_generate_variant:Nn \@@_store_addto_prop:n { V } % \end{macrocode} % \end{macro} % % \subsubsection{Function for storing content in sequence} % % \begin{macro}[int]{\@@_store_addto_seq:n, \@@_store_addto_seq:v, \@@_store_addto_seq:V} % The function \myhlc|\@@_store_addto_seq:n| stores the \mymarg{content} in % \emph{sequence} defined by \mykey[env]{save-ans} key. This function % is used by |\anskey| and \myenv*[no-index]{anskey*} in \myenv*[no-index]{enumext} and % \myenv*[no-index]{enumext*}, |\item*| in \myenv*[no-index]{keyans} and % \myenv*[no-index]{keyans*} and |\anspic*| in \myenv*[no-index]{keyanspic}. % % The form in which the \mymarg{content} is stored in \emph{sequence} is in % an internal \myenv*[no-index]{enumext} or \myenv*[no-index]{enumext*} environments with % the \emph{\enquote{same structure}} in which the command was executed. % % The \emph{\enquote{stored content}} is retrieved by means of the % |\printkeyans| command. As in the previous function, it does nothing % when there is no \emph{store name}. % \begin{macrocode} \cs_new_protected:Nn \@@_store_addto_seq:n { \tl_if_empty:NF \l_@@_store_name_tl { \seq_gput_right:cn { g_@@_ \l_@@_store_name_tl _seq } {#1} } } \cs_generate_variant:Nn \@@_store_addto_seq:n { v, V } % \end{macrocode} % \end{macro} % % \subsubsection{Functions for storing structure in the sequence} % % \begin{macro}[int]{\@@_store_level_open:, \@@_store_level_close:} % The \emph{\enquote{storing structure}} is handled by the functions % \myhlc|\@@_store_level_open:| and \myhlc|\@@_store_level_close:| which are % executed per level within the \myenv*[no-index]{enumext} environment. % \begin{macrocode} \cs_new_protected:Nn \@@_store_level_open: { \bool_if:NT \l_@@_check_answers_bool { \tl_if_empty:cTF { l_@@_store_save_key_ \@@_level: _tl } { \@@_store_addto_seq:n { \item \begin{enumext} } } { \tl_put_left:cn { l_@@_store_save_key_ \@@_level: _tl } { \item \begin{enumext} [ } \tl_put_right:cn { l_@@_store_save_key_ \@@_level: _tl } { ] } \@@_store_addto_seq:v { l_@@_store_save_key_ \@@_level: _tl } } } } \cs_new_protected:Nn \@@_store_level_close: { \bool_if:NT \l_@@_check_answers_bool { \@@_store_addto_seq:n { \end{enumext} } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_store_level_open_vii:, \@@_store_level_close_vii:} % The \emph{\enquote{storing structure}} is handled by the functions % \myhlc|\@@_store_level_open_vii:| and \myhlc|\@@_store_level_close_vii:| % which are executed in the \myenv*[no-index]{enumext*} environment. % % \begin{macrocode} \cs_new_protected:Nn \@@_store_level_open_vii: { \bool_if:NT \l_@@_check_answers_bool { \tl_if_empty:NTF \l_@@_store_save_key_vii_tl { \@@_store_addto_seq:n { \item \begin{enumext*} } } { \tl_put_left:Nn \l_@@_store_save_key_vii_tl { \item \begin{enumext*}[ } \tl_put_right:Nn \l_@@_store_save_key_vii_tl { ] } \@@_store_addto_seq:V \l_@@_store_save_key_vii_tl } } } \cs_new_protected:Nn \@@_store_level_close_vii: { \bool_if:NT \l_@@_check_answers_bool { \@@_store_addto_seq:n { \end{enumext*} } } } % \end{macrocode} % \end{macro} % % \subsubsection{Function for show marks and position} % % \begin{macro}[int]{\@@_print_keyans_box:NN, \@@_print_keyans_box:cc} % The function \myhlc|\@@_print_keyans_box:NN| prints a box in the left % margin with \myhlc|\l_@@_mark_answer_sym_tl| used by the \mykey[env]{wrap-ans}, % \mykey[env]{show-ans} and \mykey[env]{show-pos} keys. The function takes two % arguments: % % \begin{arguments} % \item \myhlc|\l_@@_labelwidth_X_dim| % \item \myhlc|\l_@@_labelsep_X_dim| % \end{arguments} % % \begin{macrocode} \cs_new_protected:Nn \@@_print_keyans_box:NN { \mode_leave_vertical: \skip_horizontal:n { -\dim_use:N #2 } \hbox_overlap_left:n { \makebox[ \dim_use:N #1 ][ \l_@@_mark_position_str ] { \tl_use:N \l_@@_mark_answer_sym_tl } } \skip_horizontal:n { \dim_use:N #2 } } \cs_generate_variant:Nn \@@_print_keyans_box:NN { cc } % \end{macrocode} % \end{macro} % % \subsection{The internal label and ref}\label{subsec:internal-label-ref} % % The function \myhlc|\@@_store_internal_ref:| handles the % \emph{\enquote{internal label and ref}} system used by the \mykey{save-ref} % and \mykey{mark-ref} keys for |\anskey| allow executing % |\ref|\mymarg{store name \textnormal{\textcolor{red}{:}} position} and % will return |1||.(a)||.i||.A|. % % \begin{macro}[int]{\@@_store_internal_ref:} % First the dots \enquote{\textcolor{red}{.}} are removed from % the current \mymeta{labels}, since double dots in references are not % wanted, then the result is placed in the variable % \myhlc|\l_@@_newlabel_arg_two_tl|. % \begin{macrocode} \cs_new_protected:Nn \@@_store_internal_ref: { \cs_set_protected:Nn \@@_tmp:n { \tl_set_eq:cc { l_@@_label_copy_ ##1 _tl } { l_@@_label_ ##1 _tl } \tl_reverse:c { l_@@_label_copy_ ##1 _tl } \tl_remove_once:cn { l_@@_label_copy_ ##1 _tl } { . } \tl_reverse:c { l_@@_label_copy_ ##1 _tl } } \clist_map_inline:nn { i, ii, iii, iv, vii } { \@@_tmp:n {##1} } \cs_set:Nn \@@_tmp:n { . \tl_use:c { l_@@_label_copy_ \int_to_roman:n {##1} _tl } } % \end{macrocode} % Here it is necessary to analyze the cases where the environment is started with % \myenv*[no-index]{enumext*} and if |\anskey| or \myenv*[no-index]{anskey*} is running % alone in it or if it is running in a nested \myenv*[no-index]{enumext} environment % within the starting environment. % \begin{macrocode} \bool_lazy_all:nT { { \bool_if_p:N \g_@@_starred_bool } { \int_compare_p:nNn { \l_@@_level_int } = { 0 } } } { \tl_put_right:Ne \l_@@_newlabel_arg_two_tl { \tl_use:N \l_@@_label_copy_vii_tl } } \bool_lazy_all:nT { { \bool_not_p:n { \g_@@_standard_bool } } { \bool_if_p:N \l_@@_standard_bool } { \int_compare_p:nNn { \l_@@_level_int } > { 0 } } } { \tl_put_right:Ne \l_@@_newlabel_arg_two_tl { \tl_use:N \l_@@_label_copy_vii_tl \int_step_function:nnN { 1 } { \l_@@_level_int } \@@_tmp:n } } % \end{macrocode} % If started with \myenv*[no-index]{enumext} and if |\anskey| or \myenv*[no-index]{anskey*} % is running alone in it or if it is running in a nested \myenv*[no-index]{enumext*} % environment within the starting environment. % \begin{macrocode} \bool_lazy_all:nT { { \bool_if_p:N \g_@@_standard_bool } { \int_compare_p:nNn { \l_@@_level_int } > { 0 } } { \int_compare_p:nNn { \l_@@_level_h_int } = { 0 } } } { \tl_put_right:Ne \l_@@_newlabel_arg_two_tl { \tl_use:N \l_@@_label_copy_i_tl \int_step_function:nnN { 2 } { \l_@@_level_int } \@@_tmp:n } } \cs_set:Nn \@@_tmp:n { \tl_use:c { l_@@_label_copy_ \int_to_roman:n {##1} _tl } . } \bool_lazy_all:nT { { \bool_if_p:N \g_@@_standard_bool } { \bool_if_p:N \l_@@_starred_bool } { \int_compare_p:nNn { \l_@@_level_int } > { 0 } } } { \tl_put_right:Ne \l_@@_newlabel_arg_two_tl { \int_step_function:nnN { 1 } { \l_@@_level_int } \@@_tmp:n \tl_use:N \l_@@_label_copy_vii_tl } } % \end{macrocode} % Now the variable \myhlc|\l_@@_newlabel_arg_one_tl| is set, which % contains \mymarg{store name \textnormal{\textcolor{red}{:}} position}. % \begin{macrocode} \tl_put_right:Ne \l_@@_newlabel_arg_one_tl { \l_@@_store_name_tl \c_colon_str \int_eval:n { \prop_count:c { g_@@_ \l_@@_store_name_tl _prop } } } % \end{macrocode} % Now execute the function \myhlc|\@@_newlabel:nn| and save the result in % the variable \myhlc|\l_@@_write_aux_file_tl| and finally write it in the % |.aux| file. % \begin{macrocode} \tl_put_right:Ne \l_@@_write_aux_file_tl { \@@_newlabel:nn { \exp_not:V \l_@@_newlabel_arg_one_tl } { \l_@@_newlabel_arg_two_tl } } \l_@@_write_aux_file_tl } % \end{macrocode} % \end{macro} % % \subsection{Common functions for \cs{anskey} and \texttt{anskey*} environment}\label{subsec:common-anskey} % % \subsubsection{Definition of variables} % % \begin{variable}[int]{\l_@@_store_anskey_arg_tl} % The variable \myhlc|\l_@@_store_anskey_arg_tl| saves the \emph{argument} % of |\anskey| (\S\ref{cmd:anskey}). % \begin{macrocode} \tl_new:N \l_@@_store_anskey_arg_tl % \end{macrocode} % \end{variable} % % \subsubsection{Definition of error messages} % % \begin{macro}[int]{anskey-unnumber-item, anskey-empty-arg, anskey-math-mode} % Messages used by |\anskey| and \myenv*[no-index]{anskey*}. % \begin{macrocode} \msg_new:nnnn { enumext } { anskey-unnumber-item } { Can't~store~with~an~unnumbered~'\token_to_str:N \item'~\msg_line_context:. } { Store~the~content~with~a~numbered~'\token_to_str:N \item'. } \msg_new:nnnn { enumext } { anskey-empty-arg } { Can't~store~empty~content~\msg_line_context:. } { Give~some~content~to~'\token_to_str:N \anskey'~or~remove~the~command. } \msg_new:nnnn { enumext } { anskey-math-mode } { '#1'~can't~work~in~math~mode~\msg_line_context:. } { Leave~math~mode~before~using~'#1'. } % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions common to \cs[no-index]{anskey} and \env{anskey*}} % % \begin{macro}[int]{\@@_store_anskey_arg:n} % The internal function \myhlc|\@@_store_anskey_arg:n| first passes the % \mymarg{argument} to the \emph{prop list}, then checks the % state of the variable \myhlc|\l_@@_store_ref_key_bool| handled by the % \mykey[env]{save-ref} key and calls the function \myhlc|\@@_store_internal_ref:| % for the \emph{\enquote{internal label and ref}} system. After % this, if the \mykey[env]{show-ans} or \mykey[env]{show-pos} keys are active, it % shows the \emph{\enquote{wrapped}} \mymarg{argument}. % \begin{macrocode} \cs_new_protected:Nn \@@_store_anskey_arg:n { \int_gincr:N \g_@@_item_anskey_int \@@_store_addto_prop:n {#1} \bool_if:NT \l_@@_store_ref_key_bool { \@@_store_internal_ref: } \@@_anskey_show_wrap_left:n {#1} % \end{macrocode} % Now the processing of the \myoarg{key \textnormal{\textcolor{gray}{=}} val} % passed to the command starts, building the |\item| in the variable \myhlc|\l_@@_store_anskey_arg_tl| % which is \emph{\enquote{stored}} in the \emph{sequence}. % First the variable \myhlc|\l_@@_store_anskey_arg_tl| is cleared and the % \mymeta{keys} are processed; if the \mykey[anskey,anskey*]{break-col} key is present and % the command is running under \myenv*[no-index]{enumext} (not in \myenv*[no-index]{enumext*}), % |\columnbreak| and then |\item| are added. % \begin{macrocode} \tl_clear:N \l_@@_store_anskey_arg_tl \bool_lazy_and:nnT { \bool_if_p:N \l_@@_store_columns_break_bool } { \bool_not_p:n { \l_@@_starred_bool } } { \tl_put_left:Nn \l_@@_store_anskey_arg_tl { \columnbreak } } \tl_put_right:Nn \l_@@_store_anskey_arg_tl { \item } % \end{macrocode} % If the \mykey[anskey,anskey*]{item-join} key is present and the command is not running under % \myenv*[no-index]{enumext*}, \myparg{number} is added to \myhlc|\l_@@_store_anskey_arg_tl|. % \begin{macrocode} \bool_lazy_and:nnT { \bool_not_p:n { \l_@@_starred_bool } } { \int_compare_p:nNn { \l_@@_store_item_join_int } > { 1 } } { \tl_put_right:Ne \l_@@_store_anskey_arg_tl { ( \exp_not:V \l_@@_store_item_join_int ) } } % \end{macrocode} % Then the keys \mykey[anskey,anskey*]{item-star}, \mykey[anskey,anskey*]{item-sym*} and % \mykey[anskey,anskey*]{item-pos*} are reviewed and passed to \myhlc|\l_@@_store_anskey_arg_tl| % along with the \mymarg{argument} for |\anskey| or \mymeta{body} for \myenv*[no-index]{anskey*}. % \begin{macrocode} \bool_if:NTF \l_@@_store_item_star_bool { \tl_put_right:Nn \l_@@_store_anskey_arg_tl { * } \tl_if_empty:NF \l_@@_store_item_symbol_tl { \tl_put_right:Ne \l_@@_store_anskey_arg_tl { [ \exp_not:V \l_@@_store_item_symbol_tl ] } } \dim_compare:nT { \l_@@_store_item_symbol_sep_dim != \c_zero_dim } { \tl_put_right:Ne \l_@@_store_anskey_arg_tl { [ \exp_not:V \l_@@_store_item_symbol_sep_dim ] } } \tl_put_right:Nn \l_@@_store_anskey_arg_tl {#1} } { \tl_put_right:Nn \l_@@_store_anskey_arg_tl {#1} } % \end{macrocode} % Finally it checks if the \mykey{save-ref} key is active along with the % \mypkg[no-index]{hyperref} package load, if both conditions are met, it will % create the |\hyperlink| with \emph{\enquote{symbol}} set by \mykey[env]{mark-ref} % key and then store in \emph{sequence}. % \begin{macrocode} \bool_lazy_and:nnT { \bool_if_p:N \l_@@_store_ref_key_bool } { \bool_if_p:N \l_@@_hyperref_bool } { \tl_put_right:Ne \l_@@_store_anskey_arg_tl { \hfill \exp_not:N \hyperlink { \exp_not:V \l_@@_newlabel_arg_one_tl } { \exp_not:V \l_@@_mark_ref_sym_tl } } } \@@_store_addto_seq:V \l_@@_store_anskey_arg_tl } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_anskey_show_wrap_arg:n} % The function \myhlc|\@@_anskey_show_wrap_arg:n| \emph{\enquote{wraps}} % the \mymarg{argument} passed to |\anskey| and the \mymeta{body} % for \myenv*[no-index]{anskey*} when using the \mykey[env]{wrap-ans} and \mykey[env]{mark-sep} keys. % \begin{macrocode} \cs_new_protected:Nn \@@_anskey_show_wrap_arg:n { \par \bool_if:NTF \l_@@_starred_bool { \dim_compare:nNnT { \l_@@_mark_sym_sep_dim } = { \c_zero_dim } { \dim_set:Nn \l_@@_mark_sym_sep_dim { \l_@@_labelsep_vii_dim } } \@@_print_keyans_box:NN \l_@@_labelwidth_vii_dim \l_@@_mark_sym_sep_dim } { \dim_compare:nNnT { \l_@@_mark_sym_sep_dim } = { \c_zero_dim } { \dim_set:Nn \l_@@_mark_sym_sep_dim { \dim_use:c {l_@@_labelsep_ \@@_level: _dim } } } \@@_print_keyans_box:cc { l_@@_labelwidth_ \@@_level: _dim } { l_@@_mark_sym_sep_dim } } \@@_anskey_wrapper:n {#1} } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_anskey_show_wrap_left:n} % The function \myhlc|\@@_anskey_show_wrap_left:n| will show the % \emph{\enquote{mark}} defined by the \mykey[env]{mark-ans} key or the % \emph{\enquote{position}} of the \mymarg{content} stored in the \emph{prop list} % when using the \mykey[env]{show-pos} key on the left margin next to the % \emph{\enquote{wraps}} \mymarg{argument} passed to |\anskey| and % the \mymeta{body} in \myenv*[no-index]{anskey*} on the right side when using % the \mykey[env]{show-ans} key. % \begin{macrocode} \cs_new_protected:Nn \@@_anskey_show_wrap_left:n { \bool_if:NT \l_@@_show_answer_bool { \@@_anskey_show_wrap_arg:n {#1} } \bool_if:NT \l_@@_show_position_bool { \tl_set:Ne \l_@@_mark_answer_sym_tl { \group_begin: \exp_not:N \normalfont \exp_not:N \footnotesize [ \int_eval:n { \prop_count:c { g_@@_ \l_@@_store_name_tl _prop } } ] \group_end: } \@@_anskey_show_wrap_arg:n {#1} } } % \end{macrocode} % \end{macro} % % \subsection{The command \cs{anskey}}\label{cmd:anskey} % % Since \emph{\enquote{content}} is stored in a \myenv[no-index]{list} environment % within \emph{sequences} and the options passed to each level can be managed % (more or less), it is necessary to have a little more % control over |\item| when storing. % % The |\anskey| command will cover this point and give it similar % behavior to that of |\item| in the \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} % environments executed as follows |\anskey|\myoarg{key \textnormal{\textcolor{gray}{=}} val}\mymarg{content}. % % \subsubsection{Definition of variables for \cs[no-index]{anskey}} % % \begin{variable}[int]{\l_@@_anskey_level_int} % The integer variable \myhlc|\l_@@_anskey_level_int| will control the % nesting level of the |\anskey| command. % \begin{macrocode} \int_new:N \l_@@_anskey_level_int % \end{macrocode} % \end{variable} % % \subsubsection{Definition of error messages for \cs[no-index]{anskey}} % % \begin{macro}[int]{anskey-wrong-place, anskey-nested, % anskey-cmd-key-unknown, anskey-cmd-key-value-unknown} % Messages used by |\anskey| command. % \begin{macrocode} \msg_new:nnnn { enumext } { anskey-wrong-place } { Wrong~place~for~command~'\c_backslash_str #1'~\msg_line_context:. } { '\c_backslash_str #1'~works~in~the~environment~'#2'. } \msg_new:nnnn { enumext } { anskey-nested } { The~command~'\token_to_str:N \anskey'~can't~be~nested~ \msg_line_context:. } { Close~the~first~'\token_to_str:N \anskey'~before~using~another~one. } \msg_new:nnnn { enumext } { anskey-cmd-key-unknown } { The~key~'#1'~is~unknown~by~'\token_to_str:N \anskey'~and~is~being~ ignored~\msg_line_context:. } { The~command~'\token_to_str:N \anskey'~does~not~have~a~key~called~'#1'.~ Check~that~you~have~spelled~the~key~name~correctly. } \msg_new:nnnn { enumext } { anskey-cmd-key-value-unknown } { The~key~'#1=#2'~is~unknown~by~'\token_to_str:N \anskey'~and~is~being~ ignored~\msg_line_context:. } { The~command~'\token_to_str:N \anskey'~does~not~have~a~key~called~'#1'.~ Check~that~you~have~spelled~the~key~name~correctly. } % \end{macrocode} % \end{macro} % % \subsubsection{Definition of keys for \cs[no-index]{anskey}} % % \begin{macro}[int]{break-col, item-join, item-star, item-sym*, item-pos*, unknown} % First, the keys \mykey[anskey,anskey*]{break-col}, \mykey[anskey,anskey*]{item-join}, % \mykey[anskey,anskey*]{item-star}, \mykey[anskey,anskey*]{item-sym*} and \mykey[anskey,anskey*]{item-pos*} are added. % \begin{macrocode} \keys_define:nn { enumext / anskey } { break-col .bool_set:N = \l_@@_store_columns_break_bool, break-col .default:n = true, break-col .value_forbidden:n = true, item-join .int_set:N = \l_@@_store_item_join_int, item-join .value_required:n = true, item-star .bool_set:N = \l_@@_store_item_star_bool, item-star .default:n = true, item-star .value_forbidden:n = true, item-sym* .tl_set:N = \l_@@_store_item_symbol_tl, item-sym* .value_required:n = true, item-pos* .dim_set:N = \l_@@_store_item_symbol_sep_dim, item-pos* .value_required:n = true, unknown .code:n = { \@@_anskey_unknown:n {#1} }, } % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions for the command} % % \begin{macro}[int]{\@@_anskey_unknown:n, \@@_anskey_unknown:nn} % The \mymeta{keys} are stored in \cs{l_keys_key_str} and the value % (if any) is passed as an argument to the function \myhlc|\@@_anskey_unknown:n|. % \begin{macrocode} \cs_new_protected:Nn \@@_anskey_unknown:n { \exp_args:NV \@@_anskey_unknown:nn \l_keys_key_str {#1} } \cs_new_protected:Nn \@@_anskey_unknown:nn { \tl_if_blank:nTF {#2} { \msg_error:nnn { enumext } { anskey-cmd-key-unknown } {#1} } { \msg_error:nnnn { enumext } { anskey-cmd-key-value-unknown } {#1} {#2} } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_in_keyans:} % Inside \myenv*[no-index]{keyans}, \myenv*[no-index]{keyans*} and % \myenv*[no-index]{keyanspic} the flag \myhlc|\l_@@_store_active_bool| is % set to false on purpose, so the \mykey[env]{save-ans} checks cannot use it % there. The predicate \myhlc|\@@_in_keyans:| is true when any of these % environments is open, and it avoids a second error message for the same % mistake. % \begin{macrocode} \prg_new_conditional:Npnn \@@_in_keyans: { p , T , F , TF } { \int_compare:nNnTF { \l_@@_keyans_level_int + \l_@@_keyans_level_h_int + \l_@@_keyans_pic_level_int } > { 0 } { \prg_return_true: } { \prg_return_false: } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_anskey_safe_outer:, \@@_anskey_safe_inner:} % The \myhlc|\@@_anskey_safe_outer:| function will return the % appropriate messages when the command is executed outside the % environment in which the \mykey[env]{save-ans} key was activated or % inside the \myenv*[no-index]{keyans}, \myenv*[no-index]{keyans*} or % \myenv*[no-index]{keyanspic} environments. % \begin{macrocode} \cs_new_protected:Nn \@@_anskey_safe_outer: { \bool_lazy_or:nnF { \l_@@_store_active_bool } { \@@_in_keyans_p: } { \msg_error:nnnn { enumext } { anskey-wrong-place }{ anskey }{ enumext } } \int_compare:nNnT { \l_@@_keyans_level_int } = { 1 } { \msg_error:nnnn { enumext } { command-wrong-place }{ anskey }{ keyans } } \int_compare:nNnT { \l_@@_keyans_level_h_int } = { 1 } { \msg_error:nnnn { enumext } { command-wrong-place }{ anskey }{ keyans* } } \int_compare:nNnT { \l_@@_keyans_pic_level_int } = { 1 } { \msg_error:nnnn { enumext } { command-wrong-place }{ anskey }{ keyanspic } } } % \end{macrocode} % The \myhlc|\@@_anskey_safe_inner:| function will first check if the % command is nested, if preceded by a not numbered |\item| or if it is % in \emph{math mode} returning the appropriate messages. % \begin{macrocode} \cs_new_protected:Nn \@@_anskey_safe_inner: { \int_incr:N \l_@@_anskey_level_int \int_compare:nNnT { \l_@@_anskey_level_int } > { 1 } { \msg_error:nn { enumext } { anskey-nested } } \bool_if:NF \l_@@_item_number_bool { \msg_error:nn { enumext } { anskey-unnumber-item } } \mode_if_math:T { \msg_error:nne { enumext } { anskey-math-mode } { \token_to_str:N \anskey } } } % \end{macrocode} % \end{macro} % % \begin{important}* % The |\anskey| command will only be present when using the % \mykey{save-ans} key in \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} % environments, otherwise it will return an error. % \end{important} % % \begin{macro}{\anskey} % The command accepts an optional \myoarg{key \textnormal{\textcolor{gray}{=}} val} argument in `|#1|' and a % mandatory \mymarg{content} in `|#2|'. The function \myhlc|\@@_anskey_safe_outer:| is called first to be % sure where the command is executed, then the state of the % variable \myhlc|\l_@@_check_answers_bool| set by the key \mykey[env]{no-store} is checked; % if it is true, \myhlc|\g_@@_item_anskey_int| is incremented for the internal % \emph{\enquote{check answer}} system and the function % \myhlc|\@@_anskey_safe_inner:n| is executed to ensure that the command is not % nested and that the argument is not empty; finally the % \myoarg{key \textnormal{\textcolor{gray}{=}} val} is searched and the % function \myhlc|\@@_store_anskey_arg:n| is called. % \begin{macrocode} \NewDocumentCommand \anskey { o +m } { \@@_anskey_safe_outer: \group_begin: \bool_if:NT \l_@@_check_answers_bool { \tl_if_novalue:nF {#1} { \keys_set:nn { enumext / anskey } {#1} } \tl_if_blank:nTF {#2} { \msg_error:nn { enumext } { anskey-empty-arg } } { \@@_anskey_safe_inner: \@@_store_anskey_arg:n {#2} } } \group_end: } % \end{macrocode} % \end{macro} % % \subsection{The environment \env{anskey*}}\label{env:anskey} % % The original implementation of the \myenv*[no-index]{anskey*} environment used % non-public functions from the \mypkg{scontents}\cite{scontents} package, % which was not the best approach. Fortunately \hologo{LaTeX} release 2025-06-01 % implemented the new \texttt{c-type} argument in the \mypkg[no-index]{ltcmd}\cite{ltnews}, % with which the \mymeta{body} of the environment can be recorded in % \emph{verbatim mode}, and \myhlc|\tl_retokenize:n| (wrapper around the \myhlc|\scantokens|) % provided by \hologo{LaTeX}3 release 2025-07-08 does the work as the % original implementation. % % \subsubsection{Definition of variables for \env{anskey*}} % % \begin{variable}[int]{ % \l_@@_store_anskey_env_tl, % \l_@@_write_anskey_env_bool, % \l_@@_write_anskey_env_file_name_tl, % \l_@@_write_anskey_env_file_iow, % } % The variable \myhlc|\l_@@_store_anskey_env_tl| saves the \mymeta{body} % of the environment \myenv*[no-index]{anskey*} (\S\ref{env:anskey}). % % The variables \myhlc|\l_@@_write_anskey_env_bool|, \myhlc|\l_@@_write_anskey_env_file_name_tl| % and \myhlc|\l_@@_write_anskey_env_file_iow| are used by the \mykey{write-env} % and \mykey{overwrite} keys in the \myenv*[no-index]{anskey*} environment implementation. % \begin{macrocode} \tl_new:N \l_@@_store_anskey_env_tl \bool_new:N \l_@@_write_anskey_env_bool \tl_new:N \l_@@_write_anskey_env_file_name_tl \iow_new:N \l_@@_write_anskey_env_file_iow % \end{macrocode} % \end{variable} % % \begin{variable}[int]{\c_@@_anskey_env_hidden_space_str} % The \myhlc|\c_@@_anskey_env_hidden_space_str| is a constant \emph{string} % used to hide the \mymeta{forced space} added by \hologo{TeX} when % recording content in a macro. This \emph{string} contains the \emph{reserved phrase} % `|%^^Aenumextheol%|' which is added to the end of the argument stored % in \emph{sequence} and \emph{prop list} when the key \mykey{force-eol} is false. % \begin{macrocode} \str_const:Ne \c_@@_anskey_env_hidden_space_str { \c_percent_str \c_circumflex_str \c_circumflex_str A enumextheol \c_percent_str } % \end{macrocode} % \end{variable} % % \subsubsection{Definition of error messages for \env{anskey*}} % % \begin{macro}[int]{anskey-env-error} % Message used by reserved \myenv*[no-index]{anskey*} environment by \mypkg*[no-index]{enumext} % package. % \begin{macrocode} \msg_new:nnnn { enumext } { anskey-env-error } { The~environment~'#1'~is~reserved~by~'enumext'~package,~ it~is~already~defined~\msg_line_context:. } { The~environment~'#1'~is~defined~internally~ for~the~'save-ans'~key~with~save-ans~key~active.~See~documentation. } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{anskey-env-wrong, anskey-env-key-unknown, % anskey-env-key-value-unknown} % Messages used by \myenv*[no-index]{anskey*} environment. % \begin{macrocode} \msg_new:nnnn { enumext } { anskey-env-wrong } { The~environment~anskey*~cannot~be~used~in~'#1'~\msg_line_context:. } { 'anskey*'~can~only~be~used~with~the~key~'save-ans'~in~ 'enumext'~or~'enumext*'. } \msg_new:nnnn { enumext } { anskey-env-key-unknown } { The~key~'#1'~is~unknown~by~environment~ 'anskey*'~and~is~being~ignored~\msg_line_context:. } { The~environment~'anskey*'~does~not~have~a~key~called~'#1'.~ Check~that~you~have~spelled~the~key~name~correctly. } \msg_new:nnnn { enumext } { anskey-env-key-value-unknown } { The~key~'#1=#2'~is~unknown~by~environment~ 'anskey*'~and~is~being~ignored~\msg_line_context:. } { The~environment~'anskey*'~does~not~have~a~key~called~'#1'.~ Check~that~you~have~spelled~the~key~name~correctly. } % \end{macrocode} % \end{macro} % % \subsubsection{Definition of messages for writing files in \env{anskey*}} % % These messages are not error messages, they report to the terminal what % happens with the file written by the environment. % % \begin{macro}[int]{overwrite-file, writing-file, not-writing} % Messages used when \myenv*[no-index]{anskey*} writes the external file. % \begin{macrocode} \msg_new:nnn { enumext } { overwrite-file } { Overwriting~file~'#1'. } \msg_new:nnn { enumext } { writing-file } { Writing~file~'#1'. } \msg_new:nnn { enumext } { not-writing } { File~'#1'~already~exists.~Not~writing. } % \end{macrocode} % \end{macro} % % \subsubsection{Definition of keys for \env{anskey*}} % % \begin{macro}[int]{break-col, item-join, item-star, item-sym*, item-pos*, % force-eol, write-env, overwrite, unknown} % First, the same keys from the |\anskey| command are added along with the % \mykey[anskey,anskey*]{force-eol}, \mykey[anskey,anskey*]{write-env} and \mykey[anskey,anskey*]{overwrite} % keys that were in the original implementation that used the % \mypkg[no-index]{scontents} support package for these. % \begin{macrocode} \keys_define:nn { enumext / anskey* } { break-col .bool_set:N = \l_@@_store_columns_break_bool, break-col .default:n = true, break-col .value_forbidden:n = true, item-join .int_set:N = \l_@@_store_item_join_int, item-join .value_required:n = true, item-star .bool_set:N = \l_@@_store_item_star_bool, item-star .default:n = true, item-star .value_forbidden:n = true, item-sym* .tl_set:N = \l_@@_store_item_symbol_tl, item-sym* .value_required:n = true, item-pos* .dim_set:N = \l_@@_store_item_symbol_sep_dim, item-pos* .value_required:n = true, force-eol .bool_set:N = \l_@@_anskey_env_force_eol_bool, force-eol .initial:n = false, force-eol .default:n = true, write-env .code:n = { \bool_set_true:N \l_@@_write_anskey_env_bool \tl_set:Nn \l_@@_write_anskey_env_file_name_tl {#1} }, write-env .value_required:n = true, overwrite .bool_set:N = \l_@@_anskey_env_overwrite_bool, overwrite .initial:n = false, overwrite .default:n = true, unknown .code:n = { \@@_anskey_env_unknown:n {#1} }, } % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions for the environment} % % \begin{macro}[int]{\@@_anskey_env_unknown:n, \@@_anskey_env_unknown:nn} % The \mymeta{keys} are stored in \cs{l_keys_key_str} and the value % (if any) is passed as an argument to the function \myhlc|\@@_anskey_env_unknown:n|. % \begin{macrocode} \cs_new_protected:Nn \@@_anskey_env_unknown:n { \exp_args:NV \@@_anskey_env_unknown:nn \l_keys_key_str {#1} } \cs_new_protected:Nn \@@_anskey_env_unknown:nn { \tl_if_blank:nTF {#2} { \msg_error:nnn { enumext } { anskey-env-key-unknown } {#1} } { \msg_error:nnnn { enumext } { anskey-env-key-value-unknown } {#1} {#2} } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_anskey_env_file_if_writable:n, \@@_anskey_env_file_if_writable:nT, % \@@_anskey_env_file_if_writable:nF, \@@_anskey_env_file_if_writable:nTF, % \@@_anskey_env_file_write:nn, \@@_anskey_env_file_write:VV} % The conditional function \myhlc|\@@_anskey_env_file_if_writable:n| is used by % the \mykey[anskey*]{write-env} and \mykey[anskey*]{overwrite} keys in the \myenv*[no-index]{anskey*} % environment to determine whether the output file is written or overwritten. % \begin{macrocode} \prg_new_protected_conditional:Npnn \@@_anskey_env_file_if_writable:n #1 { T, F, TF } { \bool_if:NTF \l_@@_write_anskey_env_bool { \file_if_exist:nTF {#1} { \bool_if:NTF \l_@@_anskey_env_overwrite_bool { \msg_warning:nne { enumext } { overwrite-file } {#1} \prg_return_true: } { \msg_warning:nne { enumext } { not-writing } {#1} \prg_return_false: } } { \msg_warning:nne { enumext } { writing-file } {#1} \prg_return_true: } } { \prg_return_false: } } % \end{macrocode} % The \myhlc|\@@_anskey_env_file_write:nn| function is used by the % \mykey{write-env} key in the \myenv*[no-index]{anskey*} environment to write the % output file with the \mymeta{body} of the environment. % \begin{macrocode} \cs_new_protected:Nn \@@_anskey_env_file_write:nn { \@@_anskey_env_file_if_writable:nT {#1} { \iow_open:Nn \l_@@_write_anskey_env_file_iow {#1} \iow_now:Nn \l_@@_write_anskey_env_file_iow {#2} \iow_close:N \l_@@_write_anskey_env_file_iow } } \cs_generate_variant:Nn \@@_anskey_env_file_write:nn { VV } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_anskey_env_safe_outer:, \@@_anskey_env_safe_inner:, % \@@_store_anskey_env:n} % The function \myhlc|\@@_anskey_env_safe_outer:| will return the % appropriate messages when \myenv*[no-index]{anskey*} is executed outside the % environment in which the \mykey[env]{save-ans} key was activated % or within the \myenv*[no-index]{keyans}, \myenv*[no-index]{keyans*} or \myenv*[no-index]{keyanspic} % environments. % \begin{macrocode} \cs_new_protected:Nn \@@_anskey_env_safe_outer: { \bool_lazy_or:nnF { \l_@@_store_active_bool } { \@@_in_keyans_p: } { \msg_error:nnn { enumext } { anskey-env-error } { anskey* } } \int_compare:nNnT { \l_@@_keyans_level_int } = { 1 } { \msg_error:nnn { enumext } { anskey-env-wrong }{ keyans } } \int_compare:nNnT { \l_@@_keyans_level_h_int } = { 1 } { \msg_error:nnn { enumext } { anskey-env-wrong } { keyans* } } \int_compare:nNnT { \l_@@_keyans_pic_level_int } = { 1 } { \msg_error:nnn { enumext } { anskey-env-wrong } { keyanspic } } } % \end{macrocode} % The function \myhlc|\@@_anskey_env_safe_inner:| will first check if % preceded by a not numbered |\item| or if it is in \emph{math mode} % returning the appropriate messages. % \begin{macrocode} \cs_new_protected:Nn \@@_anskey_env_safe_inner: { \bool_if:NF \l_@@_item_number_bool { \msg_error:nn { enumext } { anskey-unnumber-item } } \mode_if_math:T { \msg_error:nnn { enumext } { anskey-math-mode } { anskey* } } } % \end{macrocode} % The \myhlc|\@@_store_anskey_env:n| function will first pass the % \texttt{c-type} argument \mymeta{body} to the variable \myhlc|\l_@@_store_anskey_env_tl| and % replace the macro |\obeyedline| with |^^J| and then execute the % \mykey{write-env} and \mykey{overwrite} keys, check the state of the % variable \myhlc|\l_@@_anskey_env_force_eol_bool| managed by the \mykey{force-eol} % key, and adds \myhlc|\c_@@_anskey_env_hidden_space_str| if % necessary. Finally it uses \myhlc|\exp_args:Ne| on the % \myhlc|\@@_store_anskey_arg:n| to expand the \myhlc|\tl_retokenize:n| % function which rescans the \myhlc|\l_@@_store_anskey_env_tl| variable % before processing it. % \begin{macrocode} \cs_new_protected:Nn \@@_store_anskey_env:n { \tl_set:Nn \l_@@_store_anskey_env_tl {#1} \RenewDocumentCommand \obeyedline { } { \iow_char:N \^^J } \tl_replace_all:Nee \l_@@_store_anskey_env_tl { \obeyedline } { \iow_char:N \^^J } \@@_anskey_env_file_write:VV \l_@@_write_anskey_env_file_name_tl \l_@@_store_anskey_env_tl \bool_if:NF \l_@@_anskey_env_force_eol_bool { \tl_put_right:Ne \l_@@_store_anskey_env_tl { \c_@@_anskey_env_hidden_space_str } } \exp_args:Ne \@@_store_anskey_arg:n { \tl_retokenize:n { \l_@@_store_anskey_env_tl } } } % \end{macrocode} % % \begin{important}* % Since |\obeyedline| can be redefined by the user, for example to % |\mbox{}\par|, it is necessary to redefine it to |^^J| in order to use % \myhlc|\tl_replace_all:Nee| otherwise it returns an error. % \end{important} % \end{macro} % % \begin{macro}{anskey*} % The environment accepts an optional \myoarg{key \textnormal{\textcolor{gray}{=}} val} argument in `|#1|' and a % \texttt{c-type} argument in `|#2|'. First, the function \myhlc|\@@_anskey_env_safe_outer:| is called to make % sure where the environment is running, then the state % of the variable \myhlc|\l_@@_check_answers_bool| set by the key % \mykey[env]{no-store} is checked. If it is true, it looks for \myoarg{key \textnormal{\textcolor{gray}{=}} val} % and verifies that the \emph{argument} \texttt{c-type} \mymeta{body} is not empty. % Finally, it runs the internal check function \myhlc|\@@_anskey_env_safe_inner:n| % and calls the function \myhlc|\@@_store_anskey_arg:n|. % \begin{macrocode} \NewDocumentEnvironment{anskey*}{ o c } { \@@_anskey_env_safe_outer: \bool_if:NT \l_@@_check_answers_bool { \tl_if_novalue:nF {#1} { \keys_set:nn { enumext / anskey* } {#1} } \tl_if_blank:nTF {#2} { \msg_error:nn { enumext } { anskey-empty-arg } } { \@@_anskey_env_safe_inner: \@@_store_anskey_env:n {#2} } } } { } % \end{macrocode} % \end{macro} % % \subsection{Executing \texttt{check-ans} system and write \texttt{.log}}\label{subsec:exec-after-env} % % \begin{macro}[int]{\@@_execute_after_env:} % The \myhlc|\@@_execute_after_env:| function will first return the % appropriate message for the end of the environment in which the % \mykey[env]{save-ans} key is being executed, then calls the % \myhlc|\@@_item_answer_diff:| function and then writes the values of % the global variables used to the |.log| file. If the key % \mykey[env]{check-ans} is active, it executes the function % \myhlc|\@@_check_ans_show:|, which warns on the terminal if the numbers differ, % otherwise it executes the function \myhlc|\@@_check_ans_log:| and writes the % results in the |.log| file, and finally executes the function % \myhlc|\@@_reset_global_vars:| returning the used variables to their % original state. % \begin{macrocode} \cs_new_protected:Nn \@@_execute_after_env: { \int_compare:nNnT { \l_@@_level_int } = { 0 } { \tl_if_empty:NF \g_@@_store_name_tl { \@@_stop_save_ans_msg: \@@_item_answer_diff: \@@_log_global_vars: \@@_log_answer_vars: \bool_if:NTF \g_@@_check_ans_key_bool { \@@_check_ans_show: } { \@@_check_ans_log: } } \@@_reset_global_vars: } } % \end{macrocode} % % \begin{important}* % This function is passed to the function \myhlc|\@@_after_env:nn| for the % environments \myenv*[no-index]{enumext} (\S\ref{env:enumext}) and \myenv*[no-index]{enumext*} (\S\ref{env:starred}) % and it is executed only when the environments are not nested or at some level of these. % \end{important} % \end{macro} % % \subsection{Common functions for \env{keyans}, \env{keyans*} and \env{keyanspic}}\label{subsec:common-keyans} % % \subsubsection{Definition of variables} % % \begin{variable}[int]{ % \l_@@_mark_sep_tmpa_dim, % \l_@@_mark_sep_tmpb_dim, % \l_@@_show_pos_tmp_int, % } % Internal variables used by \mykey{mark-sep}, \mykey{show-ans} and % \mykey{show-pos} keys (\S\ref{subsec:storage-system}). % \begin{macrocode} \dim_new:N \l_@@_mark_sep_tmpa_dim \dim_new:N \l_@@_mark_sep_tmpb_dim \int_new:N \l_@@_show_pos_tmp_int % \end{macrocode} % \end{variable} % % \subsubsection{Definition of error messages} % % \begin{macro}[int]{keyans-wrong-level, wrong-place} % Messages used by \myenv*[no-index]{keyans}, \myenv*[no-index]{keyans*} and % \myenv*[no-index]{keyanspic} environments. % \begin{macrocode} \msg_new:nnnn { enumext } { keyans-wrong-level } { Wrong~level~position~for~'keyans'~\msg_line_context:. } { The~environment~'keyans'~can~only~be~in~the~first~level. } \msg_new:nnnn { enumext } { wrong-place } { Wrong~place~for~'#1'~environment~\msg_line_context:. } { '#1'~is~only~found~with~'#2'~in~'enumext'. } % \end{macrocode} % \end{macro} % % \subsubsection{Storing content in prop list} % % \begin{macro}[int]{\@@_keyans_addto_prop:n} % The function \myhlc|\@@_keyans_addto_prop:n| will pass the current \mymeta{label} for |\item*| % in \myenv*[no-index]{keyans} environment and the current \mymeta{label} for % |\anspic*| in \myenv*[no-index]{keyanspic} environment followed by the % \mymeta{contents} of the \emph{optional argument} of both commands % to the \myhlc|\l_@@_store_current_label_tl| variable, which will be stored % to the \emph{prop list} defined by the \mykey[env]{save-ans} key using the % function \myhlc|\@@_store_addto_prop:V|. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_addto_prop:n { \tl_clear:N \l_@@_store_current_label_tl \int_compare:nNnTF { \l_@@_keyans_pic_level_int } = { 1 } { \tl_put_right:Ne \l_@@_store_current_label_tl { \l_@@_label_vi_tl } } { \tl_put_right:Ne \l_@@_store_current_label_tl { \l_@@_label_v_tl } } % \end{macrocode} % If the \emph{optional argument} is present and the \mykey[env]{save-sep} % key is not empty, it is saved. % \begin{macrocode} \tl_if_novalue:nF {#1} { \tl_if_empty:NF \l_@@_store_keyans_item_opt_sep_v_tl { \tl_put_right:NV \l_@@_store_current_label_tl \l_@@_store_keyans_item_opt_sep_v_tl } \tl_put_right:Nn \l_@@_store_current_label_tl {#1} } \@@_store_addto_prop:V \l_@@_store_current_label_tl } % \end{macrocode} % \end{macro} % % \subsubsection{The \texttt{save-ref} key for \env{keyans}, \env{keyans*} and \env{keyanspic}}\label{key:save-ref-keyans} % % The \emph{\enquote{internal label and ref}} system for the \myenv*[no-index]{keyans}, % \myenv*[no-index]{keyans*} and \myenv*[no-index]{keyanspic} environments has \emph{slight differences} % with the one implemented for |\anskey| basically because in this % environments the interest is in the current \mymeta{label} for |\item*| % and |\anspic*| with the \mymeta{contents} of the \emph{optional argument}. The mechanism % defined here allows executing |\ref|\mymarg{store name \textcolor{red}{:} position} and % will return |1.(A)|. % % \begin{macro}[int]{\@@_keyans_store_ref:, \@@_keyans_store_ref_aux_i:, % \@@_keyans_store_ref_aux_ii:} % The function \myhlc|\@@_keyans_store_ref:| handles the % \emph{\enquote{internal label and ref}} system used by the % \mykey[env]{save-ref} key for |\item*| and |\anspic*| commands. % First, copies of the current \mymeta{labels} are created and the % dots \enquote{\textcolor{red}{\texttt{.}}} are removed from them, since % double dots in references are not wanted. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_store_ref: { \bool_if:NT \l_@@_store_ref_key_bool { \cs_set_protected:Nn \@@_tmp:n { \tl_set_eq:cc { l_@@_label_copy_ ##1 _tl } { l_@@_label_ ##1 _tl } \tl_reverse:c { l_@@_label_copy_ ##1 _tl } \tl_remove_once:cn { l_@@_label_copy_ ##1 _tl } { . } \tl_reverse:c { l_@@_label_copy_ ##1 _tl } } \clist_map_inline:nn { i, v, vi, vii, viii } { \@@_tmp:n {##1} } \@@_keyans_store_ref_aux_i: } } % \end{macrocode} % The auxiliary function \myhlc|\@@_keyans_store_ref_aux_i:| sets the % variable \myhlc|\l_@@_newlabel_arg_one_tl| which will contain % \mymarg{store name \textcolor{red}{:} position} analyzing whether % the environment in which they are executed is \myenv*[no-index]{enumext*} or % \myenv*[no-index]{enumext}. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_store_ref_aux_i: { \bool_if:NT \g_@@_starred_bool { \tl_set_eq:NN \l_@@_label_copy_i_tl \l_@@_label_copy_vii_tl } \int_compare:nNnT { \l_@@_keyans_pic_level_int } = { 1 } { \tl_put_right:Ne \l_@@_newlabel_arg_two_tl { \l_@@_label_copy_i_tl . \l_@@_label_copy_vi_tl } } \int_compare:nNnT { \l_@@_keyans_level_int } = { 1 } { \tl_put_right:Ne \l_@@_newlabel_arg_two_tl { \l_@@_label_copy_i_tl . \l_@@_label_copy_v_tl } } \int_compare:nNnT { \l_@@_keyans_level_h_int } = { 1 } { \tl_put_right:Ne \l_@@_newlabel_arg_two_tl { \l_@@_label_copy_i_tl . \l_@@_label_copy_viii_tl } } \tl_put_right:Ne \l_@@_newlabel_arg_one_tl { \l_@@_store_name_tl \c_colon_str \int_eval:n { \prop_count:c { g_@@_ \l_@@_store_name_tl _prop } } } \@@_keyans_store_ref_aux_ii: } % \end{macrocode} % Now the auxiliary function \myhlc|\@@_keyans_store_ref_aux_ii:| saves the % result in the variable \myhlc|\l_@@_write_aux_file_tl| and finally % writes it in the |.aux| file. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_store_ref_aux_ii: { \tl_put_right:Ne \l_@@_write_aux_file_tl { \@@_newlabel:nn { \exp_not:V \l_@@_newlabel_arg_one_tl } { \l_@@_newlabel_arg_two_tl } } \l_@@_write_aux_file_tl } % \end{macrocode} % \end{macro} % % \subsubsection{Storing content in sequence} % % \begin{macro}[int]{\@@_keyans_addto_seq:n, \@@_keyans_addto_seq_link:} % The function \myhlc|\@@_keyans_addto_seq:n| will pass the % contents of the current \mymeta{label} \myhlc|\l_@@_label_v_tl| for the % \myenv*[no-index]{keyans} environment and the \myhlc|\l_@@_label_vi_tl| for the \myenv*[no-index]{keyanspic} environment when using % |\item*| and |\anspic*|, followed by the \mymeta{contents} of the % \emph{optional argument} of both commands to the \myhlc|\l_@@_store_current_label_tl| % variable to the sequence defined by the \mykey[env]{save-ans} key. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_addto_seq:n { \tl_clear:N \l_@@_store_current_label_tl \int_compare:nNnTF { \l_@@_keyans_pic_level_int } = { 1 } { \tl_put_right:Ne \l_@@_store_current_label_tl { \item \l_@@_label_vi_tl } } { \tl_put_right:Ne \l_@@_store_current_label_tl { \item \l_@@_label_v_tl } } \tl_if_novalue:nF {#1} { \tl_if_empty:NF \l_@@_store_keyans_item_opt_sep_v_tl { \tl_put_right:NV \l_@@_store_current_label_tl \l_@@_store_keyans_item_opt_sep_v_tl } \tl_put_right:Nn \l_@@_store_current_label_tl {#1} } \@@_keyans_addto_seq_link: } % \end{macrocode} % Checks if the \mykey[env]{save-ref} key is active along with the % \mypkg[no-index]{hyperref} package load, if both conditions are met, it will % create the |\hyperlink| and then store using the % \myhlc|\@@_store_addto_seq:V| function. % Finally, when the \mykey[env]{check-ans} key is active, it increments % the value of the integer variable \myhlc|\g_@@_item_anskey_int|. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_addto_seq_link: { \bool_lazy_and:nnT { \bool_if_p:N \l_@@_store_ref_key_bool } { \bool_if_p:N \l_@@_hyperref_bool } { \tl_put_right:Ne \l_@@_store_current_label_tl { \hfill \exp_not:N \hyperlink { \exp_not:V \l_@@_newlabel_arg_one_tl } { \exp_not:V \l_@@_mark_ref_sym_tl } } } \@@_store_addto_seq:V \l_@@_store_current_label_tl \bool_if:NT \l_@@_check_answers_bool { \int_gincr:N \g_@@_item_anskey_int } } % \end{macrocode} % \end{macro} % % \subsubsection{The \texttt{show-ans} and \texttt{show-pos} keys for \env{keyans} and \env{keyanspic}} % % \begin{macro}[int]{\@@_keyans_save_item_opt:n, \@@_keyans_show_item_opt:, % \@@_keyans_show_item_opt_viii:} % The function \myhlc|\@@_keyans_save_item_opt:n| will save the optional % argument of |\item*| and |\anspic*| in the variable % \myhlc|\l_@@_store_current_opt_arg_tl|. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_save_item_opt:n { \tl_if_novalue:nF {#1} { \tl_set:Nn \l_@@_store_current_opt_arg_tl {#1} } } % \end{macrocode} % The function \myhlc|\@@_keyans_show_item_opt:| will print the optional % arguments of |\item*| and |\anspic*| when the \mykey[env]{show-ans} or % \mykey[env]{show-pos} keys are set next to the key \mykey[env]{wrap-opt} in % \myenv*[no-index]{keyans} and \myenv*[no-index]{keyanspic} environments. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_show_item_opt: { \tl_if_empty:NF \l_@@_store_current_opt_arg_tl { \bool_lazy_or:nnT { \bool_if_p:N \l_@@_show_answer_bool } { \bool_if_p:N \l_@@_show_position_bool } { \@@_keyans_wrapper_opt_v:n { \l_@@_store_current_opt_arg_tl } \c_space_tl } } } % \end{macrocode} % The function \myhlc|\@@_keyans_show_item_opt_viii:| will print the optional % argument of |\item*| when the \mykey{show-ans} or \mykey{show-pos} % keys are set next to the key \mykey{wrap-opt} in \myenv*[no-index]{keyans*} % environment. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_show_item_opt_viii: { \tl_if_empty:NF \l_@@_store_current_opt_arg_tl { \bool_lazy_or:nnT { \bool_if_p:N \l_@@_show_answer_bool } { \bool_if_p:N \l_@@_show_position_bool } { \@@_keyans_wrapper_opt_viii:n { \l_@@_store_current_opt_arg_tl } \c_space_tl } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_keyans_pos_mark_set:, \@@_keyans_show_ans:, \@@_keyans_show_pos:} % The function \myhlc|\@@_keyans_pos_mark_set:| adjusts the horizontal % spaces for the \mykey[env]{mark-sep*} key taking into account the value of % the \mykey[env]{align} key and the width of \mymeta{label}. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_pos_mark_set: { \@@_label_width_by_box:Nn \l_@@_mark_sep_tmpa_dim { \l_@@_label_v_tl } \str_case:Vn \l_@@_align_label_pos_v_str { { l } { \dim_set:Nn \l_@@_mark_sep_tmpb_dim { \c_zero_dim } } { r } { \dim_set:Nn \l_@@_mark_sep_tmpb_dim { \l_@@_labelwidth_v_dim - \l_@@_mark_sep_tmpa_dim } } { c } { \dim_set:Nn \l_@@_mark_sep_tmpb_dim { 0.5\l_@@_labelwidth_v_dim - 0.5\l_@@_mark_sep_tmpa_dim } } } % \end{macrocode} % Sets the default values for the keys \mykey[env]{mark-ans*}, \mykey{mark-sep*} and \mykey[env]{mark-pos*}. % \begin{macrocode} \dim_compare:nNnT { \l_@@_mark_sym_sep_v_dim } = { \c_zero_dim } { \dim_set:Nn \l_@@_mark_sym_sep_v_dim { \l_@@_labelsep_v_dim } } \tl_set_eq:NN \l_@@_mark_answer_sym_tl \l_@@_mark_answer_sym_v_tl \dim_add:Nn \l_@@_mark_sym_sep_v_dim { \l_@@_mark_sep_tmpb_dim } \str_set_eq:NN \l_@@_mark_position_str \l_@@_mark_position_v_str } % \end{macrocode} % The function \myhlc|\@@_keyans_show_ans:| will print the \mymeta{symbol} % set by the \mykey{mark-ans*} key when the \mykey[env]{show-ans} key is active. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_show_ans: { \bool_lazy_all:nT { { \bool_if_p:N \l_@@_show_answer_bool } { \bool_if_p:N \l_@@_item_wrap_key_bool } } { \@@_keyans_pos_mark_set: \@@_print_keyans_box:NN \l_@@_labelwidth_v_dim \l_@@_mark_sym_sep_v_dim } } % \end{macrocode} % The function \myhlc|\@@_keyans_show_pos:| will print the \mymeta{position} % of the stored content in \emph{prop list}. It is the number of elements of the % prop list plus the value of \myhlc|\l_@@_show_pos_tmp_int|, which is incremented % in each execution inside \myenv*[no-index]{keyans} and is zero in the other % environments. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_show_pos: { \int_compare:nNnTF { \l_@@_keyans_level_int } = { 1 } { \int_incr:N \l_@@_show_pos_tmp_int } { \int_zero:N \l_@@_show_pos_tmp_int } \bool_lazy_all:nT { { \bool_if_p:N \l_@@_show_position_bool } { \bool_if_p:N \l_@@_item_wrap_key_bool } } { \tl_set:Ne \l_@@_mark_answer_sym_v_tl { \group_begin: \exp_not:N \normalfont \exp_not:N \footnotesize [ \int_eval:n { \prop_count:c { g_@@_ \l_@@_store_name_tl _prop } + \l_@@_show_pos_tmp_int } ] \group_end: } \@@_keyans_pos_mark_set: \@@_print_keyans_box:NN \l_@@_labelwidth_v_dim \l_@@_mark_sym_sep_v_dim } } % \end{macrocode} % \end{macro} % % \subsection{Redefining \cs{item} and \cs{makelabel} in \env{enumext}}\label{cmd:item-enumext} % % Redefining the |\item| command is not as simple as it seems. This % command works in conjunction with the |\makelabel| command, so both % of them have to be redefined; in addition, a couple of \emph{global} % variables are needed to pass the values from one command to the other. % % When \emph{tagged} \texttt{PDF} is active |\makelabel| is redefined % as |\hss #1| and the only way to get the \mykey{align} key to work % correctly is to redefine |\makelabel| using |\makebox|. The best way to % implement this is to use the conditional command \myhlc|\IfDocumentMetadataTF| % to force this redefinition and the dedicated \mykey{mode-box} key to % manually activate it by the user. % % The \ics*{item} and |\item|\myoarg{custom} commands work in the % usual way on \myenv*[no-index]{enumext}, and |\item*|, |\item*|\myoarg{symbol} and % |\item*|\myoarg{symbol}\myoarg{offset} are added. % % \begin{variable}[int]{\g_@@_item_symbol_aux_tl} % Internal variable used by \mykey{item-sym*} key (\S\ref{key:item-starred}). % \begin{macrocode} \tl_new:N \g_@@_item_symbol_aux_tl % \end{macrocode} % \end{variable} % % \begin{macro}[int]{\@@_default_item:n} % First it checks if the \emph{optional argument} is present; if it is NOT % present, it checks the state of the variable \myhlc|\l_@@_check_answers_bool| % set by the key \mykey[env]{no-store}, sets the boolean variable % \myhlc|\l_@@_wrap_label_X_bool| to |true| for the key \mykey[env]{wrap-label} % and executes \myhlc|\@@_item_std:w| and the key \mykey[env]{itemindent}; otherwise it checks the state % of the boolean variable \myhlc|\l_@@_wrap_label_opt_X_bool| set % by the key \mykey[env]{wrap-label*} and executes \myhlc|\@@_item_std:w| with % the \emph{optional argument} and the key \mykey{itemindent}. % \begin{macrocode} \cs_new_protected:Nn \@@_default_item:n { \tl_if_novalue:nTF {#1} { \bool_if:NT \l_@@_check_answers_bool { \int_gincr:N \g_@@_item_number_int \bool_set_true:N \l_@@_item_number_bool } \bool_set_true:c { l_@@_wrap_label_ \@@_level: _bool } \@@_item_std:w \tl_use:c { l_@@_fake_item_indent_ \@@_level: _tl } } { \bool_set_eq:cc { l_@@_wrap_label_ \@@_level: _bool } { l_@@_wrap_label_opt_ \@@_level: _bool } \@@_item_std:w [#1] \tl_use:c { l_@@_fake_item_indent_ \@@_level: _tl } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_item_starred_exec:nn, \@@_item_starred_exec:} % The |\item*|, |\item*|\myoarg{symbol} and |\item*|\myoarg{symbol}\myoarg{offset} % work like the \emph{numbered} |\item|, but placing a \mymeta{symbol} % to the \emph{\enquote{left}} of the \mymeta{label} separated from % it by the value of the second \emph{optional argument} \mymeta{offset}. % % \begin{arguments} % \item \myhlc|\l_@@_item_symbol_X_tl| % \item \myhlc|\l_@@_item_symbol_sep_X_dim| % \end{arguments} % % First a copy of \myhlc|\l_@@_item_symbol_X_tl| is made, which is % set by the key \mykey[env,anskey,anskey*]{item-sym*} or passed as \emph{\enquote{first}} \emph{optional argument} in % the global variable \myhlc|\g_@@_item_symbol_aux_tl|, followed by setting the % variable \myhlc|\l_@@_item_symbol_sep_X_dim| set by the key % \mykey[env,anskey,anskey*]{item-pos*} or by the \emph{\enquote{second}} \emph{optional argument}, % then the state of the variable \myhlc|\l_@@_check_answers_bool| % set by the key \mykey[env]{no-store} is checked, the boolean variable % \myhlc|\l_@@_wrap_label_X_bool| is set to |true| for the key \mykey[env]{wrap-label} % and \myhlc|\@@_item_std:w| and the key \mykey[env]{itemindent} are executed. % \begin{macrocode} \cs_new_protected:Nn \@@_item_starred_exec:nn { \tl_if_novalue:nTF {#1} { \tl_gset_eq:Nc \g_@@_item_symbol_aux_tl { l_@@_item_symbol_ \@@_level: _tl } } { \tl_gset:Nn \g_@@_item_symbol_aux_tl {#1} } \tl_if_novalue:nTF {#2} { \dim_set_eq:cc { l_@@_item_symbol_sep_ \@@_level: _dim } { l_@@_labelsep_ \@@_level: _dim } } { \dim_set:cn { l_@@_item_symbol_sep_ \@@_level: _dim } {#2} } \bool_if:NT \l_@@_check_answers_bool { \int_gincr:N \g_@@_item_number_int \bool_set_true:N \l_@@_item_number_bool } \bool_set_true:c { l_@@_wrap_label_ \@@_level: _bool } \@@_item_std:w \tl_use:c { l_@@_fake_item_indent_ \@@_level: _tl } } % \end{macrocode} % The function \myhlc|\@@_item_starred_exec:| will be responsible for % executing |\item*| for the \myenv*[no-index]{enumext} environment. % \begin{macrocode} \cs_new_protected:Nn \@@_item_starred_exec: { \tl_if_empty:cF { l_@@_item_symbol_ \@@_level: _tl } { \mode_leave_vertical: \skip_horizontal:n { -\dim_use:c { l_@@_item_symbol_sep_ \@@_level: _dim } } \hbox_overlap_left:n { \g_@@_item_symbol_aux_tl } \skip_horizontal:n { \dim_use:c { l_@@_item_symbol_sep_ \@@_level: _dim } } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_redefine_item:} % The function \myhlc|\@@_redefine_item:| will redefine the |\item| % command in the \myenv*[no-index]{enumext} environment adding |\item*|. % This function is passed to \myhlc|\@@_list_arg_two_X:| used % in the definition of the \myenv*[no-index]{enumext} environment (\S\ref{env:enumext}). % \begin{macrocode} \cs_new_protected:Nn \@@_redefine_item: { \RenewDocumentCommand \item { s o o } { \bool_if:nTF {##1} { \@@_item_starred_exec:nn {##2} {##3} } { \@@_default_item:n {##2} } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_make_label:, \@@_make_label_std:, \@@_make_label_box:} % The function \myhlc|\@@_make_label:| redefines |\makelabel| for the keys % \mykey[env]{mode-box}, \mykey[env]{align}, \mykey[env]{font}, \mykey[env]{wrap-label}, % \mykey[env]{wrap-label*} and |\item*| for \myenv*[no-index]{enumext} environment. % This function is passed to \myhlc|\@@_list_arg_two_X:| used % in the definition of the \myenv*[no-index]{enumext} environment (\S\ref{env:enumext}). % \begin{macrocode} \cs_new_protected:Nn \@@_make_label: { \IfDocumentMetadataTF { \@@_make_label_box: } { \bool_if:NTF \l_@@_mode_box_bool { \@@_make_label_box: } { \@@_make_label_std: } } } % \end{macrocode} % Standard definition when \myhlc|\DocumentMetadata| is not active. % \begin{macrocode} \cs_new_protected:Nn \@@_make_label_std: { \RenewDocumentCommand \makelabel { m } { \tl_use:c { l_@@_label_fill_left_ \@@_level: _tl } \@@_item_starred_exec: \tl_use:c { l_@@_label_font_style_ \@@_level: _tl } \bool_if:cTF { l_@@_wrap_label_ \@@_level: _bool } { \use:c { @@_wrapper_label_ \@@_level: :n } {##1} } {##1} \tl_use:c { l_@@_label_fill_right_ \@@_level: _tl } \tl_gclear:N \g_@@_item_symbol_aux_tl } } % \end{macrocode} % Definition using |\makebox| when \myhlc|\DocumentMetadata| is active or % \mykey{mode-box} is active. % % \begin{important} % Here it is necessary to use |\strut\smash| to maintain text \emph{alignment} % in case the user wants to use |\labelbx| for example. In experiments % with \emph{mimicking} the \myenv[no-index]{description} environment it was the only way % out and it seems to have no adverse effects and may serve in the future % as a basis for a more generic \myenv[no-index]{list} environment package than % \mypkg*[no-index]{enumext}. % \end{important} % % \begin{macrocode} \cs_new_protected:Nn \@@_make_label_box: { \RenewDocumentCommand \makelabel { m } { \strut\smash { \makebox [ \dim_use:c { l_@@_labelwidth_ \@@_level: _dim } ] [ \str_use:c { l_@@_align_label_pos_ \@@_level: _str } ] { \@@_item_starred_exec: \tl_use:c { l_@@_label_font_style_ \@@_level: _tl } \bool_if:cTF { l_@@_wrap_label_ \@@_level: _bool } { \use:c { @@_wrapper_label_ \@@_level: :n } {##1} } {##1} \tl_gclear:N \g_@@_item_symbol_aux_tl } } % close smash } } % \end{macrocode} % \end{macro} % % \subsection{Setting \texttt{item-sym*} and \texttt{item-pos*} keys}\label{key:item-starred} % % In order to have a cleaner implementation of |\item*| for the % \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} environments it is best to % define a couple of keys that allow controlling and setting by default the % \mymeta{symbol} and its \mymeta{offset}. % % \begin{macro}[int]{item-sym*, item-pos*} % Define and set \mykey[env,anskey,anskey*]{item-sym*} and \mykey[env,anskey,anskey*]{item-pos*} keys for % \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*}. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:nn { \keys_define:nn { enumext / #1 } { item-sym* .tl_set:c = { l_@@_item_symbol_ #2 _tl }, item-sym* .value_required:n = true, item-sym* .initial:n = {\textborn}, item-pos* .dim_set:c = { l_@@_item_symbol_sep_ #2 _dim }, item-pos* .value_required:n = true, } } \clist_map_inline:nn { {level-1}{i}, {level-2}{ii}, {level-3}{iii}, {level-4}{iv}, {enumext*}{vii} } { \@@_tmp:nn #1 } % \end{macrocode} % \end{macro} % % \subsection{Handling unknown keys}\label{key:unknown-keys} % % At this point in the code no more \mymeta{keys} will be added. Since the % definitions of environments and commands have already been quite % \emph{restrictive}, the only thing left to do is to be equally strict % with the \mymeta{keys} (consistency matters). % % \begin{important}* % Well, the paragraph above did not hold entirely: more % \mymeta{keys} had to be added than planned, and not everything turns out % as expected. % \end{important} % % \subsubsection{Definition of error messages} % % \begin{macro}[int]{starred-unknown-key, starred-unknown-key-value} % Message used by unknown \mymeta{keys} in \myenv*[no-index]{enumext*} % environment. % \begin{macrocode} \msg_new:nnnn { enumext } { starred-unknown-key } { The~key~'#1'~is~unknown~by~environment~ '\l_@@_envir_name_tl'~and~is~being~ignored~\msg_line_context:. } { The~environment~'\l_@@_envir_name_tl'~does~not~ have~a~key~called~'#1'.~ Check~that~you~have~spelled~the~key~name~correctly. } \msg_new:nnnn { enumext } { starred-unknown-key-value } { The~key~'#1=#2'~is~unknown~by~environment~ '\l_@@_envir_name_tl'~and~is~being~ignored~\msg_line_context:. } { The~environment~'\l_@@_envir_name_tl'~does~not~ have~a~key~called~'#1'.~ Check~that~you~have~spelled~the~key~name~correctly. } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{standard-unknown-key, standard-unknown-key-value} % Message used by unknown \mymeta{keys} in \myenv*[no-index]{enumext} % environment. % \begin{macrocode} \msg_new:nnnn { enumext } { standard-unknown-key } { The~key~'#1'~is~unknown~by~environment~'\l_@@_envir_name_tl'~on~level~ \int_use:N \l_@@_level_int \c_space_tl and~is~being~ignored~ \msg_line_context:. } { The~environment~'\l_@@_envir_name_tl'~does~not~ have~a~key~called~'#1'~on~level~\int_use:N \l_@@_level_int.~ Check~that~you~have~spelled~the~key~name~correctly. } \msg_new:nnnn { enumext } { standard-unknown-key-value } { The~key~'#1=#2'~is~unknown~by~environment~'\l_@@_envir_name_tl'~on~level~ \int_use:N \l_@@_level_int \c_space_tl and~is~being~ignored~ \msg_line_context:. } { The~environment~'\l_@@_envir_name_tl'~does~not~ have~a~key~called~'#1'~on~level~\int_use:N \l_@@_level_int.~ Check~that~you~have~spelled~the~key~name~correctly. } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{keyans-unknown-key, keyans-unknown-key-value} % Message used by unknown \mymeta{keys} in \myenv*[no-index]{keyans}, % \myenv*[no-index]{keyans*} and \myenv*[no-index]{keyanspic} environments. % \begin{macrocode} \msg_new:nnnn { enumext } { keyans-unknown-key } { The~key~'#1'~is~unknown~by~environment~ '\l_@@_envir_name_tl'~and~is~being~ignored~\msg_line_context:. } { The~environment~'\l_@@_envir_name_tl'~does~not~ have~a~key~called~'#1'.~ Check~that~you~have~spelled~the~key~name~correctly. } \msg_new:nnnn { enumext } { keyans-unknown-key-value } { The~key~'#1=#2'~is~unknown~by~environment~ '\l_@@_envir_name_tl'~and~is~being~ignored~\msg_line_context:. } { The~environment~'\l_@@_envir_name_tl'~does~not~ have~a~key~called~'#1'.~ Check~that~you~have~spelled~the~key~name~correctly. } % \end{macrocode} % \end{macro} % % \subsubsection{Handling unknown keys for \env{keyans}, \env{keyans*} and \env{keyanspic}}\label{key:unknown-keys-keyans} % % \begin{macro}[int]{unknown, \@@_keyans_unknown_keys:n, \@@_keyans_unknown_keys:nn} % Define and set |unknown| key for \myenv*[no-index]{keyans}, \myenv*[no-index]{keyans*} % and \myenv*[no-index]{keyanspic} environments. Here it is necessary to set % \myhlc|\l_@@_envir_name_tl| in case an |unknown| key is passed using |\setenumext|. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:n { \keys_define:nn { enumext / #1 } { unknown .code:n = { \tl_set:Nn \l_@@_envir_name_tl {#1} \@@_keyans_unknown_keys:n {##1} }, } } \clist_map_inline:nn { keyans, keyans*, keyanspic } { \@@_tmp:n {#1} } % \end{macrocode} % Internal functions for handling |unknown| key. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_unknown_keys:n { \exp_args:NV \@@_keyans_unknown_keys:nn \l_keys_key_str {#1} } \cs_new_protected:Nn \@@_keyans_unknown_keys:nn { \tl_if_blank:nTF {#2} { \msg_error:nne { enumext } { keyans-unknown-key } {#1} } { \msg_error:nnee { enumext } { keyans-unknown-key-value } {#1} {#2} } } % \end{macrocode} % \end{macro} % % \subsubsection{Handling unknown keys for \env{enumext*}}\label{key:unknown-keys-starred} % % \begin{macro}[int]{unknown} % Define and set |unknown| key for \myenv*[no-index]{enumext*} environment. % \begin{macrocode} \keys_define:nn { enumext / enumext* } { unknown .code:n = { \tl_set:Ne \l_@@_envir_name_tl { enumext* } \@@_starred_unknown_keys:n {#1} }, } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_starred_unknown_keys:n, \@@_starred_unknown_keys:nn} % Internal functions for handling |unknown| key. % \begin{macrocode} \cs_new_protected:Nn \@@_starred_unknown_keys:n { \exp_args:NV \@@_starred_unknown_keys:nn \l_keys_key_str {#1} } \cs_new_protected:Nn \@@_starred_unknown_keys:nn { \tl_if_blank:nTF {#2} { \msg_error:nne { enumext } { starred-unknown-key } {#1} } { \msg_error:nnee { enumext } { starred-unknown-key-value } {#1} {#2} } } % \end{macrocode} % \end{macro} % % \subsubsection{Handling unknown keys for \env{enumext}}\label{key:unknown-keys-standard} % % \begin{macro}[int]{unknown, \@@_standard_unknown_keys:n, \@@_standard_unknown_keys:nn} % Defines and sets the key |unknown| for \myenv*[no-index]{enumext} environment. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:n { \keys_define:nn { enumext / level-#1 } { unknown .code:n = { \int_set:Nn \l_@@_level_int {#1} \tl_set:Ne \l_@@_envir_name_tl { enumext } \@@_standard_unknown_keys:n {##1} }, } } \clist_map_inline:nn {1, 2, 3, 4} { \@@_tmp:n {#1} } % \end{macrocode} % Internal functions for handling |unknown| key. % \begin{macrocode} \cs_new_protected:Nn \@@_standard_unknown_keys:n { \exp_args:NV \@@_standard_unknown_keys:nn \l_keys_key_str {#1} } \cs_new_protected:Nn \@@_standard_unknown_keys:nn { \tl_if_blank:nTF {#2} { \msg_error:nne { enumext } { standard-unknown-key } {#1} } { \msg_error:nnee { enumext } { standard-unknown-key-value } {#1} {#2} } } % \end{macrocode} % \end{macro} % % \subsection{Redefining \cs{item} and \cs{makelabel} in \env{keyans}}\label{cmd:item-keyans} % % The |\item| and |\item|\myoarg{custom} commands work in the % usual way in \myenv*[no-index]{keyans}, but the |\item*| and |\item*|\myoarg{content} % commands \emph{store} the current \mymeta{label} next to the \mymeta{content} % if it is present in the \emph{sequence} and \emph{prop list} defined by % \mykey{save-ans} key. % % \begin{macro}[int]{\@@_keyans_default_item:n} % The function \myhlc|\@@_keyans_default_item:n| executes the original % behavior of the |\item| along with the keys \mykey[env]{wrap-label}, % \mykey[env]{wrap-label*} and \mykey[env]{itemindent}. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_default_item:n { \tl_if_novalue:nTF {#1} { \bool_set_true:N \l_@@_wrap_label_v_bool \@@_item_std:w \tl_use:N \l_@@_fake_item_indent_v_tl } { \bool_set_eq:NN \l_@@_wrap_label_v_bool \l_@@_wrap_label_opt_v_bool \@@_item_std:w [#1] \tl_use:N \l_@@_fake_item_indent_v_tl } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_keyans_starred_item:n} % The function \myhlc|\@@_keyans_starred_item:n| will take as argument `|#1|' % the \emph{optional argument} \myoarg{content} passed to |\item*| and % save it via the \myhlc|\@@_keyans_save_item_opt:n| function, then activate % the \mykey[env]{wrap-label} key, execute |\item| using \myhlc|\@@_item_std:w|, % the \mykey[env]{itemindent} key and print the \emph{optional argument} using % the \myhlc|\@@_keyans_show_item_opt:| function handled by the % \mykey[env]{wrap-opt} key. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_starred_item:n { \@@_keyans_save_item_opt:n {#1} \bool_set_true:N \l_@@_wrap_label_v_bool \@@_item_std:w \tl_use:N \l_@@_fake_item_indent_v_tl \@@_keyans_show_item_opt: % \end{macrocode} % Now \emph{store} the current \mymeta{label} first in the \emph{prop list} % (including the \emph{optional argument}), run the internal \emph{\enquote{label and ref}} % system if the \mykey[env]{save-ref} key is active, then \emph{store} in the \emph{sequence} % and finally it increments \myhlc|\g_@@_check_starred_cmd_int| for internal % check system. % \begin{macrocode} \@@_keyans_addto_prop:n {#1} \@@_keyans_store_ref: \@@_keyans_addto_seq:n {#1} \int_gincr:N \g_@@_check_starred_cmd_int } % \end{macrocode} % \end{macro} % % \begin{macro}{\item*, \@@_keyans_redefine_item:} % The function \myhlc|\@@_keyans_redefine_item:| is responsible for adding % the \emph{starred argument} and \emph{optional argument} by the % \myhlc|\@@_list_arg_two_v:| function in the definition of the % \myenv*[no-index]{keyans} environment. Here the variable % \myhlc|\l_@@_item_wrap_key_bool| used by the \mykey[env]{wrap-ans*} key is set % to true only when |\item*| is executed and, additionally, it is necessary to use % \myhlc|\peek_remove_spaces:n| to avoid an unwanted space when using % |\item*| together with the \mykey[env]{itemindent} key. % This function is passed to \myhlc|\@@_list_arg_two_v:| used % in the definition of the \myenv*[no-index]{keyans} environment (\S\ref{subsec:second-arg}). % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_redefine_item: { \RenewDocumentCommand \item { s o } { \bool_if:nTF {##1} { \bool_set_true:N \l_@@_item_wrap_key_bool % wrap-ans* \peek_remove_spaces:n { \@@_keyans_starred_item:n {##2} } } { \bool_set_false:N \l_@@_item_wrap_key_bool \@@_keyans_default_item:n {##2} } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_keyans_make_label:, \@@_keyans_wrapper_label:n, % \@@_keyans_make_label_std:, \@@_keyans_make_label_box:, % \@@_wrapper_label_v:n} % The function \myhlc|\@@_keyans_make_label:| redefines |\makelabel| % for the keys \mykey[env]{mode-box}, \mykey[env]{align}, \mykey[env]{font}, % \mykey[env]{wrap-label}, \mykey[env]{wrap-label*}, \mykey[env]{wrap-ans*} and |\item*| % for \myenv*[no-index]{keyans} environment. % This function is passed to \myhlc|\@@_list_arg_two_v:| used % in the definition of the \myenv*[no-index]{keyans} environment (\S\ref{subsec:second-arg}). % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_make_label: { \IfDocumentMetadataTF { \@@_keyans_make_label_box: } { \bool_if:NTF \l_@@_mode_box_bool { \@@_keyans_make_label_box: } { \@@_keyans_make_label_std: } } } % \end{macrocode} % Conditionals are added to the \myhlc|\@@_keyans_wrapper_label:n| function % to handle the keys \mykey{wrap-ans*}, \mykey{wrap-label} and \mykey{wrap-label*}. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_wrapper_label:n { \bool_lazy_all:nT { { \bool_if_p:N \l_@@_wrap_label_v_bool } { \bool_if_p:N \l_@@_show_answer_bool } { \bool_if_p:N \l_@@_item_wrap_key_bool } { \cs_if_exist_p:N \@@_keyans_wrapper_item_v:n } } { \cs_set_eq:NN \@@_wrapper_label_v:n \@@_keyans_wrapper_item_v:n } \bool_if:NTF \l_@@_wrap_label_v_bool { \@@_wrapper_label_v:n {#1} } {#1} } % \end{macrocode} % Standard definition when \myhlc|\DocumentMetadata| is not active. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_make_label_std: { \RenewDocumentCommand \makelabel { m } { \tl_use:N \l_@@_label_fill_left_v_tl \@@_keyans_show_ans: \@@_keyans_show_pos: \tl_use:N \l_@@_label_font_style_v_tl \@@_keyans_wrapper_label:n {##1} \tl_use:N \l_@@_label_fill_right_v_tl } } % \end{macrocode} % Definition using |\makebox| when \myhlc|\DocumentMetadata| is active or % \mykey{mode-box} is active. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_make_label_box: { \RenewDocumentCommand \makelabel { m } { \strut\smash { \makebox[ \l_@@_labelwidth_v_dim ][ \l_@@_align_label_pos_v_str ] { \@@_keyans_show_ans: \@@_keyans_show_pos: \tl_use:N \l_@@_label_font_style_v_tl \@@_keyans_wrapper_label:n {##1} } } } } % \end{macrocode} % \end{macro} % % \subsection{Second argument of the lists}\label{subsec:second-arg} % % At this point in the code most of the tools needed to create a % \emph{custom} \myenv[no-index]{list} environment have already been programmed. Remember that the % \myhlc|\@@_start_list:nn| function takes two arguments: the \enquote{first} % one is ready, and the \enquote{second} one is defined for all levels of the % \myenv*[no-index]{enumext} environment, the \myenv*[no-index]{keyans} environment and the % \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} environments. % % Here the \myhlc|\@@_list_arg_two_X:| function is implemented, % which is responsible for setting all the list parameters, the % counter, the redefinition of |\item|, |\makelabel| along with the keys % \mykey{ref}, \mykey{itemindent} and \mykey{show-length}. % % \subsubsection{Definition of variables} % % \begin{variable}[int]{\l_@@_itemindent_X_dim} % The dimension \myhlc|\l_@@_itemindent_X_dim| is set by the function % \myhlc|\@@_calc_hspace:NNNNNNN| (\S\ref{subsubsec:leftmargin}). % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:n { \dim_new:c { l_@@_itemindent_ #1 _dim } } \clist_map_inline:nn { i, ii, iii, iv, v, vi, vii, viii } { \@@_tmp:n {#1} } % \end{macrocode} % \end{variable} % % \subsubsection{Definition of error messages} % % \begin{macro}[int]{width-negative} % Messages used in length calculation. % \begin{macrocode} \msg_new:nnn { enumext } { width-negative } { Ignoring~negative~value~'#1=#2'~\msg_line_context:.\\ The~key~'#1'~accepts~values~>=~0pt. } % \end{macrocode} % \end{macro} % % \subsubsection{Definition of messages for the \texttt{show-length} key} % % The messages that print the lengths of the lists to the terminal; they are % not error messages. % % \begin{macro}[int]{list-lengths} % Messages used by \mykey[env]{show-length} key in \myenv*[no-index]{enumext}. % \begin{macrocode} \msg_new:nnn { enumext } { list-lengths } { ****~Lengths~used~by~'enumext'~level~'#2'~ \msg_line_context:~\c_space_tl ****\\ \@@_show_length:nnn { dim } { labelsep } {#1} \@@_show_length:nnn { dim } { labelwidth } {#1} \@@_show_length:nnn { dim } { itemindent } {#1} \@@_show_length:nnn { dim } { leftmargin } {#1} \@@_show_length:nnn { dim } { rightmargin } {#1} \@@_show_length:nnn { dim } { listparindent } {#1} \@@_show_length:nnn { skip } { topsep } {#1} \@@_show_length:nnn { skip } { parsep } {#1} \@@_show_length:nnn { skip } { partopsep } {#1} \@@_show_length:nnn { skip } { itemsep } {#1} **************************************************** } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{list-lengths-not-nested} % Messages used by \mykey[env]{show-length} key in \myenv*[no-index]{enumext*}, % \myenv*[no-index]{keyans*} and \myenv*[no-index]{keyans}. % \begin{macrocode} \msg_new:nnn { enumext } { list-lengths-not-nested } { ****~Lengths~used~by~'#2'~environment~ \msg_line_context:~\c_space_tl ****\\ \@@_show_length:nnn { dim } { labelsep } {#1} \@@_show_length:nnn { dim } { labelwidth } {#1} \@@_show_length:nnn { dim } { itemindent } {#1} \@@_show_length:nnn { dim } { leftmargin } {#1} \@@_show_length:nnn { dim } { rightmargin } {#1} \@@_show_length:nnn { dim } { listparindent } {#1} \@@_show_length:nnn { skip } { topsep } {#1} \@@_show_length:nnn { skip } { parsep } {#1} \@@_show_length:nnn { skip } { partopsep } {#1} \@@_show_length:nnn { skip } { itemsep } {#1} **************************************************** } % \end{macrocode} % \end{macro} % % \subsubsection{Calculation of \cs{leftmargin} and \cs{itemindent}}\label{subsubsec:leftmargin} % % Consider the figure~\ref{fig:eight} where the default margins (on the % left) of a list are represented. % % \begin{figure}[!htbp] % \centering % \begin{tikzpicture}[line cap=round,line join=round,x=0.8cm,y=0.8cm,every node/.style={font=\footnotesize}] % \draw[<->,color=gray] (-0.5,6.175) --node[below,text=lightgray,font=\footnotesize\ttfamily]{margin page} (2,6.175); % \draw[line width=0.5pt,dash pattern=on 2pt off 2pt,color=gray] (2,4.85) -- (2,7.5); % \draw[<->,color=gray] (2.0,7.0) --node[above,text=keyname]{\vphantom{p}\texttt{list-offset}} (4.5,7.0); % \draw[<->,color=gray] (4.5,7.0) --node[above,text=blue!75]{\vphantom{p}\texttt{\textbackslash{}labelwidth}} (7.5,7.0); % \draw[<->,color=gray] (7.5,7.0) --node[above,text=blue!75]{\texttt{\textbackslash{}labelsep}} (9.5,7.0); % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (4.5,6.5) rectangle (7.5,6.85);% labelwidth % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.5,6.5) rectangle (9.5,6.85);% labelsep % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (9.5,6.5) rectangle (15,6.85);% item width % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (9.5,6.0) rectangle (15,6.35); % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (9.5,5.5) rectangle (15,5.85); % \draw[<->,color=gray] (1.25,5.35) --node[below,text=blue!75]% % {\begin{tabular}{c} % \texttt{\textbackslash{}leftmargin + \textbackslash{}itemindent} \\ % \mykey{list-indent} % \end{tabular}} (9.5,5.35); % \end{tikzpicture} % \caption{Representation of standard horizontal lengths in \myenv[no-index]{list} environment.} % \label{fig:eight} % \end{figure} % % The idea is to have control over these margins so that the list does % not overlap the left margin of the page. The \emph{key} relationship is that % the \emph{\enquote{right edge}} of the |\labelsep| equals the \emph{\enquote{right edge}} of the |\itemindent|, % so that the left edge of the \emph{\enquote{label box}} is at |\leftmargin+\itemindent| minus |\labelwidth+\labelsep|. % Thus, the handling of the margins by the package will be as shown in % the figure~\ref{fig:nine}. % % \begin{figure}[!htbp] % \centering % \begin{tikzpicture}[line cap=round,line join=round,x=0.8cm,y=0.8cm,every node/.style={font=\footnotesize}] % \draw[<->,color=gray] (-0.5,6.175) --node[below,text=lightgray,font=\footnotesize\ttfamily]{margin page} (2,6.175); % \draw[line width=0.5pt,dash pattern=on 2pt off 2pt,color=gray] (2,4.85) -- (2,7.5); % \draw[<->,color=gray] (2.0,7.0) --node[above,text=keyname]{\vphantom{p}\texttt{list-offset}} (4.5,7.0); % \draw[<->,color=gray] (4.5,7.0) --node[above,text=blue!75]{\vphantom{p}\texttt{\textbackslash{}labelwidth}} (7.5,7.0); % \draw[<->,color=gray] (7.5,7.0) --node[above,text=blue!75]{\texttt{\textbackslash{}labelsep}} (9.5,7.0); % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (4.5,6.5) rectangle (7.5,6.85);% labelwidth % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.5,6.5) rectangle (9.5,6.85);% labelsep % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (9.5,6.5) rectangle (15,6.85);% item width % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (9.5,6.0) rectangle (15,6.35); % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (9.5,5.5) rectangle (15,5.85); % \draw[<->,color=gray] (4.5,5.35) --node[below,text=blue!75]% % {\begin{tabular}{c} % \texttt{\textbackslash{}leftmargin + \textbackslash{}itemindent} \\ % \mykey{list-indent} % \end{tabular}} (9.5,5.35); % \end{tikzpicture} % \caption{Representation of horizontal lengths concept in list in \mypkg*[no-index]{enumext}.} % \label{fig:nine} % \end{figure} % % Where the default values will look like in the figure~\ref{fig:last}. % % \begin{figure}[htbp] % \centering % \begin{tikzpicture}[line cap=round,line join=round,x=0.8cm,y=0.8cm,every node/.style={font=\footnotesize}] % \draw[<->,color=gray] (-0.5,6.175) --node[below,text=lightgray,font=\footnotesize\ttfamily]{margin page} (2,6.175); % \draw [line width=0.5pt,dash pattern=on 2pt off 2pt,color=gray] (2,4.85) -- (2,7.5); % \draw[<->,color=gray] (2.0,7.0) --node[above,text=keyname]{\vphantom{p}\texttt{labelwidth}} (5.0,7.0); % \draw[<->,color=gray] (5.0,7.0) --node[above,text=keyname]{\texttt{labelsep}} (7.0,7.0); % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (2.0,6.5) rectangle (5.0,6.85);% labelwidth % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (5.0,6.5) rectangle (7.0,6.85);% labelsep % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,6.5) rectangle (15,6.85);% item width % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,6.0) rectangle (15,6.35); % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,5.5) rectangle (15,5.85); % \draw[<->,color=gray] (2.0,5.35) --node[below,text=blue!75]% % {\begin{tabular}{c} % \texttt{\textbackslash{}leftmargin + \textbackslash{}itemindent} \\ % \mykey{list-indent} % \end{tabular}} % (7.0,5.35); % \end{tikzpicture} % \caption{Default horizontal lengths in \mypkg*[no-index]{enumext}.} % \label{fig:last} % \end{figure} % % \begin{macro}[int]{\@@_calc_hspace:NNNNNNN, \@@_calc_hspace:ccccccc} % The function \myhlc|\@@_calc_hspace:NNNNNNN| takes seven arguments to be % able to determine horizontal spaces for all list environment: % % \begin{arguments} % \item \myhlc|\l_@@_labelwidth_X_dim| % \item \myhlc|\l_@@_labelsep_X_dim| % \item \myhlc|\l_@@_listoffset_X_dim| % \item \myhlc|\l_@@_leftmargin_tmp_X_dim| % \item \myhlc|\l_@@_leftmargin_X_dim| % \item \myhlc|\l_@@_itemindent_X_dim| % \item \myhlc|\l_@@_leftmargin_tmp_X_bool| % \end{arguments} % % And returns the \emph{\enquote{adjusted}} values of |\leftmargin| % and |\itemindent|. % % % \begin{macrocode} \cs_new_protected:Nn \@@_calc_hspace:NNNNNNN { \dim_compare:nNnT {#1} < { \c_zero_dim } { \msg_warning:nnnV { enumext } { width-negative }{ labelwidth } #1 \dim_set:Nn #1 { \dim_abs:n {#1} } } \dim_compare:nNnT {#2} < { \c_zero_dim } { \msg_warning:nnnV { enumext } { width-negative }{ labelsep } #2 \dim_set:Nn #2 { \dim_abs:n {#2} } } % \end{macrocode} % If no value has been passed to the \mykey[env]{labelwidth} and \mykey[env]{labelsep} keys, the % default values are set for \myhlc|\l_@@_leftmargin_tmp_X_dim|. % \begin{macrocode} \bool_if:NF #7 { \dim_set:Nn #4 { #1 + #2} } % \end{macrocode} % The cases are now analyzed and the values for |\leftmargin| and % |\itemindent| are set. % \begin{macrocode} \dim_compare:nNnTF {#4} < { \c_zero_dim } { \dim_set:Nn #6 { #1 + #2 - #4} \dim_set:Nn #5 { #1 + #2 + #3 - #6 } } { \dim_compare:nNnT {#4} = { #1 + #2 } { \dim_set:Nn #6 { \c_zero_dim } } \dim_compare:nNnT {#4} < { #1 + #2 } { \dim_set:Nn #6 { #1 + #2 - #4} } \dim_compare:nNnT {#4} > { #1 + #2 } { \dim_set:Nn #6 { -#1 - #2 + #4} \dim_set:Nn #6 { #6*-1} } \dim_set:Nn #5 { #1 + #2 + #3 - #6 } } } \cs_generate_variant:Nn \@@_calc_hspace:NNNNNNN { ccccccc } % \end{macrocode} % \end{macro} % % \subsubsection{Setting second argument of the lists} % % \begin{macro}[int]{\@@_list_arg_two_i:, \@@_list_arg_two_ii:, \@@_list_arg_two_iii:, % \@@_list_arg_two_iv:, \@@_list_arg_two_v:} % |\leftmargini|, |\leftmarginii|, |\leftmarginiii| and % |\leftmarginiv| are \enquote{not set}; in this case, the parameters % for vertical and horizontal list spacing per level are set directly. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:n { \cs_new_protected:cpn { @@_list_arg_two_ #1 : } { \@@_calc_hspace:ccccccc { l_@@_labelwidth_ #1 _dim } { l_@@_labelsep_ #1 _dim } { l_@@_listoffset_ #1 _dim } { l_@@_leftmargin_tmp_ #1 _dim } { l_@@_leftmargin_ #1 _dim } { l_@@_itemindent_ #1 _dim } { l_@@_leftmargin_tmp_ #1 _bool } \clist_map_inline:nn { labelsep, labelwidth, itemindent, leftmargin, rightmargin, listparindent } { \dim_set_eq:cc {####1} { l_@@_####1 _ #1 _dim } } \clist_map_inline:nn { topsep, parsep, partopsep, itemsep } { \skip_set_eq:cc {####1} { l_@@_####1 _ #1 _skip } } \clist_map_inline:nn { beginparpenalty, itempenalty, endparpenalty } { \int_set_eq:cc {@####1} { l_@@_####1 _ #1 _int } } \usecounter { enumX #1 } \setcounter { enumX #1 } { \int_eval:n { \int_use:c { l_@@_start_ #1 _int } - 1 } } \str_if_eq:nnTF {#1} { v } { \@@_keyans_redefine_item: \@@_keyans_make_label: \@@_keyans_ref: \@@_keyans_fake_item_indent: \bool_if:cT { l_@@_show_length_ #1 _bool } { \msg_term:nnnn { enumext } { list-lengths-not-nested } { v } { keyans } } } { \@@_redefine_item: \@@_make_label: \@@_standard_ref: \@@_fake_item_indent: \bool_if:cT { l_@@_show_length_ #1 _bool } { \msg_term:nnne { enumext } { list-lengths } {#1} { \int_use:N \l_@@_level_int } } } } } \clist_map_inline:nn { i, ii, iii, iv, v } { \@@_tmp:n {#1} } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_list_arg_two_vii:, \@@_list_arg_two_viii:} % For the horizontal environments \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} % the implementation is similar, but, the value of |\partopsep| is always % \mydim{0pt}. At this point the \mykey[env]{parsep} key is modified to % make it take the value of the \mykey[env]{itemsep} key and later, in the % environment definition, \myhlc|\parindent| is modified to make it set % the value of \mykey[env]{listparindent} and \mykey{parsep} to set the value % of \myhlc|\parskip| locally. % % \begin{important}* % For compatibility with \emph{tagged} \texttt{PDF} and \hologo{LaTeX} % release 2026-06-01, |\setcounter| is moved to |\begin{list}|\mymarg{arg one}\mymarg{arg two}|\setcounter| % in the definition of the environments \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} (\S\ref{env:starred},~\S\ref{env:keyans-starred}). % This resolves the nesting problem reported by Tim Prescott (\texttt{@teepeemm}) in % \href{https://github.com/pablgonz/enumext/issues/5}{enumext* nested in enumext starts at 2 with DocumentMetadata} % this was caused by the \mypkg[no-index]{latex-lab-block}\cite{latexlab} update in this release. % \end{important} % % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:n { \cs_new_protected:cpn { @@_list_arg_two_ #1 : } { \bool_set_true:c { l_@@_leftmargin_tmp_ #1 _bool } \dim_zero:c { l_@@_leftmargin_tmp_ #1 _dim } \@@_calc_hspace:ccccccc { l_@@_labelwidth_ #1 _dim } { l_@@_labelsep_ #1 _dim } { l_@@_listoffset_ #1 _dim } { l_@@_leftmargin_tmp_ #1 _dim } { l_@@_leftmargin_ #1 _dim } { l_@@_itemindent_ #1 _dim } { l_@@_leftmargin_tmp_ #1 _bool } \clist_map_inline:nn { labelsep, labelwidth, itemindent, leftmargin, rightmargin, listparindent } { \dim_set_eq:cc {####1} { l_@@_####1 _ #1 _dim } } \clist_map_inline:nn { topsep, parsep, partopsep, itemsep } { \skip_set_eq:cc {####1} { l_@@_####1 _ #1 _skip } } \clist_map_inline:nn { beginparpenalty, itempenalty, endparpenalty } { \int_set_eq:cc {@####1} { l_@@_####1 _ #1 _int } } \skip_set_eq:Nc \parsep { l_@@_itemsep_ #1 _skip } \skip_zero:N \partopsep \usecounter { enumX #1 } % \setcounter { enumX #1 } % { \int_eval:n { \int_use:c { l_@@_start_ #1 _int } - 1 } } \@@_starred_ref: \str_if_eq:nnTF {#1} { vii } { \@@_fake_item_indent_vii: \bool_if:cT { l_@@_show_length_vii_bool } { \msg_term:nnnn { enumext } { list-lengths-not-nested } { vii } { enumext* } } } { \@@_fake_item_indent_viii: \bool_if:cT { l_@@_show_length_ #1 _bool } { \msg_term:nnnn { enumext } { list-lengths-not-nested } {#1} { keyans* } } } } } \clist_map_inline:nn { vii, viii } { \@@_tmp:n {#1} } % \end{macrocode} % \end{macro} % % \subsection{The environment \env{enumext}}\label{env:enumext} % % \subsubsection{Definition of variables for \env{enumext}} % % \begin{variable}[int]{\l_@@_store_upper_level_X_bool} % Internal variables used by the \emph{\enquote{storing structure}} of % the \myenv*[no-index]{enumext} environment when it is nested. % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:n { \bool_new:c { l_@@_store_upper_level_ #1 _bool } } \clist_map_inline:nn { i, ii, iii, iv, vii } { \@@_tmp:n {#1} } % \end{macrocode} % \end{variable} % % \subsubsection{Definition of error messages for \env{enumext}} % % \begin{macro}[int]{list-too-deep} % Message for the nesting depth of the environment \myenv*[no-index]{enumext}. % \begin{macrocode} \msg_new:nnnn { enumext } { list-too-deep } { Too~deep~nesting~for~'enumext'~\msg_line_context:. } { The~maximum~level~of~nesting~is~4. } % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions for \env{enumext}} % % \begin{macro}[int]{\@@_safe_exec:}\label{fun:safe-exec-enumext} % The \myhlc|\@@_safe_exec:| function first calls the function \myhlc|\@@_is_not_nested:| % which sets \myhlc|\g_@@_standard_bool| to |true| if it % is NOT nested within \myenv*[no-index]{enumext*}, then calls the function % \myhlc|\@@_internal_mini_page:| to create the environment \myhlc|\@@_mini_page|, % increments \myhlc|\l_@@_level_int| to restrict nesting of the % environment, sets \myhlc|\l_@@_standard_bool| to |true| and % finally calls the function \myhlc|\@@_is_on_first_level:| which sets % \myhlc|\l_@@_standard_first_bool| to |true| only if the % environment is NOT nested and is at the \emph{\enquote{first level}}. % \begin{macrocode} \cs_new_protected:Nn \@@_safe_exec: { \@@_is_not_nested: \@@_internal_mini_page: \int_incr:N \l_@@_level_int \int_compare:nNnT { \l_@@_level_int } > { 4 } { \msg_fatal:nn { enumext } { list-too-deep } } \bool_set_true:N \l_@@_standard_bool \bool_set_false:N \l_@@_starred_bool \@@_is_on_first_level: } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_parse_keys:n} % The \myhlc|\@@_parse_keys:n| function first clears the % variable \myhlc|\l_@@_series_name_str| used by the key \mykey[env]{series} and then % checks if it is at the \emph{\enquote{first level}}; if so, it % processes the \mymeta{keys} and then executes the function % \myhlc|\@@_parse_series:n| used by the key \mykey{series} and calls the % function \myhlc|\@@_nested_base_line_fix:| used by the key % \mykey[env]{base-fix}; otherwise it passes the \mymeta{keys} to the inner % levels of the environment, then executes the function \myhlc|\@@_store_active_keys:n| % and reprocesses the \mymeta{keys} to pass them to the \emph{sequence} % if the key \mykey[env]{save-key} is not active. % \begin{macrocode} \cs_new_protected:Nn \@@_parse_keys:n { \tl_if_novalue:nF {#1} { \str_clear:N \l_@@_series_name_str \int_compare:nNnTF { \l_@@_level_int } = { 1 } { \keys_set:nn { enumext / level-1 } {#1} \bool_if:NF \l_@@_print_keyans_cmd_bool { \@@_parse_series:n {#1} } \@@_nested_base_line_fix: } { \exp_args:Ne \keys_set:nn { enumext / level-\int_use:N \l_@@_level_int } {#1} \bool_if:NF \l_@@_print_keyans_cmd_bool { \@@_parse_series:n {#1} } } \@@_store_active_keys:n {#1} } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_start_store_level:} % The \myhlc|\@@_start_store_level:| function activates the \emph{\enquote{storing structure}} % mechanism in the \emph{sequence} for the command % |\anskey| and the environment \myenv*[no-index]{anskey*}. % \begin{macrocode} \cs_new_protected:Nn \@@_start_store_level: { \bool_lazy_all:nT { { \bool_if_p:N \l_@@_store_active_bool } { \bool_not_p:n { \l_@@_keyans_env_bool } } { \bool_if_p:N \g_@@_standard_bool } } { \int_compare:nNnT { \l_@@_level_int } > { 1 } { \bool_set_true:c { l_@@_store_upper_level_ \@@_level: _bool } \@@_store_level_open: } } % \end{macrocode} % If \myenv*[no-index]{enumext} are nested in \myenv*[no-index]{enumext*} add \myhlc|\@@_store_level_open:| % to preserve the \emph{\enquote{storing structure}}. % \begin{macrocode} \bool_lazy_all:nT { { \bool_if_p:N \l_@@_store_active_bool } { \bool_not_p:n { \l_@@_keyans_env_bool } } { \int_compare_p:nNn { \l_@@_level_h_int } = { 1 } } } { \int_compare:nNnT { \l_@@_level_int } > { 0 } { \bool_set_true:c { l_@@_store_upper_level_ \@@_level: _bool } \@@_store_level_open: } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_stop_store_level:} % The \myhlc|\@@_stop_store_level:| function stops the \emph{\enquote{storing structure}} % mechanism in the \emph{sequence} for the command % |\anskey| and the environment \myenv*[no-index]{anskey*}. % \begin{macrocode} \cs_new_protected:Nn \@@_stop_store_level: { \bool_if:cT { l_@@_store_upper_level_ \@@_level: _bool } { \@@_store_level_close: } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_multicols_start:} % The function \myhlc|\@@_multicols_start:| will start the % \myenv[no-index]{multicols} environment according to the value passed by the % \mykey[env]{columns} key, then set the default value for % |\columnsep| when \mykey[env]{columns-sep}=\mydim{0pt} and set the % value of |\multicolsep| equal to zero and leave |\columnseprule| % equal to zero for inner levels. % \begin{macrocode} \cs_new_protected:Nn \@@_multicols_start: { \int_compare:nNnT { \int_use:c { l_@@_columns_ \@@_level: _int } } > { 1 } { \dim_compare:nNnT { \dim_use:c { l_@@_columns_sep_ \@@_level: _dim } } = { \c_zero_dim } { \dim_set:cn { l_@@_columns_sep_ \@@_level: _dim } { ( \dim_use:c { l_@@_labelwidth_ \@@_level: _dim } + \dim_use:c { l_@@_labelsep_ \@@_level: _dim } ) / \int_use:c { l_@@_columns_ \@@_level: _int } - \dim_use:c { l_@@_listoffset_ \@@_level: _dim } } } \dim_set_eq:Nc \columnsep { l_@@_columns_sep_ \@@_level: _dim } \int_compare:nNnT { \l_@@_level_int } > { 1 } { \dim_zero:N \columnseprule } % \end{macrocode} % The \emph{vertical spacing} settings for the % \myenv[no-index]{multicols} environment are calculated using the function \myhlc|\@@_multi_addvspace:|, % the \emph{\enquote{vertical adjust spacing}} is applied, and then the % \myenv[no-index]{multicols} environment is started. % \begin{macrocode} \bool_if:cF { l_@@_minipage_active_ \@@_level: _bool } { \skip_zero:N \multicolsep \@@_multi_addvspace: } \raggedcolumns \begin{multicols}{ \int_use:c { l_@@_columns_ \@@_level: _int } } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_multicols_stop:} % The function \myhlc|\@@_multicols_stop:| will stop the \myenv[no-index]{multicols} % environment and apply the \emph{\enquote{vertical adjust}} spacing. When % the \mykey[env]{mini-env} key is active the space is not added here: % it is stored with \myhlc|\@@_mini_capture_multicols:| to be applied % by \myhlc|\@@_mini_apply_end:| after the environment on the % \emph{\enquote{right side}}. % For compatibility with \emph{tagged} \texttt{PDF}, the closing of the % \myenv[no-index]{list} environment is executed here along with \myhlc|\@@_stop_store_level:|. % \begin{macrocode} \cs_new_protected:Nn \@@_multicols_stop: { \int_compare:nNnTF { \int_use:c { l_@@_columns_ \@@_level: _int } } > { 1 } { \@@_stop_list: \@@_stop_store_level: \end{multicols} \@@_unskip_unkern: \@@_unskip_unkern: \par \bool_if:cTF { l_@@_minipage_active_ \@@_level: _bool } { \@@_mini_capture_multicols: } { \addvspace{ \skip_use:c { l_@@_multicols_below_ \@@_level: _skip } } } } { \@@_stop_list: \@@_stop_store_level: } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_before_list:} % The function \myhlc|\@@_before_list:| first calls the function % \myhlc|\@@_vspace_above:| used by the keys \mykey[env]{above} and % \mykey[env]{above*}, then calls the function \myhlc|\@@_before_args_exec:| % used by the key \mykey[env]{before*} and finally execute the function % \myhlc|\@@_check_ans_active:| for the check answer mechanism. % \begin{macrocode} \cs_new_protected:Nn \@@_before_list: { \@@_vspace_above: \@@_before_args_exec: \@@_check_ans_active: % \end{macrocode} % When the \mykey[env]{mini-env} key is active it will set the value of the % \myhlc|\l_@@_minipage_right_X_dim| to be the \emph{width} of the \myhlc|\@@_mini_page| % environment on the \emph{\enquote{right side}}, using this value together with the value % of the \myhlc|\l_@@_minipage_hsep_X_dim| set by the \mykey[env]{mini-sep} key, % the value of \myhlc|\l_@@_minipage_left_X_dim| will be set, which will be % the \emph{width} of \myhlc|\@@_mini_page| environment on the % \emph{\enquote{left side}}, always having a current |\linewidth| % as \emph{maximum width} between them. % \begin{macrocode} \dim_compare:nNnT { \dim_use:c { l_@@_minipage_right_ \@@_level: _dim } } > { \c_zero_dim } { \dim_set:cn { l_@@_minipage_left_ \@@_level: _dim } { \linewidth - \dim_use:c { l_@@_minipage_right_ \@@_level: _dim } - \dim_use:c { l_@@_minipage_hsep_ \@@_level: _dim } } % \end{macrocode} % The boolean variable \myhlc|\l_@@_minipage_active_X_bool| will be % activated and the integer variable \myhlc|\g_@@_minipage_stat_int| % used by the |\miniright| command will be incremented, then % the function \myhlc|\@@_minipage_add_space:| is called and the % \myhlc|\@@_mini_page| environment on the \emph{\enquote{left % side}} will be initialized followed by the \emph{\enquote{vertical spacing}} % applied to preserve the \emph{\enquote{baseline}} between the \emph{left} % and \emph{right} side environments. % After these actions, the function \myhlc|\@@_multicols_start:| is % called to handle the \myenv[no-index]{multicols} environment. % \begin{macrocode} \bool_set_true:c { l_@@_minipage_active_ \@@_level: _bool } \int_gincr:N \g_@@_minipage_stat_int \@@_minipage_add_space: \noindent \@@_mini_page{ \dim_use:c { l_@@_minipage_left_ \@@_level: _dim } } } \@@_multicols_start: } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_second_part:} % The function \myhlc|\@@_second_part:| first checks the state of % the boolean variable \myhlc|\l_@@_minipage_active_X_bool|; if it is % |true|, a small test is executed to check if the use of % |\miniright| was omitted (the \myhlc|\@@_mini_page| % environment has not been closed), then it closes \myhlc|\@@_mini_page| % and adds the stored \emph{adjusted vertical space} using \myhlc|\@@_mini_apply_end:|, % otherwise it closes the \myenv[no-index]{multicols} environment. % \begin{macrocode} \cs_new_protected:Nn \@@_second_part: { \bool_if:cTF { l_@@_minipage_active_ \@@_level: _bool } { \int_compare:nNnT { \g_@@_minipage_stat_int } = { 1 } { \msg_warning:nn { enumext } { missing-miniright } \miniright } \int_gzero:N \g_@@_minipage_stat_int \@@_unskip_unkern: % remove topsep + [partopsep] \end@@_mini_page \@@_mini_apply_end: } { \@@_multicols_stop: } % \end{macrocode} % Now the functions \myhlc|\@@_after_stop_list:| used by % the key \mykey[env,foreachkeyans]{after}, \myhlc|\@@_check_ans_key_hook:| used by the key % \mykey[env]{check-ans}, and \myhlc|\@@_vspace_below:| used by the keys \mykey[env]{below} % and \mykey[env]{below*} are executed. Finally it sets \myhlc|\l_@@_standard_bool| to false and calls % the function \myhlc|\@@_standard_save_counter:| used by the \mykey[env]{series}, % \mykey[env]{resume} and \mykey[env]{resume*} keys. % \begin{macrocode} \@@_after_stop_list: \@@_check_ans_key_hook: \@@_vspace_below: \bool_set_false:N \l_@@_standard_bool \bool_if:NF \l_@@_print_keyans_cmd_bool { \@@_standard_save_counter: } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_set_item_width:}\label{fun:item-width-enumext} % The function \myhlc|\@@_set_item_width:| will set the value of |\itemwidth| % taking into account the value established by the \mykey[env]{list-offset} % key for each level of the environment. % \begin{macrocode} \cs_new_protected:Nn \@@_set_item_width: { \dim_set:Nn \itemwidth { \linewidth } \dim_compare:nT { \dim_use:c { l_@@_listoffset_ \@@_level: _dim } != \c_zero_dim } { \dim_sub:Nn \itemwidth { \dim_use:c { l_@@_listoffset_ \@@_level: _dim } } } } % \end{macrocode} % \end{macro} % % \begin{macro}{enumext} % Now create the \myenv*{enumext} environment based on \myenv[no-index]{list} % environment by levels. It accepts an optional \myoarg{key \textnormal{\textcolor{gray}{=}} val} argument % in `|#1|'. It first checks where the environment is running % (\S\ref{fun:safe-exec-enumext}) and processes the \mymeta{keys}. Then it % applies the vertical space and the code of the keys \mykey[env]{above} and % \mykey[env]{before*}, activates the \emph{\enquote{storing structure}} and opens % the list with the label of the current level. Finally it sets |\itemwidth| % (\S\ref{fun:item-width-enumext}) and executes the code set by the key % \mykey[env]{first}. % \begin{macrocode} \NewDocumentEnvironment{enumext}{ O{} } { \@@_safe_exec: \@@_parse_keys:n {#1} \@@_before_list: \@@_start_store_level: \@@_start_list:nn { \tl_use:c { l_@@_label_ \@@_level: _tl } } { \use:c { @@_list_arg_two_ \@@_level: : } \@@_before_keys_exec: } \@@_set_item_width: \@@_after_args_exec: } { \@@_second_part: } % \end{macrocode} % \end{macro} % % Since the \mykey{check-ans} check must not be executed by levels % but on the complete list, it is taken out of the \myenv*[no-index]{enumext} % environment using the \emph{\enquote{hook}} function \myhlc|\@@_after_env:nn|. % \begin{macrocode} \@@_after_env:nn {enumext} { \@@_execute_after_env: } % \end{macrocode} % % \subsection{The environment \env{keyans}}\label{env:keyans} % % The environment \myenv*[no-index]{keyans} also based on lists. % The main differences with the \myenv*[no-index]{enumext} environment are the % \emph{nesting} and the way the \emph{answers} (choice) will be stored and checked, this % environment is intended exclusively for \emph{\enquote{multiple choice questions}}. % % \subsubsection{Definition of error messages for \env{keyans}} % % \begin{macro}[int]{keyans-nested} % Message used by \myenv*[no-index]{keyans} environment. % \begin{macrocode} \msg_new:nnnn { enumext } { keyans-nested } { The~environment~'keyans'~can't~be~nested~\msg_line_context:. } { Close~the~first~'keyans'~environment~before~starting~ another~one. } % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions for \env{keyans}} % % \begin{macro}[int]{\@@_keyans_safe_exec:} % The \myenv*[no-index]{keyans} environment will only be available if the % \mykey[env]{save-ans} key is active and can only be used at the % \emph{\enquote{first level}} within the \myenv*[no-index]{enumext} environment. % The environment must not be nested, so a maximum is set at this point. % If the conditions are not met, an error message is returned. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_safe_exec: { \bool_lazy_or:nnF { \l_@@_store_active_bool } { \@@_in_keyans_p: } { \msg_error:nnnn { enumext } { wrong-place }{ keyans }{ save-ans } } \int_incr:N \l_@@_keyans_level_int \bool_set_true:N \l_@@_keyans_env_bool \@@_keyans_name_and_start: % Set false for interfering with enumext nested in keyans % (yes, its possible and crayze) \bool_set_false:N \l_@@_store_active_bool \int_compare:nNnT { \l_@@_keyans_level_int } > { 1 } { \msg_error:nn { enumext } { keyans-nested } } \int_compare:nNnT { \l_@@_level_int } > { 1 } { \msg_error:nn { enumext } { keyans-wrong-level } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_keyans_parse_keys:n} % Parse \myoarg{key \textnormal{\textcolor{gray}{=}} val} for % \myenv*[no-index]{keyans} environment. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_parse_keys:n { \keys_set:nn { enumext / keyans } {#1} } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_before_list_v:, \@@_keyans_multicols_start:, % \@@_keyans_multicols_stop:, \@@_second_part_v:} % Same implementation as the one used in the \myenv*[no-index]{enumext} environment. % \begin{macrocode} \cs_new_protected:Nn \@@_before_list_v: { \@@_vspace_above_v: \@@_before_args_exec_v: \dim_compare:nNnT { \l_@@_minipage_right_v_dim } > { \c_zero_dim } { \dim_set:Nn \l_@@_minipage_left_v_dim { \linewidth - \l_@@_minipage_right_v_dim - \l_@@_minipage_hsep_v_dim } \bool_set_true:N \l_@@_minipage_active_v_bool \int_gincr:N \g_@@_minipage_stat_int \@@_keyans_minipage_add_space: \@@_mini_page{ \l_@@_minipage_left_v_dim } } \@@_keyans_multicols_start: } \cs_new_protected:Nn \@@_keyans_multicols_start: { \int_compare:nNnT { \l_@@_columns_v_int } > { 1 } { \dim_compare:nNnT { \l_@@_columns_sep_v_dim } = { \c_zero_dim } { \dim_set:Nn \l_@@_columns_sep_v_dim { ( \l_@@_labelwidth_v_dim + \l_@@_labelsep_v_dim ) / \l_@@_columns_v_int - \l_@@_listoffset_v_dim } } \dim_set_eq:NN \columnsep \l_@@_columns_sep_v_dim \dim_zero:N \columnseprule % no rule here \bool_if:NF \l_@@_minipage_active_v_bool { \skip_zero:N \multicolsep \@@_keyans_multi_addvspace: } \raggedcolumns \begin{multicols}{ \l_@@_columns_v_int } } } \cs_new_protected:Nn \@@_keyans_multicols_stop: { \int_compare:nNnTF { \l_@@_columns_v_int } > { 1 } { \@@_stop_list: \end{multicols} \@@_unskip_unkern: \@@_unskip_unkern: \par \bool_if:NTF \l_@@_minipage_active_v_bool { \@@_mini_capture_multicols: } { \addvspace{ \l_@@_multicols_below_v_skip } } } { \@@_stop_list: } } \cs_new_protected:Nn \@@_second_part_v: { \bool_if:NTF \l_@@_minipage_active_v_bool { \int_compare:nNnT { \g_@@_minipage_stat_int } = { 1 } { \msg_warning:nn { enumext } { missing-miniright } \miniright } \int_gzero:N \g_@@_minipage_stat_int \@@_unskip_unkern: % remove \topsep + [\partopsep] \end@@_mini_page \@@_mini_apply_end: } { \@@_keyans_multicols_stop: } \bool_set_false:N \l_@@_keyans_env_bool \@@_after_stop_list_v: \@@_vspace_below_v: } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_keyans_set_item_width:}\label{fun:item-width-keyans} % The function \myhlc|\@@_keyans_set_item_width:| will set the value of |\itemwidth| % taking into account the value established by the \mykey[env]{list-offset} % key. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_set_item_width: { \dim_set:Nn \itemwidth { \linewidth } \dim_compare:nT { \l_@@_listoffset_v_dim != \c_zero_dim } { \dim_sub:Nn \itemwidth { \l_@@_listoffset_v_dim } } } % \end{macrocode} % \end{macro} % % \begin{macro}{keyans} % Defines the environment \myenv*{keyans}, also based on lists. It accepts an % optional \myoarg{key \textnormal{\textcolor{gray}{=}} val} argument in `|#1|'. It first checks that the environment is % available and where it is running, and processes the \mymeta{keys}. Then it opens % the list, sets |\itemwidth| (\S\ref{fun:item-width-keyans}) and executes the % code set by the key \mykey[env]{first}. In the second part it checks the use % of |\item*| and finishes the environment. % \begin{macrocode} \NewDocumentEnvironment{keyans}{ O{} } { \@@_keyans_safe_exec: \@@_keyans_parse_keys:n {#1} \@@_before_list_v: \@@_start_list:nn { \tl_use:N \l_@@_label_v_tl } { \@@_list_arg_two_v: \@@_before_keys_exec_v: } \@@_keyans_set_item_width: \@@_after_args_exec_v: } { \@@_check_starred_cmd:n { item } \@@_second_part_v: } % \end{macrocode} % \end{macro} % % \subsection{Tagging PDF support for non-standard list environments}\label{subsec:tag-nonstandard-list} % % The \hologo{LaTeX} release 2022-06-01 brings automatic support for % \emph{tagged} \texttt{PDF} in several aspects, including the standard % \emph{list environments} and the \myenv[no-index]{list} environment. Unfortunately % non-standard \emph{list environments} like \myenv*[no-index]{keyanspic} or the % horizontal list environments \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} are % not structured in a nice way, i.e. the visual result in the \texttt{PDF} % file is the expected one, but the underlying structure is not correct. In % simple terms, for \emph{tagged} \texttt{PDF} a \myenv[no-index]{list} environment % is a \myenv[no-index]{list} environment, no matter what it looks like in the \texttt{PDF} file. % % To maintain a correct \myenv[no-index]{list} structure when \myhlc|\DocumentMetadata| is % active, it is necessary to do some things manually using % \mypkg{tagpdf}\cite{tagpdf} and \mypkg{ltsockets}\cite{ltsockets}. % This implementation is an adaptation of the answer given by the author % of this package thanks to Ulrike Fischer's comments in \href{https://tex.stackexchange.com/a/725902}{How can I modify my \texttt{\textbackslash item} redefinition to be compatible with \texttt{tagging-pdf}}. % % \subsubsection{Socket for tagging support in \env{enumext*} and \env{keyans*}} % % \begin{macro}[int]{start-list-tags, stop-start-tags, stop-list-tags, % stop-list-tags-par, \@@_start_list_tag:n, % \@@_stop_start_list_tag:, \@@_stop_list_tag:n, % \@@_stop_item_break_tag:n, \@@_stop_start_break_tag:, % stop-start-tags-break, stop-list-tags-break} % First, the necessary \texttt{sockets} and their % behavior are defined for \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*}. % \begin{macrocode} \socket_new:nn {tagsupport/@@/starred}{ 1 } \socket_new_plug:nnn {tagsupport/@@/starred} {start-list-tags} { \tag_resume:n {#1} \tag_struct_begin:n {tag=LI} \tag_struct_begin:n {tag=Lbl} \tag_mc_begin:n {tag=Lbl} } \socket_new_plug:nnn {tagsupport/@@/starred} {stop-start-tags} { \tag_mc_end: \tag_struct_end:n {tag=Lbl} \tag_struct_begin:n {tag=LBody} % {tag=text-unit} now "semantic-para" % (https://github.com/latex3/latex2e/commit/83f054afc042e82a664085b6f2fd7c8d61705fb9) \tag_struct_begin:n {tag=semantic-para} % {tag=text} now "text-block" \tag_struct_begin:n {tag=text-block} } \socket_new_plug:nnn {tagsupport/@@/starred} {stop-list-tags} { \tag_struct_end:n {tag=text-block} \tag_struct_end:n {tag=semantic-para} % {tag=text-unit} \tag_struct_end:n {tag=LBody} \tag_struct_end:n {tag=LI} \tag_suspend:n {#1} } \socket_new_plug:nnn {tagsupport/@@/starred} {stop-list-tags-par} { \tag_struct_end:n {tag=LBody} \tag_struct_end:n {tag=LI} \tag_suspend:n {#1} } \socket_new_plug:nnn {tagsupport/@@/starred} {stop-start-tags-break} { \tag_mc_end: \tag_struct_end:n {tag=Lbl} \tag_struct_begin:n {tag=LBody} \tag_socket_use:nn {para/semantic/begin} { } \tag_socket_use:nn {para/textblock/begin} { } } \socket_new_plug:nnn {tagsupport/@@/starred} {stop-list-tags-break} { \tag_socket_use:n {para/textblock/end} \tag_socket_use:nn {para/semantic/end} { } \tag_struct_end:n {tag=LBody} \tag_struct_end:n {tag=LI} \tag_suspend:n {#1} } % \end{macrocode} % % And now they are wrapped so that they are only active when \myhlc|\DocumentMetadata| is present. % \begin{macrocode} \cs_new_protected_nopar:Nn \@@_start_list_tag:n { \IfDocumentMetadataT { \socket_assign_plug:nn {tagsupport/@@/starred} {start-list-tags} \socket_use:nn {tagsupport/@@/starred} {#1} } } \cs_new_protected_nopar:Nn \@@_stop_start_list_tag: { \IfDocumentMetadataT { \socket_assign_plug:nn {tagsupport/@@/starred} {stop-start-tags} \socket_use:nn {tagsupport/@@/starred} { } } } \cs_new_protected_nopar:Nn \@@_stop_start_break_tag: { \IfDocumentMetadataT { \socket_assign_plug:nn {tagsupport/@@/starred} {stop-start-tags-break} \socket_use:nn {tagsupport/@@/starred} { } } } \cs_new_protected_nopar:Nn \@@_stop_list_tag:n { \IfDocumentMetadataT { \socket_assign_plug:nn {tagsupport/@@/starred} {stop-list-tags} \socket_use:nn {tagsupport/@@/starred} {#1} } } % \end{macrocode} % % The items of \mykey[env]{item-break} have no \myenv[no-index]{minipage}, so the % paragraphs of the \mymeta{content} are tagged by the \emph{paragraph hooks}. % The first paragraph of the item is opened while the tagging is still % suspended, because the label is placed before the structures of the % \mymeta{content} are started, so its \emph{begin} hook is never executed. % For this reason, the plug \texttt{stop-start-tags-break} (used by % \myhlc|\@@_stop_start_break_tag:|) opens the structures of that paragraph % using the sockets \texttt{para/semantic/begin} and % \texttt{para/textblock/begin} of the \hologo{LaTeX} kernel. These % sockets also take care of the counters of the \emph{paragraph hooks}, the % names of the tags and the class of the \texttt{Layout} attribute % \texttt{TextAlign}. % If the last paragraph of the item has already been ended by a \myhlc|\par|, % coming from an empty line before the next \myhlc|\item| or before \myhlc|\end| % or from a \myhlc|\par| inside a group, the hook has closed the % \texttt{text-block} and \texttt{semantic-para} structures and the marked % content, and we are in \emph{vertical mode}. Then only \texttt{LBody} and % \texttt{LI} remain to be closed, using the plug \texttt{stop-list-tags-par}. % When the item ends with a standard list (\myenv[no-index]{itemize}, % for example) we are also in \emph{vertical mode}, but the % \texttt{semantic-para} that contains the list is still open, because the % kernel closes it with the |\par| that ends the paragraph \emph{continued} % after the list. For this reason a |\par| is executed first in vertical mode: % it closes that structure, and if there is nothing pending it does nothing. % Otherwise the paragraph is still open and the plug % \texttt{stop-list-tags-break} closes it with the sockets % \texttt{para/textblock/end} and \texttt{para/semantic/end}, before the % \myhlc|\par| that ends the item. That \myhlc|\par| runs with the tagging % suspended and is not counted. % \begin{macrocode} \cs_new_protected_nopar:Nn \@@_stop_item_break_tag:n { \IfDocumentMetadataT { \mode_if_vertical:TF { \par \socket_assign_plug:nn {tagsupport/@@/starred} {stop-list-tags-par} } { \socket_assign_plug:nn {tagsupport/@@/starred} {stop-list-tags-break} } \socket_use:nn {tagsupport/@@/starred} {#1} } } % \end{macrocode} % \end{macro} % % \subsubsection{Socket for tagging support in \env{keyanspic}} % % \begin{macro}[int]{start-list-tags, stop-start-tags, stop-list-tags, % \@@_anspic_start_list_tag:, \@@_anspic_stop_start_list_tag:, % \@@_anspic_stop_list_tag:} % First, the necessary \texttt{sockets} and their % behavior are defined for the \myenv*[no-index]{keyanspic} environment. % \begin{macrocode} \socket_new:nn {tagsupport/@@/keyanspic}{ 0 } \socket_new_plug:nnn {tagsupport/@@/keyanspic} {start-list-tags} { \tag_resume:n {keyanspic} \tag_struct_begin:n {tag=LI} \tag_struct_begin:n {tag=Lbl} \tag_mc_begin:n {tag=Lbl} } \socket_new_plug:nnn {tagsupport/@@/keyanspic} {stop-start-tags} { \tag_mc_end: \tag_struct_end:n {tag=Lbl} \tag_struct_begin:n {tag=LBody} \tag_struct_begin:n {tag=semantic-para} \tag_struct_begin:n {tag=text-block} \tag_mc_begin:n {tag=text-block} } \socket_new_plug:nnn {tagsupport/@@/keyanspic} {stop-list-tags} { \tag_mc_end: \tag_struct_end:n {tag=text-block} \tag_struct_end:n {tag=semantic-para} \tag_struct_end:n {tag=LBody} \tag_struct_end:n {tag=LI} \tag_suspend:n {keyanspic} } % \end{macrocode} % And now they are wrapped so that they are only active when % \myhlc|\DocumentMetadata| is present. % \begin{macrocode} \cs_new_protected_nopar:Nn \@@_anspic_start_list_tag: { \IfDocumentMetadataT { \socket_assign_plug:nn {tagsupport/@@/keyanspic} {start-list-tags} \socket_use:n {tagsupport/@@/keyanspic} } } \cs_new_protected_nopar:Nn \@@_anspic_stop_start_list_tag: { \IfDocumentMetadataT { \socket_assign_plug:nn {tagsupport/@@/keyanspic} {stop-start-tags} \socket_use:n {tagsupport/@@/keyanspic} } } \cs_new_protected_nopar:Nn \@@_anspic_stop_list_tag: { \IfDocumentMetadataT { \socket_assign_plug:nn {tagsupport/@@/keyanspic} {stop-list-tags} \socket_use:n {tagsupport/@@/keyanspic} } } % \end{macrocode} % \end{macro} % % \subsection{The environment \env{keyanspic} and \cs{anspic}}\label{subsec:keyanspic-anspic} % % The \myenv*[no-index]{keyanspic} environment is a \myenv[no-index]{list} based environment that % uses the same configuration for \emph{\enquote{spacing}} and \mymeta{label} % as the \myenv*[no-index]{keyans} environment, but it does not use |\item|. % The \mymeta{contents} are passed to the environment by means of the % |\anspic| command as replacement for |\item| command and placed % inside \myenv[no-index]{minipage} environments, with the \mymeta{label} % centered \emph{\enquote{above}} or \emph{\enquote{below}}, adjusting % \emph{widths} and \emph{position} according to the options passed to % the environment. % % \begin{figure}[ht] % \centering % \begin{tikzpicture}[line cap=round,line join=round,x=0.8cm,y=0.8cm,every node/.style={font=\footnotesize}] % % space above % \draw[color=white] (7.0,6.10) rectangle (17.5,6.5) node[pos=.5,text=black]% % { \mykey{layout-top} }; % % space between % \draw[color=white] (7.0,4.5) rectangle (17.5,4.9) node[pos=.5,text=black]% % { \mykey{layout-sep} }; % % space below % \draw[color=white] (7.0,2.9) rectangle (17.5,3.3) node[pos=.5,text=black]% % { \mykey{layout-top} }; % % labelwidth % \draw[<->,color=gray] (2.0,7.0) --node[above,text=keyname]{\vphantom{p}\texttt{labelwidth}} (5.0,7.0); % \draw[<->,color=gray] (5.0,7.0) --node[above,text=keyname]{\texttt{labelsep}} (7.0,7.0); % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (2.0,6.5) rectangle (5.0,6.85);% labelwidth % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (5.0,6.5) rectangle (7.0,6.85);% labelsep % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,6.5) rectangle (17.5,6.85);% item width % % minipage one % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,5.25) rectangle (10.5,6.10) node[pos=.5,text=black]% % {\begin{tabular}{c} % \texttt{minipage one} \\ % \textcolor{blue}{\emph{drawing or tabular}} % \end{tabular}}; % % label one % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,4.9) rectangle (10.5,5.25) node[pos=.5,text=black]% % { \textcolor{blue}{\texttt{label}} }; % % minipage two % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (10.5,5.25) rectangle (14,6.10) node[pos=.5,text=black]% % {\begin{tabular}{c} % \texttt{minipage two} \\ % \textcolor{blue}{\emph{drawing or tabular}} % \end{tabular}}; % % label two % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (10.5,4.9) rectangle (14,5.25) node[pos=.5,text=black]% % { \textcolor{blue}{\texttt{label}} }; % % minipage three % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (14,5.25) rectangle (17.5,6.10) node[pos=.5,text=black]% % {\begin{tabular}{c} % \texttt{minipage three} \\ % \textcolor{blue}{\emph{drawing or tabular}} % \end{tabular}}; % % label three % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (14,4.9) rectangle (17.5,5.25) node[pos=.5,text=black]% % { \textcolor{blue}{\texttt{label}} }; % % minipage four % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,3.65) rectangle (12.25,4.5) node[pos=.5,text=black]% % {\begin{tabular}{c} % \texttt{minipage four} \\ % \textcolor{blue}{\emph{drawing or tabular}} % \end{tabular}}; % % label four % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,3.3) rectangle (12.25,3.65) node[pos=.5,text=black]% % { \textcolor{blue}{\texttt{label}} }; % % minipage five % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (12.25,3.65) rectangle (17.5,4.5) node[pos=.5,text=black]% % {\begin{tabular}{c} % \texttt{minipage five} \\ % \textcolor{blue}{\emph{drawing or tabular}} % \end{tabular}}; % % label five % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (12.25,3.3) rectangle (17.5,3.65) node[pos=.5,text=black]% % { \textcolor{blue}{\texttt{label}} }; % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (2.0,2.55) rectangle (5.0,2.9);% labelwidth % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (5.0,2.55) rectangle (7.0,2.9);% labelsep % \draw[color=lightgray,fill=lightgray,fill opacity=0.15] (7.0,2.55) rectangle (17.5,2.9);% item width % \end{tikzpicture} % \caption{Representation of the \myenv*{keyanspic} spacing in \mypkg*[no-index]{enumext}.} % \label{fig:keyanspic} % \end{figure} % % In order for the \myenv*[no-index]{keyanspic} environment and the |\anspic| % command to work correctly, some variables must be set and exported in % the first part of the environment definition and pass them to |\anspic| % which is executed in the second part of the environment. This % implementation is adapted from the answer given by Enrico Gregorio % (\texttt{@egreg}) in \href{https://tex.stackexchange.com/a/577705/7832}{How to process the body of an environment and divide it by a \textbackslash macro?}. % % \subsubsection{Definition of variables for \env{keyanspic} and \cs[no-index]{anspic}} % % \begin{variable}[int]{ % \l_@@_anspic_args_seq, % \l_@@_anspic_mini_width_dim, % \l_@@_anspic_above_int, % \l_@@_anspic_below_int, % \l_@@_anspic_label_above_bool, % \l_@@_anspic_mini_pos_str, % \l_@@_anspic_label_box, % \l_@@_anspic_body_box, % \l_@@_anspic_label_htdp_dim, % \l_@@_anspic_body_htdp_dim, % } % Internal variables used by \myenv*[no-index]{keyanspic} environment and % \ics*{anspic} command (\S\ref{env:keyanspic}). % \begin{macrocode} \seq_new:N \l_@@_anspic_args_seq \dim_new:N \l_@@_anspic_mini_width_dim \int_new:N \l_@@_anspic_above_int \int_new:N \l_@@_anspic_below_int \bool_new:N \l_@@_anspic_label_above_bool \str_new:N \l_@@_anspic_mini_pos_str \box_new:N \l_@@_anspic_label_box \box_new:N \l_@@_anspic_body_box \dim_new:N \l_@@_anspic_label_htdp_dim \dim_new:N \l_@@_anspic_body_htdp_dim % \end{macrocode} % \end{variable} % % \subsubsection{Definition of error messages for \env{keyanspic}} % % \begin{macro}[int]{keyanspic-nested, keyanspic-wrong-level, % keyanspic-item-cmd} % Messages used by \myenv*[no-index]{keyanspic} environment. % \begin{macrocode} \msg_new:nnnn { enumext } { keyanspic-nested } { The~environment~'keyanspic'~can't~be~nested~\msg_line_context:. } { Close~the~first~'keyanspic'~environment~before~starting~ another~one. } \msg_new:nnnn { enumext } { keyanspic-wrong-level } { Wrong~level~position~for~'keyanspic'~\msg_line_context:. } { The~environment~'keyanspic'~can~only~be~in~the~first~level. } \msg_new:nnnn { enumext } { keyanspic-item-cmd } { Can't~use~'\token_to_str:N \item'~in~'keyanspic'~\msg_line_context:. } { Remove~'\token_to_str:N \item'~from~the~'keyanspic'~environment. } % \end{macrocode} % \end{macro} % % \subsubsection{The environment \env{keyanspic}}\label{env:keyanspic} % % \begin{macro}[int]{label-pos, label-sep, layout-sty, layout-sep, % layout-top, mark-ans, mark-pos, mark-sep, save-sep, % wrap-opt, wrap-ans*, show-ans, show-pos, unknown} % First the keys are defined. The position of the % \mymeta{label} centered \enquote{above} or \enquote{below} is handled by \mykey[env]{label-pos}, % and its vertical separation from the \emph{drawing or tabular} by the key % \mykey[env]{label-sep}. % The \emph{\enquote{layout style}} is handled by the key % \mykey[env]{layout-sty}, which takes two values separated by comma \mymarg{n° % upper, n° lower} and determines the number of \myenv[no-index]{minipage} % environments in which all arguments of |\anspic| are printed at the % \enquote{upper} and \enquote{lower} within the environments separated % by the value of the key \mykey[env]{layout-sep}. The vertical space % \enquote{top} and \enquote{bottom} of the environment is handled % by the key \mykey[env]{layout-top}. % \begin{macrocode} \keys_define:nn { enumext / keyanspic } { label-pos .choices:nn = { above , below } { \int_case:nn { \l_keys_choice_int } { {1} { \bool_set_true:N \l_@@_anspic_label_above_bool \str_set:Nn \l_@@_anspic_mini_pos_str { t } } {2} { \bool_set_false:N \l_@@_anspic_label_above_bool \str_set:Nn \l_@@_anspic_mini_pos_str { b } } } }, label-pos .initial:n = below, label-pos .value_required:n = true, label-pos / unknown .code:n = \msg_error:nneee { enumext } { unknown-choice } { label-pos } { above,~ below } { \exp_not:n {#1} }, label-sep .skip_set:N = \l_@@_anspic_label_sep_skip, label-sep .value_required:n = true, layout-sty .tl_set:N = \l_@@_anspic_layout_style_tl, layout-sty .value_required:n = true, layout-sep .meta:nn = { enumext / keyans } { parsep = {#1} }, layout-sep .value_required:n = true, layout-top .meta:nn = { enumext / keyans } { topsep = {#1} }, layout-top .value_required:n = true, mark-ans .meta:nn = { enumext / keyans } { mark-ans = {#1} }, mark-ans .value_required:n = true, mark-pos .meta:nn = { enumext / keyans } { mark-pos = {#1} }, mark-pos .value_required:n = true, mark-sep .meta:nn = { enumext / keyans } { mark-sep = {#1} }, mark-sep .value_required:n = true, save-sep .meta:nn = { enumext / keyans } { save-sep = {#1} }, save-sep .value_required:n = true, wrap-opt .meta:nn = { enumext / keyans } { wrap-opt = {#1} }, wrap-opt .value_required:n = true, wrap-ans* .meta:nn = { enumext / keyans } { wrap-ans* = {#1} }, wrap-ans* .value_required:n = true, show-ans .meta:nn = { enumext / keyans } { show-ans = {#1} }, show-ans .value_required:n = true, show-pos .meta:nn = { enumext / keyans } { show-pos = {#1} }, show-pos .value_required:n = true, unknown .code:n = { \tl_set:Ne \l_@@_envir_name_tl { keyanspic } \@@_keyans_unknown_keys:n {#1} }, } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_keyans_pic_safe_exec:, \@@_keyans_pic_parse_keys:n, % \@@_keyans_pic_skip_abs:N, \@@_keyans_pic_arg_two:} % The function \myhlc|\@@_keyans_pic_safe_exec:| check the nested level % position inside the \myenv*[no-index]{enumext} environment. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_pic_safe_exec: { \int_incr:N \l_@@_keyans_pic_level_int \int_compare:nNnT { \l_@@_keyans_pic_level_int } > { 1 } { \msg_error:nn { enumext } { keyanspic-nested } } \@@_keyans_name_and_start: } % \end{macrocode} % Parse \myoarg{key \textnormal{\textcolor{gray}{=}} val} for % \myenv*[no-index]{keyanspic} environment. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_pic_parse_keys:n { \tl_if_novalue:nF {#1} { \keys_set:nn { enumext / keyanspic } {#1} } } % \end{macrocode} % The function \myhlc|\@@_keyans_pic_skip_abs:N| will return a positive % value |\parsep| from \myenv*[no-index]{keyans} environment. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_pic_skip_abs:N { \dim_compare:nNnT {#1} < { \c_zero_dim } { \skip_set:Nn #1 { -#1 } } } % \end{macrocode} % The \myhlc|\@@_keyans_pic_arg_two:| function is used in the % \emph{second argument} of the \myenv[no-index]{list} environment that defines % the \myenv*[no-index]{keyanspic} environment, taking the % configuration of the \emph{\enquote{spaces}} and the keys % \mykey[env]{label}, \mykey[env]{wrap-label}, \mykey[env]{parsep} and \mykey[env]{topsep} % from the \myenv*[no-index]{keyans} environment. % The first step is to set the boolean variable % \myhlc|\l_@@_leftmargin_tmp_v_bool| handled by the \mykey[env]{list-indent} key % to |false|, then copy the definition of the second list argument % from the \myenv*[no-index]{keyans} environment definition and make sure that % |\parsep| does not have a negative value. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_pic_arg_two: { \bool_set_false:N \l_@@_leftmargin_tmp_v_bool \@@_list_arg_two_v: \@@_keyans_pic_skip_abs:N \parsep % \end{macrocode} % Now the counter |enumXv| of the \myenv*[no-index]{keyans} environment is incremented % and the \emph{total height} of the \mymeta{label} is saved in % \myhlc|\l_@@_anspic_label_htdp_dim| used by |\anspic|, and the % values of |\parsep| are adjusted only if the key \mykey[env]{label-pos} is set to \emph{below}. % \begin{macrocode} \bool_if:NF \l_@@_anspic_label_above_bool { \stepcounter { enumXv } \hbox_set:Nn \l_@@_anspic_label_box { \l_@@_label_v_tl } \dim_set:Nn \l_@@_anspic_label_htdp_dim { \box_ht_plus_dp:N \l_@@_anspic_label_box } \skip_add:Nn \parsep { \l_@@_anspic_label_htdp_dim + \box_dp:N \strutbox + \l_@@_anspic_label_sep_skip } } % \end{macrocode} % Finally the value of |\leftmargin| and |\topsep| is \emph{adjusted}, % then |\listparindent|, |\partopsep| and |\itemsep| are set to zero so that % the \emph{horizontal} and \emph{vertical} space is not affected. % \begin{macrocode} \dim_add:Nn \leftmargin { -\l_@@_labelwidth_v_dim - \l_@@_labelsep_v_dim } \ignorespaces \skip_add:Nn \topsep { 0.5\box_dp:N \strutbox } \dim_zero:N \listparindent \skip_zero:N \partopsep \skip_zero:N \itemsep } % \end{macrocode} % \end{macro} % % \begin{macro}{keyanspic} % Defines the environment \myenv*{keyanspic}. It accepts an optional \myoarg{key \textnormal{\textcolor{gray}{=}} val} % argument in `|#1|' that is processed after checking the nested level. For compatibility % with \emph{tagged} \texttt{PDF} the |\begin{|\myenv[no-index]{list}|}| % form must be used, along with a lot of conditional code using \myhlc|\IfDocumentMetadataTF|. % First, the code for automatic \emph{tagged} \texttt{PDF} % for \myenv[no-index]{list} environments is stopped, |\item| is redefined so that it cannot be % used, and the code for automatic \emph{tagged} \texttt{PDF} is stopped for % the \myenv*[no-index]{keyanspic} environment. % \begin{macrocode} \NewDocumentEnvironment{keyanspic}{ o } { \@@_keyans_pic_safe_exec: \@@_keyans_pic_parse_keys:n {#1} \begin{list} { } { \@@_keyans_pic_arg_two: } \IfDocumentMetadataT { \tag_suspend:n {list} } \item[] \scan_stop: \RenewDocumentCommand \item {} { \msg_error:nn { enumext } { keyanspic-item-cmd } } \IfDocumentMetadataT { \tag_resume:n {keyanspic} \tag_socket_use:n { para/off } \tag_suspend:n {keyanspic} } } % \end{macrocode} % In the second part of the environment definition, the code for % \emph{tagged} \texttt{PDF} is placed manually and the command is executed: % |\anspic| is run using the \myhlc|\@@_anspic_exec:| function. % \begin{macrocode} { \IfDocumentMetadataT { \tag_resume:n {keyanspic} } \@@_anspic_exec: \IfDocumentMetadataT { \tag_suspend:n {keyanspic} } \end{list} \IfDocumentMetadataT { \tag_struct_end:n {tag=L} } % \end{macrocode} % Finally it checks if |\anspic*| has been used, sets the counter |enumXvi| % to zero and applies the \enquote{adjusted} vertical space at the bottom. % \begin{macrocode} \@@_check_starred_cmd:n { anspic } \setcounter { enumXvi } { 0 } \bool_if:NTF \l_@@_anspic_label_above_bool { \par\addvspace{ 0.5\box_dp:N \strutbox } } { \par \addvspace { \dim_eval:n { \l_@@_anspic_label_htdp_dim + \box_ht_plus_dp:N \strutbox + \l_@@_anspic_label_sep_skip + \l_@@_topsep_v_skip } } } } % \end{macrocode} % \end{macro} % % \subsubsection{The command \cs{anspic}}\label{cmd:anspic} % The |\anspic| command takes three arguments, the \emph{starred versions} |\anspic*|\myoarg{content} % \emph{store} the current \mymeta{label} next to the \emph{optional argument} % \myoarg{content} in the \emph{sequence} and \emph{prop list} % defined by \mykey{save-ans} key. The third \emph{mandatory argument} % \mymarg{drawing or tabular} is NOT \emph{stored} in the \emph{sequence} or % \emph{prop list}. % % \begin{important} % One of the complications here to make the \myenv*[no-index]{keyanspic} % environment compatible with \emph{tagged} PDF is the position of % \mymeta{label}, the |\anspic| command processes the arguments in % order, where `|#1|' and `|#2|' correspond to \mymeta{label} and `|#3|' to the % mandatory argument and puts all this inside a \myenv[no-index]{minipage} % environment. If `|#1|' and `|#2|', that is \mymeta{label}, is above `|#3|' % there are no problems with \emph{tagged} PDF, but if `|#3|' comes first % the list created with \emph{tagged} PDF will not be correct. % \end{important} % % \begin{macro}[int]{\@@_anspic_body_dim:n, \@@_anspic_label:nn, % \@@_anspic_label_pos:nnn, \@@_anspic_args:nnn, % \@@_anspic_print:n, \@@_anspic_print:e, % \@@_anspic_print:V, \@@_anspic_row:n, \@@_anspic_exec:} % The \myhlc|\@@_anspic_body_dim:n| function will set the value of % \myhlc|\l_@@_anspic_body_htdp_dim| equal to the \enquote{height plus depth} % of the \emph{mandatory argument} if the key \mykey[env]{label-pos} is set % \enquote{below}. % \begin{macrocode} \cs_new_protected:Nn \@@_anspic_body_dim:n { \bool_if:NF \l_@@_anspic_label_above_bool { \IfDocumentMetadataT { \tag_suspend:n {keyanspic} } \vbox_set:Nn \l_@@_anspic_body_box {#1} \dim_set:Nn \l_@@_anspic_body_htdp_dim { \box_ht_plus_dp:N \l_@@_anspic_body_box } \IfDocumentMetadataT { \tag_resume:n {keyanspic} } } } % \end{macrocode} % The \myhlc|\@@_anspic_label:nn| function will process inside |\makebox| the % \emph{starred argument} `|*|' and \emph{optional argument} passed % to the command. Here the \mymeta{label} and % \emph{optional argument} are stored in \emph{prop list} and \emph{sequence} % and the \mykey[env]{show-ans}, \mykey[env]{show-pos}, \mykey[env]{font}, % \mykey[env]{wrap-label}, \mykey[env]{wrap-ans*} and \mykey[env]{wrap-opt} keys are executed. % \begin{macrocode} \cs_new_protected:Nn \@@_anspic_label:nn { \makebox[ \l_@@_anspic_mini_width_dim ][ c ] { \bool_if:nTF {#1} { \bool_set_true:N \l_@@_item_wrap_key_bool \bool_set_true:N \l_@@_wrap_label_v_bool \@@_keyans_save_item_opt:n {#2} \@@_keyans_addto_prop:n {#2} \@@_keyans_store_ref: \@@_keyans_addto_seq:n {#2} \int_gincr:N \g_@@_check_starred_cmd_int \@@_keyans_show_ans: \@@_keyans_show_pos: \makebox[ \l_@@_labelwidth_v_dim ][c] { \tl_use:N \l_@@_label_font_style_v_tl \@@_keyans_wrapper_label:n { \l_@@_label_vi_tl } } \skip_horizontal:n { \l_@@_labelsep_v_dim } \@@_keyans_show_item_opt: } { \bool_set_false:N \l_@@_item_wrap_key_bool \tl_use:N \l_@@_label_font_style_v_tl \@@_wrapper_label_v:n { \l_@@_label_vi_tl } } } } % \end{macrocode} % The function \myhlc|\@@_anspic_label_pos:nnn| will be in charge of % handling the \emph{\enquote{counter}} and the position of the \mymeta{label}, % set by \mykey{label-pos} key which will have the same configuration % as the \myenv*[no-index]{keyans} environment. % \begin{macrocode} \cs_new_protected:Nn \@@_anspic_label_pos:nnn { \stepcounter { enumXvi } \@@_anspic_body_dim:n {#3} \bool_if:NTF \l_@@_anspic_label_above_bool { \@@_anspic_label:nn {#1} {#2} } { \raisebox { -\dim_eval:n { \l_@@_anspic_label_htdp_dim + \l_@@_anspic_body_htdp_dim + \box_dp:N \strutbox + \l_@@_anspic_label_sep_skip } } [ 0pt ] [ 0pt ] { \@@_anspic_label:nn {#1} {#2} } } } % % \end{macrocode} % The \myhlc|\@@_anspic_args:nnn| function will be responsible for placing % the code compatible with \emph{tagged} \texttt{PDF} and the arguments % within the \myhlc|\l_@@_anspic_args_seq| sequence which will be processed % by the \myhlc|\@@_anspic_print:n| function in the second part of the % definition of the \myenv*[no-index]{keyanspic} environment. % \begin{macrocode} \cs_new_protected:Nn \@@_anspic_args:nnn { \@@_anspic_start_list_tag: \@@_anspic_label_pos:nnn {#1} {#2} {#3} \@@_anspic_stop_start_list_tag: \bool_if:NTF \l_@@_anspic_label_above_bool { \\[\l_@@_anspic_label_sep_skip] #3 } { \\ #3 } \@@_anspic_stop_list_tag: } % \end{macrocode} % The value \mymarg{n° upper, n° lower} passed to the \mykey[env]{layout-sty} % key is split by comma and is handled directly by the function % \myhlc|\@@_anspic_print:n| and passed to the function \myhlc|\@@_anspic_row:n|. % \begin{macrocode} \cs_new_protected:Nn \@@_anspic_print:n { \clist_map_function:nN {#1} \@@_anspic_row:n } \cs_generate_variant:Nn \@@_anspic_print:n { e, V } % \end{macrocode} % The function \myhlc|\@@_anspic_row:n| will set the \emph{widths} for the % \myenv[no-index]{minipage} environments and place \emph{all arguments} passed % to |\anspic| \emph{saved} in the \myhlc|\l_@@_anspic_args_seq| sequence % inside them. % \begin{macrocode} \cs_new_protected:Nn \@@_anspic_row:n { \dim_set:Nn \l_@@_anspic_mini_width_dim { \linewidth / #1 } \int_set:Nn \l_@@_anspic_above_int { \l_@@_anspic_below_int } \int_set:Nn \l_@@_anspic_below_int { \l_@@_anspic_above_int + #1 } \int_step_inline:nnn { \l_@@_anspic_above_int + 1 } { \l_@@_anspic_below_int } { \IfDocumentMetadataT { \tag_suspend:n {minipage} } \begin{minipage}[ \l_@@_anspic_mini_pos_str ]{ \l_@@_anspic_mini_width_dim } \centering \seq_item:Nn \l_@@_anspic_args_seq {##1} \end{minipage} \IfDocumentMetadataT { \tag_resume:n {minipage} } } \par } % \end{macrocode} % The \myhlc|\@@_anspic_exec:| function will execute all the code in the % |\anspic| command in the second argument of the \myenv*[no-index]{keyanspic} environment % definition. If the key \mykey{layout-sty} is not set, everything will % be printed on a \emph{single line}. % \begin{macrocode} \cs_new_protected:Nn \@@_anspic_exec: { \tl_if_empty:NTF \l_@@_anspic_layout_style_tl { \@@_anspic_print:e { \seq_count:N \l_@@_anspic_args_seq } } { \@@_anspic_print:V \l_@@_anspic_layout_style_tl } } % \end{macrocode} % \end{macro} % % \begin{macro}{\anspic} % The command accepts a \emph{starred argument} `|*|' in `|#1|', an optional % \myoarg{content} in `|#2|' and a mandatory \mymarg{drawing or tabular} in `|#3|'. % The command is active in the \myenv*[no-index]{keyanspic} % environment only if the \mykey[env]{save-ans} key is present, otherwise % an error is returned. % The three arguments are handled by the function \myhlc|\@@_anspic_args:nnn| % and stored in the sequence \myhlc|\l_@@_anspic_args_seq| which is processed % by the \myenv*[no-index]{keyanspic} environment. % \begin{macrocode} \NewDocumentCommand \anspic { s o +m } { \bool_lazy_or:nnF { \l_@@_store_active_bool } { \@@_in_keyans_p: } { \msg_error:nnnn { enumext } { wrong-place }{ keyanspic }{ save-ans } } \int_compare:nNnT { \l_@@_level_int } > { 1 } { \msg_error:nn { enumext } { keyanspic-wrong-level } } \int_compare:nNnT { \l_@@_keyans_level_int } = { 1 } { \msg_error:nnnn { enumext } { command-wrong-place }{ anspic }{ keyans } } \seq_put_right:Nn \l_@@_anspic_args_seq { \@@_anspic_args:nnn {#1} {#2} {#3} } } % \end{macrocode} % \end{macro} % % \subsection{The horizontal environments}\label{subsec:horizontal-envs} % % Generating \emph{horizontal list environments} is NOT as simple as standard % \hologo{LaTeX} list environments. The fundamental part of the code is adapted % from the \mypkg{shortlst} package to a more modern version using \mypkg{expl3}\cite{expl3}. % It is not possible to redefine |\item| and |\makelabel| using |\RenewDocumentCommand| as in % the vertical \emph{non starred} versions. % % To achieve the \emph{horizontal list environments}, the |\item| % command and its \mymeta{content} are captured in a \emph{horizontal box} using |\makebox| for % the \mykey{label} and a \myenv[no-index]{minipage} environment for the \mymeta{content} passed to % |\item|; the \emph{optional argument} \myparg{number} is also added to |\item| % to be able to \emph{join columns} horizontally. In simple terms, the goal is for % |\item| to behave in the same way as in the \myenv*[no-index]{enumext} environment but % with an additional \emph{first optional argument} \myparg{number}. % % Since |\item| is not redefined with |\RenewDocumentCommand|, the original % definition of the kernel is replaced by the one of the horizontal environment. % The original is not lost, a copy is made at the beginning of the document and % |\item| is turned into a \emph{switch} that decides which of the two % definitions must be run, as explained in \S\ref{subsec:item-nested}. Because of % this, the \emph{standard list environments} and any environment defined using % base \myenv[no-index]{list} or \myhlc|\trivlist| can be used in the \mymeta{content} % of the items of \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*}: % \myenv[no-index]{itemize}, \myenv[no-index]{enumerate}, \myenv[no-index]{description}, % \myenv[no-index]{quote}, \myenv[no-index]{quotation}, \myenv[no-index]{verse}, % \myenv[no-index]{list}, \myenv[no-index]{center}, \myenv[no-index]{flushleft}, % \myenv[no-index]{flushright}, \myenv[no-index]{trivlist}, \myenv[no-index]{tabbing}, % \myenv[no-index]{verbatim} and all environments created with |\newtheorem|. % % \begin{important} % When \mykey{item-break} is active and the item occupies the whole row, the % content of the item is not captured in a \emph{horizontal box} or in % a \myenv[no-index]{minipage}, but it is typeset directly in the vertical list % (\S\ref{subsec:item-break-impl}). % \end{important} % % \begin{important} % For compatibility with the \emph{tagged} \texttt{PDF}, the environments are closed % according to the presence or not of the \mykey{mini-env} key. % \end{important} % % \subsubsection{Definition of variables} % % \begin{variable}[int]{ % \l_@@_joined_item_X_int, % \l_@@_joined_item_aux_X_int, % \l_@@_tmpa_X_int, % \l_@@_item_width_X_dim, % \g_@@_minipage_active_X_bool, % \l_@@_miniright_code_X_box, % } % Internal variables used by \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} % environments. The integers \myhlc|\l_@@_joined_item_X_int|, % \myhlc|\l_@@_joined_item_aux_X_int| and \myhlc|\l_@@_tmpa_X_int| and the dimension % \myhlc|\l_@@_item_width_X_dim| are used by the functions that calculate the % item box width and join the item columns. The variables % \myhlc|\g_@@_minipage_active_X_bool| and \myhlc|\l_@@_miniright_code_X_box| % are used by the \mykey{mini-env}, \mykey{mini-right} and \mykey{mini-right*} keys % (\S\ref{subsubsec:mini-env}). % \begin{macrocode} \cs_set_protected:Nn \@@_tmp:n { \int_new:c { l_@@_joined_item_ #1 _int } \int_new:c { l_@@_joined_item_aux_ #1 _int } \int_new:c { l_@@_tmpa_ #1 _int } \dim_new:c { l_@@_item_width_ #1 _dim } \bool_new:c { g_@@_minipage_active_ #1 _bool } \box_new:c { l_@@_miniright_code_ #1 _box } } \clist_map_inline:nn { vii, viii } { \@@_tmp:n {#1} } % \end{macrocode} % \end{variable} % % \subsubsection{Definition of error messages} % % \begin{macro}[int]{nested-horizontal, item-joined, item-joined-columns} % Messages used by \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} environments. % \begin{macrocode} \msg_new:nnnn { enumext } { nested-horizontal } { The~environment~\l_@@_envir_name_tl \c_space_tl can't~be~nested~in~'#1'~ \msg_line_context:. } { 'enumext*'~and~'keyans*'~are~horizontal~lists~and~can't~be~ inside~each~other. } \msg_new:nnn { enumext } { item-joined } { Items~joined~(#1)~>~#2~columns~\msg_line_context:. } \msg_new:nnn { enumext } { item-joined-columns } { Not~enough~space~to~join~items~(#1)~>~#2~\msg_line_context:. } % \end{macrocode} % \end{macro} % % \subsubsection{Functions for item box width} % % \begin{macro}[int]{\@@_starred_columns_set_vii:, \@@_starred_columns_set_viii:} % Sets the default value for the \emph{width of the box} containing the % \mymeta{content} of the items for \myenv*[no-index]{enumext*} environment. % \begin{macrocode} \cs_new_protected:Nn \@@_starred_columns_set_vii: { \dim_compare:nNnT { \l_@@_columns_sep_vii_dim } = { \c_zero_dim } { \dim_set:Nn \l_@@_columns_sep_vii_dim { ( \l_@@_labelwidth_vii_dim + \l_@@_labelsep_vii_dim ) / \l_@@_columns_vii_int } } \int_set:Nn \l_@@_tmpa_vii_int { \l_@@_columns_vii_int - 1 } \dim_set:Nn \l_@@_item_width_vii_dim { ( \linewidth - \l_@@_columns_sep_vii_dim * \l_@@_tmpa_vii_int ) / \l_@@_columns_vii_int - \l_@@_labelwidth_vii_dim - \l_@@_labelsep_vii_dim } % \end{macrocode} % When the key \mykey[env]{rightmargin} is active the values must be adjusted. % \begin{macrocode} \dim_compare:nNnT { \l_@@_rightmargin_vii_dim } > { \c_zero_dim } { \dim_sub:Nn \l_@@_item_width_vii_dim { ( \l_@@_rightmargin_vii_dim * \l_@@_tmpa_vii_int ) / \l_@@_columns_vii_int } \dim_add:Nn \l_@@_columns_sep_vii_dim { \l_@@_rightmargin_vii_dim } } } % \end{macrocode} % Same implementation for the \myenv*[no-index]{keyans*} environment. % \begin{macrocode} \cs_new_protected:Nn \@@_starred_columns_set_viii: { \dim_compare:nNnT { \l_@@_columns_sep_viii_dim } = { \c_zero_dim } { \dim_set:Nn \l_@@_columns_sep_viii_dim { ( \l_@@_labelwidth_viii_dim + \l_@@_labelsep_viii_dim ) / \l_@@_columns_viii_int } } \int_set:Nn \l_@@_tmpa_viii_int { \l_@@_columns_viii_int - 1 } \dim_set:Nn \l_@@_item_width_viii_dim { ( \linewidth - \l_@@_columns_sep_viii_dim * \l_@@_tmpa_viii_int ) / \l_@@_columns_viii_int - \l_@@_labelwidth_viii_dim - \l_@@_labelsep_viii_dim } \dim_compare:nNnT { \l_@@_rightmargin_viii_dim } > { \c_zero_dim } { \dim_sub:Nn \l_@@_item_width_viii_dim { ( \l_@@_rightmargin_viii_dim * \l_@@_tmpa_viii_int ) / \l_@@_columns_viii_int } \dim_add:Nn \l_@@_columns_sep_viii_dim { \l_@@_rightmargin_viii_dim } } } % \end{macrocode} % \end{macro} % % \subsubsection{Functions for join item columns} % % \begin{macro}[int]{\@@_starred_joined_item_vii:n, \@@_starred_joined_item_viii:n} % The functions \myhlc|\@@_starred_joined_item_vii:n| and \myhlc|\@@_starred_joined_item_viii:n| % will set the \emph{width} of the box in which the \mymeta{content} % passed to |\item|\myparg{columns} will be stored together with % the value of |\itemwidth| for the \myenv*[no-index]{enumext*} environment. % \begin{macrocode} \cs_new_protected:Nn \@@_starred_joined_item_vii:n { \int_set:Nn \l_@@_joined_item_vii_int {#1} \int_compare:nNnT { \l_@@_joined_item_vii_int } > { \l_@@_columns_vii_int } { \msg_warning:nnee { enumext } { item-joined } { \int_use:N \l_@@_joined_item_vii_int } { \int_use:N \l_@@_columns_vii_int } \int_set:Nn \l_@@_joined_item_vii_int { \l_@@_columns_vii_int - \l_@@_item_column_pos_vii_int + 1 } } \int_compare:nNnT { \l_@@_joined_item_vii_int } > { \l_@@_columns_vii_int - \l_@@_item_column_pos_vii_int + 1 } { \msg_warning:nnee { enumext } { item-joined-columns } { \int_use:N \l_@@_joined_item_vii_int } { \int_eval:n { \l_@@_columns_vii_int - \l_@@_item_column_pos_vii_int + 1 } } \int_set:Nn \l_@@_joined_item_vii_int { \l_@@_columns_vii_int - \l_@@_item_column_pos_vii_int + 1 } } \int_compare:nNnTF { \l_@@_joined_item_vii_int } > { 1 } { \int_set_eq:NN \l_@@_joined_item_aux_vii_int \l_@@_joined_item_vii_int \int_decr:N \l_@@_joined_item_aux_vii_int \int_add:Nn \l_@@_item_column_pos_vii_int { \l_@@_joined_item_aux_vii_int } \int_gadd:Nn \g_@@_item_count_all_vii_int { \l_@@_joined_item_aux_vii_int } \dim_set:Nn \l_@@_joined_width_vii_dim { \l_@@_item_width_vii_dim * \l_@@_joined_item_vii_int + ( \l_@@_labelwidth_vii_dim + \l_@@_labelsep_vii_dim + \l_@@_columns_sep_vii_dim ) * \l_@@_joined_item_aux_vii_int } \dim_set_eq:NN \itemwidth \l_@@_joined_width_vii_dim } { \dim_set_eq:NN \l_@@_joined_width_vii_dim \l_@@_item_width_vii_dim \dim_set_eq:NN \itemwidth \l_@@_item_width_vii_dim } } % \end{macrocode} % Same implementation for the \myenv*[no-index]{keyans*} environment. % \begin{macrocode} \cs_new_protected:Nn \@@_starred_joined_item_viii:n { \int_set:Nn \l_@@_joined_item_viii_int {#1} \int_compare:nNnT { \l_@@_joined_item_viii_int } > { \l_@@_columns_viii_int } { \msg_warning:nnee { enumext } { item-joined } { \int_use:N \l_@@_joined_item_viii_int } { \int_use:N \l_@@_columns_viii_int } \int_set:Nn \l_@@_joined_item_viii_int { \l_@@_columns_viii_int - \l_@@_item_column_pos_viii_int + 1 } } \int_compare:nNnT { \l_@@_joined_item_viii_int } > { \l_@@_columns_viii_int - \l_@@_item_column_pos_viii_int + 1 } { \msg_warning:nnee { enumext } { item-joined-columns } { \int_use:N \l_@@_joined_item_viii_int } { \int_eval:n { \l_@@_columns_viii_int - \l_@@_item_column_pos_viii_int + 1 } } \int_set:Nn \l_@@_joined_item_viii_int { \l_@@_columns_viii_int - \l_@@_item_column_pos_viii_int + 1 } } \int_compare:nNnTF { \l_@@_joined_item_viii_int } > { 1 } { \int_set_eq:NN \l_@@_joined_item_aux_viii_int \l_@@_joined_item_viii_int \int_decr:N \l_@@_joined_item_aux_viii_int \int_add:Nn \l_@@_item_column_pos_viii_int { \l_@@_joined_item_aux_viii_int } \int_gadd:Nn \g_@@_item_count_all_viii_int { \l_@@_joined_item_aux_viii_int } \dim_set:Nn \l_@@_joined_width_viii_dim { \l_@@_item_width_viii_dim * \l_@@_joined_item_viii_int + ( \l_@@_labelwidth_viii_dim + \l_@@_labelsep_viii_dim + \l_@@_columns_sep_viii_dim )*\l_@@_joined_item_aux_viii_int } \dim_set_eq:NN \itemwidth \l_@@_joined_width_viii_dim } { \dim_set_eq:NN \l_@@_joined_width_viii_dim \l_@@_item_width_viii_dim \dim_set_eq:NN \itemwidth \l_@@_item_width_viii_dim } } % \end{macrocode} % \end{macro} % % \subsubsection{Functions for \texttt{mini-env}, \texttt{mini-right} and \texttt{mini-right*} keys}\label{subsubsec:mini-env} % % \begin{macro}[int]{\@@_start_mini_vii:, \@@_stop_mini_vii:} % The implementation of the \mykey[env]{mini-env} key support is almost % identical to the one used in the \myenv*[no-index]{enumext} and \myenv*[no-index]{keyans} % environments, the difference is that the \myhlc|\@@_mini_page| % environment on the \emph{\enquote{right side}} is executed % \emph{\enquote{after}} closing the environment, so it is necessary to % make a global copy of the variable \myhlc|\l_@@_minipage_right_vii_dim| in % the variable \myhlc|\g_@@_minipage_right_vii_dim|. % \begin{macrocode} \cs_new_protected:Nn \@@_start_mini_vii: { \dim_compare:nNnT { \l_@@_minipage_right_vii_dim } > { \c_zero_dim } { \dim_set:Nn \l_@@_minipage_left_vii_dim { \linewidth - \l_@@_minipage_right_vii_dim - \l_@@_minipage_hsep_vii_dim } \bool_set_true:N \l_@@_minipage_active_vii_bool \dim_gset_eq:NN \g_@@_minipage_right_vii_dim \l_@@_minipage_right_vii_dim \@@_mini_addvspace_vii: \nointerlineskip\noindent \@@_mini_page{ \l_@@_minipage_left_vii_dim } } } % \end{macrocode} % The function \myhlc|\@@_stop_mini_vii:| closes the \myhlc|\@@_mini_page| % environment on the \emph{\enquote{left side}}, applies \myhlc|\hfill| and % sets the variable \myhlc|\g_@@_minipage_active_vii_bool| to |true| % which will be used in the function \myhlc|\@@_after_env:nn| to execute % the \myenv[no-index]{minipage} on the \emph{\enquote{right side}}. At this point % the \myhlc|\@@_stop_list:| and \myhlc|\@@_stop_store_level_vii:| % functions are executed, stopping the \myenv[no-index]{list} environment and the level saving % mechanism for storage in \emph{sequence} of the |\anskey| command % and \myenv*[no-index]{anskey*} environment. This function is passed to the % \myhlc|\@@_after_list_vii:| function in the second part of the \myenv*[no-index]{enumext*} % environment definition (\S\ref{env:starred}). Before closing the % \myhlc|\@@_mini_page| the function \myhlc|\@@_mini_capture_end:| stores % the space \emph{\enquote{below}}. % \begin{macrocode} \cs_new_protected:Nn \@@_stop_mini_vii: { \bool_if:NTF \l_@@_minipage_active_vii_bool { \@@_stop_list: \@@_stop_store_level_vii: \@@_mini_capture_end: \IfDocumentMetadataT { \tag_resume:n {enumext*} } \end@@_mini_page \hfill \bool_gset_true:N \g_@@_minipage_active_vii_bool } { \@@_stop_list: \@@_stop_store_level_vii: } } % \end{macrocode} % \end{macro} % % Finally the \mymarg{code} passed to the \mykey{mini-right} % or \mykey{mini-right*} keys stored in the variable \myhlc|\g_@@_miniright_code_vii_tl| % in the \myenv[no-index]{minipage} environment on the \emph{\enquote{right % side}} is executed. For compatibility with the \mypkg{caption} package and possibly % other \mymarg{code} passed to this key, it is passed to a box and % then printed. Once the \myenv[no-index]{minipage} on the \emph{\enquote{right % side}} is closed, \myhlc|\@@_mini_apply_end:| adds the stored space % \emph{\enquote{below}}. This minipage is opened after the environment has % ended, so it is placed in a group; otherwise the assignments that % \hologo{LaTeX} makes when \emph{tagging} \texttt{PDF} is active (for % example, the one that makes a heading warn that it is inside a box) would % remain active after the list. % \begin{macrocode} \@@_after_env:nn {enumext*} { \bool_if:NT \g_@@_minipage_active_vii_bool { \group_begin: \@@_minipage:w [ t ] { \g_@@_minipage_right_vii_dim } \legacy_if_gset_false:n { @minipage } \skip_vertical:N \c_zero_skip \par\addvspace { \g_@@_minipage_right_skip } \bool_if:NF \g_@@_minipage_center_vii_bool { \tl_gput_left:Nn \g_@@_miniright_code_vii_tl { \centering } } \vbox_set_top:Nn \l_@@_miniright_code_vii_box { \tl_use:N \g_@@_miniright_code_vii_tl } \box_use_drop:N \l_@@_miniright_code_vii_box \skip_vertical:N \c_zero_skip \@@_endminipage: \group_end: \@@_mini_apply_end: } \bool_gset_false:N \g_@@_minipage_active_vii_bool \bool_gset_true:N \g_@@_minipage_center_vii_bool \tl_gclear:N \g_@@_miniright_code_vii_tl \dim_gzero:N \g_@@_minipage_right_vii_dim \bool_gset_false:N \g_@@_starred_bool } % \end{macrocode} % % \begin{macro}[int]{\@@_start_mini_viii:, \@@_stop_mini_viii:} % The implementation of the \mykey[env]{mini-env}, \mykey[env]{mini-right} and % \mykey[env]{mini-right*} keys is identical to the one used in the % \myenv*[no-index]{enumext*} environment. % \begin{macrocode} \cs_new_protected:Nn \@@_start_mini_viii: { \dim_compare:nNnT { \l_@@_minipage_right_viii_dim } > { \c_zero_dim } { \dim_set:Nn \l_@@_minipage_left_viii_dim { \linewidth - \l_@@_minipage_right_viii_dim - \l_@@_minipage_hsep_viii_dim } \bool_set_true:N \l_@@_minipage_active_viii_bool \dim_gset_eq:NN \g_@@_minipage_right_viii_dim \l_@@_minipage_right_viii_dim \@@_mini_addvspace_viii: \nointerlineskip\noindent \@@_mini_page{ \l_@@_minipage_left_viii_dim } } } \cs_new_protected:Nn \@@_stop_mini_viii: { \bool_if:NTF \l_@@_minipage_active_viii_bool { \@@_stop_list: \@@_mini_capture_end: \IfDocumentMetadataT { \tag_resume:n {keyans*} } \end@@_mini_page \hfill \bool_gset_true:N \g_@@_minipage_active_viii_bool } { \@@_stop_list: } } \@@_after_env:nn {keyans*} { \bool_if:NT \g_@@_minipage_active_viii_bool { \group_begin: \@@_mini_page{ \g_@@_minipage_right_viii_dim } \par\addvspace { \g_@@_minipage_right_skip } \bool_if:NF \g_@@_minipage_center_viii_bool { \tl_gput_left:Nn \g_@@_miniright_code_viii_tl { \centering } } \vbox_set_top:Nn \l_@@_miniright_code_viii_box { \tl_use:N \g_@@_miniright_code_viii_tl } \box_use_drop:N \l_@@_miniright_code_viii_box \end@@_mini_page \group_end: \@@_mini_apply_end: } \bool_gset_false:N \g_@@_minipage_active_viii_bool \bool_gset_true:N \g_@@_minipage_center_viii_bool \tl_gclear:N \g_@@_miniright_code_viii_tl \dim_gzero:N \g_@@_minipage_right_viii_dim } % \end{macrocode} % \end{macro} % % \subsection{The environment \env{enumext*}}\label{env:starred} % % \begin{macro}{enumext*} % The environment accepts an optional \myoarg{key \textnormal{\textcolor{gray}{=}} val} argument in `|#1|' % that is processed after checking where it is running. The environment is % generated and a temporary definition is given to \myhlc|\@@_stop_item_tmp_vii:| equal to % \myhlc|\@@_first_item_tmp_vii:| and next to |\item| equal to the switch % \myhlc|\@@_item_switch_vii:| (\S\ref{subsec:item-nested}), which decides whether % |\item| belongs to \env{enumext*} (\myhlc|\@@_start_item_tmp_vii:|, redefined % later) or to a standard list nested inside it; the nesting depth of % the \env{enumext*} environment is stored in \myhlc|\l_@@_base_depth_int|. Unlike the implementation used by % the \mypkg[no-index]{shortlst} package, the values of % \myhlc|\rightskip| and |\@rightskip| are not set equal to |\@flushglue|, whose value is % \mydim{0.0pt plus 1.0 fil}; in the tests performed this fails in % some circumstances and different results are obtained when using % \hologo{pdfTeX} and \hologo{LuaTeX}. % \begin{macrocode} \NewDocumentEnvironment{enumext*}{ o } { \@@_safe_exec_vii: \@@_parse_keys_vii:n {#1} \@@_before_list_vii: \@@_start_store_level_vii: \@@_nested_save: \@@_start_list:nn { } { \@@_list_arg_two_vii: \@@_before_keys_exec_vii: } \IfDocumentMetadataT { \tag_suspend:n {enumext*} } \@@_starred_columns_set_vii: \item[] \scan_stop: % \end{macrocode} % For compatibility with \emph{tagged} \texttt{PDF} in \hologo{LaTeX} % release 2026-06-01, |\setcounter| is set at this point in the % environment definition, thereby avoiding the problem reported by % Tim Prescott (\texttt{@teepeemm}) in \href{https://github.com/pablgonz/enumext/issues/5}{enumext* nested in enumext starts at 2 with DocumentMetadata} % this was caused by the \mypkg[no-index]{latex-lab-block}\cite{latexlab} update in this release. % \begin{macrocode} \setcounter { enumXvii } { \int_eval:n { \int_use:c { l_@@_start_vii_int } - 1 } } \cs_set_eq:NN \@@_stop_item_tmp_vii: \@@_first_item_tmp_vii: \cs_set_eq:NN \item \@@_item_switch_vii: \int_set:Nn \l_@@_base_depth_int { \@listdepth } \bool_set_false:N \l_@@_trivlist_bool \ignorespaces } { % {tag=text-unit} \IfDocumentMetadataT { \tag_struct_end:n {tag=semantic-para} } \@@_stop_item_tmp_vii: \@@_remove_extra_parsep_vii: \@@_after_list_vii: } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_safe_exec_vii:}\label{fun:safe-exec-starred} % The function \myhlc|\@@_is_not_nested:| is called first, which sets % \myhlc|\g_@@_starred_bool| to true if it is NOT nested within \myenv*[no-index]{enumext}; % then the function \myhlc|\@@_internal_mini_page:| is called to create the % environment \myhlc|\@@_mini_page|, \myhlc|\l_@@_level_h_int| is incremented % to restrict nesting of the environment, \myhlc|\l_@@_starred_bool| is set % to true, and finally the function \myhlc|\@@_is_on_first_level:| is called, which % sets \myhlc|\l_@@_starred_first_bool| to % true if it is not nested, allowing the \emph{\enquote{storage system}} % to be used. % \begin{macrocode} \cs_new_protected:Nn \@@_safe_exec_vii: { \@@_is_not_nested: \@@_internal_mini_page: \int_incr:N \l_@@_level_h_int \int_compare:nNnT { \l_@@_level_h_int } > { 1 } { \msg_error:nn { enumext } { nested } } \int_compare:nNnT { \l_@@_keyans_level_h_int } = { 1 } { \msg_error:nnn { enumext } { nested-horizontal } { keyans*} } \bool_set_true:N \l_@@_starred_bool \bool_set_false:N \l_@@_standard_bool \@@_is_on_first_level: } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_parse_keys_vii:n} % It first checks the state of the variable \myhlc|\l_@@_resume_count_vii_bool| % set by the key \mykey[env]{resume} and calls the function \myhlc|\@@_resume_last_counter:| % if it is |true|, then clears the variable \myhlc|\l_@@_series_name_str| % used by the key \mykey[env]{series}, processes the environment \myoarg{key \textnormal{\textcolor{gray}{=}} val} % and executes the function \myhlc|\@@_parse_series:n| used by the key % \mykey{series}, then executes the function \myhlc|\@@_store_active_keys_vii:n| % and reprocesses the \mymeta{keys} to pass them to the storage \emph{sequence} % if the key \mykey[env]{save-key} is not active. % % \begin{important}* % Here it is necessary to check the status of \myhlc|\l_@@_resume_count_vii_bool| % in case the key \mykey{resume} is set using |\setenumext{enumext*}{resume}|. % \end{important} % % \begin{macrocode} \cs_new_protected:Nn \@@_parse_keys_vii:n { \bool_if:NT \l_@@_resume_count_vii_bool { \@@_resume_last_counter: } \tl_if_novalue:nF {#1} { \str_clear:N \l_@@_series_name_str \keys_set:nn { enumext / enumext* } {#1} \bool_if:NF \l_@@_print_keyans_cmd_bool { \@@_parse_series:n {#1} } \@@_store_active_keys_vii:n {#1} } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_before_list_vii:} % The function \myhlc|\@@_before_list_vii:| first calls the function % \myhlc|\@@_vspace_above_vii:| used by the keys \mykey[env]{above} and % \mykey[env]{above*}, then calls the function \myhlc|\@@_check_ans_active:| for % the check answer mechanism and finally calls the functions % \myhlc|\@@_before_args_exec_vii:| and \myhlc|\@@_start_mini_vii:| used by the % keys \mykey[env]{before*}, \mykey[env]{mini-env}, \mykey[env]{mini-right} and % \mykey[env]{mini-right*}. % \begin{macrocode} \cs_new_protected:Nn \@@_before_list_vii: { \@@_vspace_above_vii: \@@_check_ans_active: \@@_before_args_exec_vii: \@@_start_mini_vii: } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_after_list_vii:} % The function \myhlc|\@@_after_list_vii:| first calls the function % \myhlc|\@@_stop_mini_vii:| which internally calls \myhlc|\@@_stop_list:| and % \myhlc|\@@_stop_store_level_vii:| (\S\ref{subsubsec:mini-env}) used % by the keys \mykey[env]{mini-env}, \mykey[env]{mini-right} and \mykey[env]{mini-right*}, % then to the functions \myhlc|\@@_after_stop_list_vii:| used by the key % \mykey[env,foreachkeyans]{after}, \myhlc|\@@_check_ans_key_hook:| used by the key \mykey[env]{check-ans}, % \myhlc|\@@_vspace_below_vii:| used by the keys \mykey[env]{below} and % \mykey[env]{below*}. Finally set \myhlc|\l_@@_starred_bool| to false and call % the \myhlc|\@@_starred_save_counter:| function used by the \mykey[env]{series}, % \mykey[env]{resume} and \mykey[env]{resume*} keys. % \begin{macrocode} \cs_new_protected:Nn \@@_after_list_vii: { \@@_stop_mini_vii: \@@_after_stop_list_vii: \@@_check_ans_key_hook: \@@_vspace_below_vii: \bool_set_false:N \l_@@_starred_bool \bool_if:NF \l_@@_print_keyans_cmd_bool { \@@_starred_save_counter: } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_start_store_level_vii:, \@@_stop_store_level_vii:} % The \myhlc|\@@_start_store_level_vii:| and \myhlc|\@@_stop_store_level_vii:| % functions activate the \emph{\enquote{storing structure}} mechanism % in \emph{sequence} for |\anskey| command and \myenv*[no-index]{anskey*} % environment if \myenv*[no-index]{enumext*} are nested in \myenv*[no-index]{enumext}. % \begin{macrocode} \cs_new_protected:Nn \@@_start_store_level_vii: { \bool_if:NT \l_@@_store_active_bool { \int_compare:nNnT { \l_@@_level_int } > { 0 } { \@@_store_level_open_vii: } } } \cs_new_protected:Nn \@@_stop_store_level_vii: { \bool_if:NT \l_@@_store_active_bool { \int_compare:nNnT { \l_@@_level_int } > { 0 } { \@@_store_level_close_vii: } } } % \end{macrocode} % \end{macro} % % \subsubsection{The command \cs{item} in \env{enumext*}}\label{cmd:item-enumext-starred} % % \begin{macro}[int]{\@@_first_item_tmp_vii:} % % The \myhlc|\@@_first_item_tmp_vii:| function will remove horizontal space % equal to |\labelwidth| plus |\labelsep| to the left of the \emph{\enquote{first}} % |\item| in the environment at the point of execution of this function, % where it is equal to the \myhlc|\@@_stop_item_tmp_vii:| function inside the % environment body definition. % \begin{macrocode} \cs_new_protected_nopar:Nn \@@_first_item_tmp_vii: { \skip_horizontal:n { -\l_@@_labelwidth_vii_dim - \l_@@_labelsep_vii_dim } \ignorespaces } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_start_item_tmp_vii:, \@@_item_peek_args_vii:, % \@@_joined_item_vii:w, \@@_standard_item_vii:w, % \@@_starred_item_vii:w, \@@_starred_item_vii_aux_i:w, % \@@_starred_item_vii_aux_ii:w, \@@_starred_item_vii_aux_iii:w} % First the function \myhlc|\@@_stop_item_tmp_vii:| is called, which is % redefined later, then the value of % \myhlc|\l_@@_item_column_pos_vii_int|, which counts the items by rows, and % the value of \myhlc|\g_@@_item_count_all_vii_int|, which counts the % total of items in the environment, are incremented. After that the % function \myhlc|\@@_item_peek_args_vii:| is called, which handles the % arguments passed to |\item|. % \begin{macrocode} \cs_new_protected_nopar:Nn \@@_start_item_tmp_vii: { \@@_stop_item_tmp_vii: \int_incr:N \l_@@_item_column_pos_vii_int \int_gincr:N \g_@@_item_count_all_vii_int \@@_item_peek_args_vii: } % \end{macrocode} % The function \myhlc|\@@_item_peek_args_vii:| handles the |\item|\myparg{number}. % It looks for the argument \enquote{\textcolor{star}{\ttfamily (}}; % if it is present, it calls the function \myhlc|\@@_joined_item_vii:w| \myparg{number}, % which is in charge of joining the items in the same row; if it is % not present, it sets the default value \textcolor{gray}{\ttfamily(\mydim{1})}. % \begin{macrocode} \cs_new_protected:Nn \@@_item_peek_args_vii: { \peek_meaning:NTF ( { \@@_joined_item_vii:w } { \@@_joined_item_vii:w (1) } } % \end{macrocode} % The function \myhlc|\@@_joined_item_vii:w| will first call the % function \myhlc|\@@_starred_joined_item_vii:n| in charge of setting the % \emph{width} of the box that stores the content passed to |\item|. Then it % looks for the argument \enquote{\textcolor{star}{\ttfamily *}}; if it is present, it calls the % function \myhlc|\@@_starred_item_vii:w|, otherwise it calls the % function \myhlc|\@@_standard_item_vii:w|. % \begin{macrocode} \cs_new_protected:Npn \@@_joined_item_vii:w (#1) { \@@_starred_joined_item_vii:n {#1} \peek_meaning_remove:NTF * { \@@_starred_item_vii:w } { \@@_standard_item_vii:w } } % \end{macrocode} % The function \myhlc|\@@_standard_item_vii:w| will first look for the % argument `|[|', if present it will set the state of the variable % \myhlc|\l_@@_wrap_label_vii_bool| equal to the state of the variable % \myhlc|\l_@@_wrap_label_opt_vii_bool| handled by the key % \mykey[env]{wrap-label*} and finally execute the \emph{non-enumerated} % version |\item|\myoarg{custom} by means of the function % \myhlc|\@@_start_item_vii:w|; otherwise it sets the value of the % variable \myhlc|\l_@@_wrap_label_vii_bool| handled by the % \mykey[env]{wrap-label} key to true and set the switch |\if@noitemarg| to % true to execute the enumerated version of |\item| by means of the % function \myhlc|\@@_start_item_vii:w| |[| \myhlc|\l_@@_label_vii_tl| |]|. % \begin{macrocode} \cs_new_protected:Npn \@@_standard_item_vii:w { \bool_set_false:N \l_@@_item_starred_vii_bool \peek_meaning:NTF [ { \bool_set_eq:NN \l_@@_wrap_label_vii_bool \l_@@_wrap_label_opt_vii_bool \@@_start_item_vii:w } { \bool_set_true:N \l_@@_wrap_label_vii_bool \legacy_if_set_true:n { @noitemarg } \@@_start_item_vii:w [ \l_@@_label_vii_tl ] \ignorespaces } } % \end{macrocode} % The function \myhlc|\@@_starred_item_vii:w| together with the specified % auxiliary functions \myhlc|aux_i:w|, \myhlc|aux_ii:w|, and \myhlc|aux_iii:w| execute |\item*|, % |\item*|\myoarg{symbol} and |\item*|\myoarg{symbol}\myoarg{offset}. % \begin{macrocode} \cs_new_protected:Npn \@@_starred_item_vii:w { \bool_set_true:N \l_@@_item_starred_vii_bool \bool_set_true:N \l_@@_wrap_label_vii_bool \peek_meaning:NTF [ { \@@_starred_item_vii_aux_i:w } { \@@_starred_item_vii_aux_ii:w } } \cs_new_protected:Npn \@@_starred_item_vii_aux_i:w [#1] { \tl_gset:Nn \g_@@_item_symbol_aux_vii_tl {#1} \@@_starred_item_vii_aux_ii:w } \cs_new_protected:Npn \@@_starred_item_vii_aux_ii:w { \peek_meaning:NTF [ { \@@_starred_item_vii_aux_iii:w } { \dim_set_eq:NN \l_@@_item_symbol_sep_vii_dim \l_@@_labelsep_vii_dim \legacy_if_set_true:n { @noitemarg } \@@_start_item_vii:w [ \l_@@_label_vii_tl ] \ignorespaces } } \cs_new_protected:Npn \@@_starred_item_vii_aux_iii:w [#1] { \dim_set:Nn \l_@@_item_symbol_sep_vii_dim {#1} \legacy_if_set_true:n { @noitemarg } \@@_start_item_vii:w [ \l_@@_label_vii_tl ] \ignorespaces } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_fake_make_label_vii:n} % The \myhlc|\@@_fake_make_label_vii:n| function will be in charge of % handling the definition of |\item|. First it increments the counter % \icounter[no-index]{enumXvii} for the enumerated items and activates support for % the \emph{check answers} mechanism, followed by support for % |\item*|\myoarg{symbol}\myoarg{offset} if present, then the % \mykey[env]{wrap-label} and \mykey[env]{wrap-label*} keys, executed using % |\makebox| whose width is given by the \mykey[env]{labelwidth} key and % position by the \mykey[env]{align} key; inside its argument it % executes the \mykey[env]{font} key together with the function defined by the % \mykey{wrap-label} or \mykey{wrap-label*} keys. Finally it executes the % \mykey[env]{labelsep} key applying a \myhlc|\skip_horizontal:N| and \myhlc|\ignorespaces|. % % \begin{important} % For compatibility with \emph{tagged} \texttt{PDF} and \mypkg[no-index]{hyperref} % when an environment \myenv*[no-index]{enumext} is nested in \myenv*[no-index]{enumext*} % and the key \mykey[env]{save-ans} is not active need setting the |\if@hyper@item| % switch to |true|. The explanation for this is given % by the master Heiko Oberdiek on \href{https://tex.stackexchange.com/a/404911}{\textbackslash % refstepcounter\{enumi\} twice (or more) creates destination with the % same identifier}. % This patch is only needed if you are running |pdflatex| and not if % you are running |lualatex| % \end{important} % % \begin{macrocode} \cs_new_protected_nopar:Nn \@@_fake_make_label_vii:n { \legacy_if:nT { @noitemarg } { \legacy_if_set_false:n { @noitemarg } \legacy_if:nT { @nmbrlist } { \IfDocumentMetadataT { \bool_if:NT \l_@@_hyperref_bool { \legacy_if_set_true:n { @hyper@item } } } \refstepcounter{enumXvii} \bool_if:NT \l_@@_check_answers_bool { \int_gincr:N \g_@@_item_number_int \bool_set_true:N \l_@@_item_number_bool } } } \bool_if:NT \l_@@_item_starred_vii_bool { \tl_if_blank:VT \g_@@_item_symbol_aux_vii_tl { \tl_gset_eq:NN \g_@@_item_symbol_aux_vii_tl \l_@@_item_symbol_vii_tl } \mode_leave_vertical: \skip_horizontal:n { -\l_@@_item_symbol_sep_vii_dim } \hbox_overlap_left:n { \g_@@_item_symbol_aux_vii_tl } \skip_horizontal:N \l_@@_item_symbol_sep_vii_dim \tl_gclear:N \g_@@_item_symbol_aux_vii_tl } \makebox[ \l_@@_labelwidth_vii_dim ][ \l_@@_align_label_vii_str ] { \tl_use:N \l_@@_label_font_style_vii_tl \bool_if:NTF \l_@@_wrap_label_vii_bool { \@@_wrapper_label_vii:n {#1} } {#1} } \skip_horizontal:N \l_@@_labelsep_vii_dim \ignorespaces } % \end{macrocode} % \end{macro} % % \subsubsection{The \cs{item} command inside nested lists}\label{subsec:item-nested} % % In the \myenv*[no-index]{enumext*} and \myenv*[no-index]{keyans*} environments % |\item| is a \emph{streaming} command: it closes the box of the previous item and % opens the next one, so the |\item| of the environment and the |\item| of a % list nested in the \emph{\enquote{item content}}, for example % \myenv[no-index]{itemize}, run inside the same \myenv[no-index]{minipage}. % To distinguish them two things are used, depending on how the nested % environment is built. % % The environments based on \myenv[no-index]{list} increase the depth of lists % \myhlc|\@listdepth|. This depth is stored in \myhlc|\l_@@_base_depth_int| when the % environment starts and again after opening the \myenv[no-index]{minipage} of an % item, where the kernel resets it to zero. While \myhlc|\@listdepth| is greater than % the stored value |\item| belongs to the nested list and the copy % \myhlc|\@@_item_std:w| is executed; otherwise the \emph{real} |\item| of the % environment is executed. % % The environments based on \myhlc|\trivlist|, like \myenv[no-index]{center} or the % theorems, do not increase \myhlc|\@listdepth|. For them the boolean % \myhlc|\l_@@_trivlist_bool| is set to true by a wrapper of % \myhlc|\trivlist|. The assignment is % local to the group of the nested environment, so the boolean is true while % it is open and false again when it is closed, and the switch executes the % copy \myhlc|\@@_item_std:w| in the same way. The boolean is set to false when % the environment starts and after opening each item. % % \begin{important}* % The nested lists inherit \myhlc|\labelwidth| and \myhlc|\labelsep| from the % group in which they are opened, which is the one of the \env{list} that defines % \myenv*[no-index]{enumext*}, where they have the values of the keys % \mykey{labelwidth} and \mykey{labelsep}. Without a correction the label of % \myenv[no-index]{itemize} would be displaced and the space after the label of % \myenv[no-index]{description} and of the theorems would change. The values that % they have before starting the environment are saved in % \myhlc|\l_@@_outer_labelwidth_dim| and \myhlc|\l_@@_outer_labelsep_dim|, and % \myhlc|\@@_nested_reset:| restores them after opening the % \myenv[no-index]{minipage} of the item, or inside the group of an item of % \mykey{item-break}. The nested list is therefore typeset as if it were in a % \myenv[no-index]{minipage} at that point of the document. The other parameters % of the list, like \myhlc|\leftmargin| or \myhlc|\itemindent|, are always set by % the nested list. % \end{important} % % \begin{macro}[int]{\l_@@_base_depth_int, \l_@@_trivlist_bool, % \@@_trivlist_orig:, % \l_@@_outer_labelwidth_dim, \l_@@_outer_labelsep_dim, % \@@_item_switch:N, \@@_item_switch_vii:, % \@@_item_switch_viii:, \@@_nested_save:, \@@_nested_reset:} % First the variables: the depth of lists of the environment, the boolean that % is true inside an environment based on \myhlc|\trivlist| and the values of % \myhlc|\labelwidth| and \myhlc|\labelsep| before starting the environment. % \begin{macrocode} \int_new:N \l_@@_base_depth_int \bool_new:N \l_@@_trivlist_bool \dim_new:N \l_@@_outer_labelwidth_dim \dim_new:N \l_@@_outer_labelsep_dim % \end{macrocode} % The function \myhlc|\@@_item_switch:N| executes the copy of the kernel % |\item| when the depth of lists is greater than the stored one or when the % boolean is true, otherwise it executes the function in its argument, the real % |\item| of the environment. % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_item_switch:N #1 { \bool_lazy_or:nnTF { \int_compare_p:nNn { \@listdepth } > { \l_@@_base_depth_int } } { \l_@@_trivlist_bool } { \@@_item_std:w } { #1 } } % \end{macrocode} % The function \myhlc|\@@_nested_save:| is run before the \env{list} of the % environment is opened and \myhlc|\@@_nested_reset:| is run inside the item, % after the label has been typeset; it stores the depth of lists, sets the % boolean to false and restores the saved values. % \begin{macrocode} \cs_new_protected_nopar:Nn \@@_nested_save: { \dim_set_eq:NN \l_@@_outer_labelwidth_dim \labelwidth \dim_set_eq:NN \l_@@_outer_labelsep_dim \labelsep } \cs_new_protected_nopar:Nn \@@_nested_reset: { \int_set:Nn \l_@@_base_depth_int { \@listdepth } \bool_set_false:N \l_@@_trivlist_bool \dim_set_eq:NN \labelwidth \l_@@_outer_labelwidth_dim \dim_set_eq:NN \labelsep \l_@@_outer_labelsep_dim } % \end{macrocode} % At the beginning of the document \myhlc|\trivlist| is replaced by a version % that runs the original one and then sets the boolean to true, inside the group % of the environment. The \texttt{cmd} hooks of the kernel are not used for this % because the patch of \myhlc|\trivlist| fails when \texttt{PDF} tagging is active, % with the error \texttt{Use of \textbackslash\_\_hook\_make\_prefixes:w % doesn't match its definition}. % \begin{macrocode} \@@_at_begin_document:n { \cs_new_eq:NN \@@_trivlist_orig: \trivlist \cs_set_protected_nopar:Npn \trivlist { \@@_trivlist_orig: \bool_set_true:N \l_@@_trivlist_bool } } % \end{macrocode} % Finally the definition of |\item| in \myenv*[no-index]{enumext*} and % \myenv*[no-index]{keyans*} respectively. % \begin{macrocode} \cs_new_protected_nopar:Nn \@@_item_switch_vii: { \@@_item_switch:N \@@_start_item_tmp_vii: } \cs_new_protected_nopar:Nn \@@_item_switch_viii: { \@@_item_switch:N \@@_start_item_tmp_viii: } % \end{macrocode} % \end{macro} % % \subsubsection{Real definition of \cs{item} in \env{enumext*}} % % The functions \myhlc|\@@_start_item_vii:w| and \myhlc|\@@_stop_item_vii:| executing % the true definition of |\item| inside the \myenv*[no-index]{enumext*} environment, unlike % the implementation in \mypkg[no-index]{shortlst}, no extra group is added % around the \emph{horizontal box} and the plain form of the % \myenv[no-index]{lrbox} environment, that is \myhlc|\hbox_set_to_wd:Nnw| and % \myhlc|\hbox_set_end:|, is used instead of the \env{lrbox} environment. % % \begin{macro}[int]{\@@_start_item_vii:w, \@@_start_item_box_vii:w, \@@_stop_item_vii:} % The function \myhlc|\@@_start_item_vii:w| chooses how the item is built: % if the key \mykey[env]{item-break} is active and the item occupies the % whole row, that is, the number of joined columns is equal to the value of % \mykey[env]{columns} after the adjustments of % \myhlc|\@@_starred_joined_item_vii:n|, it calls % \myhlc|\@@_start_item_break_vii:n| (\S\ref{subsec:item-break-impl}), % otherwise it calls \myhlc|\@@_start_item_box_vii:w|, described next. % % In \myhlc|\@@_start_item_box_vii:w| first the value of \myhlc|\@@_stop_item_tmp_vii:| is set equal to % \myhlc|\@@_stop_item_vii:|, which is defined later; after that it % starts capturing |\item| and \emph{\enquote{item content}} in a \emph{horizontal box} % where the width will be |\itemwidth| plus |\labelwidth| plus |\labelsep|. % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_start_item_vii:w [#1] { \bool_lazy_and:nnTF { \l_@@_item_break_vii_bool } { \int_compare_p:nNn { \l_@@_joined_item_vii_int } = { \l_@@_columns_vii_int } } { \@@_start_item_break_vii:n {#1} } { \@@_start_item_box_vii:w [#1] } } \cs_new_protected_nopar:Npn \@@_start_item_box_vii:w [#1] { \cs_set_eq:NN \@@_stop_item_tmp_vii: \@@_stop_item_vii: \hbox_set_to_wd:Nnw \l_@@_item_text_vii_box { \l_@@_joined_width_vii_dim + \l_@@_labelwidth_vii_dim + \l_@@_labelsep_vii_dim } % \end{macrocode} % Redefine the |\footnote| command. % \begin{macrocode} \@@_renew_footnote_starred: % \end{macrocode} % Now the \emph{sockets} for \emph{tagging} \texttt{PDF} % support are inserted and |\item| is run. % \begin{macrocode} \@@_start_list_tag:n {enumext*} \@@_fake_make_label_vii:n {#1} \@@_stop_start_list_tag: % \end{macrocode} % Finally the \myenv[no-index]{minipage} environment is opened, the % \emph{\enquote{item content}} is captured, \myhlc|\parindent| takes the value of the % key \mykey[env]{listparindent} and \myhlc|\parskip| takes the value of the key % \mykey[env]{parsep}, then the keys \mykey[env]{itemindent} and % \mykey[env]{first} are executed. Inside the \myenv[no-index]{minipage} % |\@listdepth| is reset to zero, so the nesting depth is stored again in % \myhlc|\l_@@_base_depth_int| right after opening it; this allows the % switch (\S\ref{subsec:item-nested}) to recognize standard lists nested in the item. % % \begin{important}* % Here the use of \myhlc|\@@_unskip_unkern:| (run twice) and % \myhlc|\skip_horizontal:n| with the value of \mykey{listparindent} is % necessary, otherwise an unwanted space is created when using % |\item|\myoarg{opt} and the value passed to the key \mykey{itemindent} is % incremented. % \end{important} % % \begin{macrocode} \@@_minipage:w [ t ]{ \l_@@_joined_width_vii_dim } \@@_nested_reset: \dim_set_eq:NN \parindent \l_@@_listparindent_vii_dim \skip_set_eq:NN \parskip \l_@@_parsep_vii_skip \@@_unskip_unkern: \@@_unskip_unkern: \skip_horizontal:n { -\l_@@_listparindent_vii_dim } \ignorespaces \tl_use:N \l_@@_fake_item_indent_vii_tl \tl_use:N \l_@@_after_list_args_vii_tl } % \end{macrocode} % The \myhlc|\@@_stop_item_vii:| function will finish fetching |\item| % and \emph{\enquote{item content}} by closing the \myenv[no-index]{minipage} % environment, the \emph{sockets} for \emph{tagging} \texttt{PDF} and the % \emph{horizontal box}. % \begin{macrocode} \cs_new_protected_nopar:Nn \@@_stop_item_vii: { \@@_endminipage: \@@_stop_list_tag:n {enumext*} \hbox_set_end: % \end{macrocode} % Here the \emph{warnings} are reduced a bit by setting the value % of \myhlc|\hbadness| to \mydim{10000}, print |\item| and \emph{\enquote{item content}} % from the \emph{horizontal box}. % \begin{macrocode} \int_set:Nn \hbadness { 10000 } \box_use_drop:N \l_@@_item_text_vii_box % \end{macrocode} % Finally apply the \emph{vertical space} between rows set by \mykey[env]{itemsep} % key passed to |\parsep| using |\par\noindent| and \emph{horizontal space} % between columns set by \mykey[env]{columns-sep} key using \myhlc|\skip_horizontal:N|. % \begin{macrocode} \int_compare:nNnTF { \l_@@_item_column_pos_vii_int } = { \l_@@_columns_vii_int } { \par\noindent \int_zero:N \l_@@_item_column_pos_vii_int } { \skip_horizontal:N \l_@@_columns_sep_vii_dim } } % \end{macrocode} % \end{macro} % % \subsubsection{Items without \env{minipage}: the \mykey{item-break} key}\label{subsec:item-break-impl} % % \begin{macro}[int]{\@@_start_item_break_vii:n, \@@_stop_item_break_vii:} % When the key \mykey[env]{item-break} is active and the item occupies the % whole row, the \mymeta{content} is NOT captured in a \emph{horizontal box}: % it flows as the text of the list, so it can be broken between pages. The % functions are the equivalent of \myhlc|\@@_start_item_box_vii:w| and % \myhlc|\@@_stop_item_vii:| for this case. % % The \emph{label} is placed at the left of the row with a negative skip and % the lines of the \mymeta{content} are indented by the width of the % \mykey{labelwidth} plus the \mykey{labelsep}. This is done the same way as the % lists do: the width is added to \myhlc|\@totalleftmargin|, subtracted from % \myhlc|\linewidth| and the paragraph shape is set again with \myhlc|\parshape|. % All the assignments to \myhlc|\@totalleftmargin|, \myhlc|\linewidth|, % \myhlc|\parshape|, \myhlc|\parindent| and \myhlc|\parskip| are local to the % group that is opened here and closed in \myhlc|\@@_stop_item_break_vii:| after % the \myhlc|\par| that ends the item. The \emph{sockets} for \emph{tagging} % \texttt{PDF} are the same ones used by the items with box, but since there is % no \myenv[no-index]{minipage} to start the paragraph the marked content of the % text is opened and closed by hand. % % \begin{important}* % The first idea was to make the indentation with \myhlc|\leftskip|, but that is % not safe, because commands such as \myhlc|\centering| or \myhlc|\raggedright| % set it to zero and the indentation is lost. The alternative used here is the % one of the \myenv[no-index]{list} environment, but \myhlc|\@totalleftmargin| % and \myhlc|\linewidth| are internal parameters of the \hologo{LaTeX} kernel and % relying on them is not correct practice, so the code must be reviewed if the % kernel changes them. % The technique of adjusting these parameters, instead of using a surrounding % list, comes from the \mypkg{indent}\cite{indent} package. % \end{important} % % \begin{macrocode} \cs_new_protected_nopar:Nn \@@_start_item_break_vii:n { \cs_set_eq:NN \@@_stop_item_tmp_vii: \@@_stop_item_break_vii: \group_begin: \dim_add:Nn \@totalleftmargin { \l_@@_labelwidth_vii_dim + \l_@@_labelsep_vii_dim } \dim_sub:Nn \linewidth { \l_@@_labelwidth_vii_dim + \l_@@_labelsep_vii_dim } \parshape \c_one_int \@totalleftmargin \linewidth \skip_horizontal:n { -\l_@@_labelwidth_vii_dim - \l_@@_labelsep_vii_dim } \@@_start_list_tag:n {enumext*} \@@_fake_make_label_vii:n {#1} \@@_nested_reset: \@@_stop_start_break_tag: \dim_set_eq:NN \parindent \l_@@_listparindent_vii_dim \skip_set_eq:NN \parskip \l_@@_parsep_vii_skip \tl_use:N \l_@@_fake_item_indent_vii_tl \tl_use:N \l_@@_after_list_args_vii_tl } \cs_new_protected_nopar:Nn \@@_stop_item_break_vii: { \@@_stop_item_break_tag:n {enumext*} \par \group_end: \int_zero:N \l_@@_item_column_pos_vii_int \noindent } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_remove_extra_parsep_vii:} % Remove the extra \emph{vertical space} equal to |\parsep=\itemsep| when the % total number of |\item| is divisible by the number of |\item| in the last % row of the environment. Here the removal of the last \mymeta{skip} with % \myhlc|\@@_unskip_unkern:|, \myhlc|\unskip| or |\removelastskip| does % not obtain the expected result, the extra space remains; the option is to % add a negative \mymeta{skip} with the value of \mykey[env]{itemsep} using % \myhlc|\skip_vertical:n|, the \mypkg*[no-index]{expl3} interface of \myhlc|\vskip|, after % ending the paragraph with \myhlc|\para_end:|, so that \hologo{TeX} is in % \mymeta{vertical mode} and the skip is applied directly to the vertical list. % A zero skip is added after it and, finally, the counter of \emph{all} the % items is reset to zero. % \begin{macrocode} \cs_new_protected:Nn \@@_remove_extra_parsep_vii: { \int_compare:nNnT { \int_mod:nn { \g_@@_item_count_all_vii_int } { \l_@@_columns_vii_int } } = { 0 } { \para_end: \skip_vertical:n { -\l_@@_itemsep_vii_skip } \skip_vertical:N \c_zero_skip \int_gzero:N \g_@@_item_count_all_vii_int } } % \end{macrocode} % \end{macro} % % Since the \mykey{check-ans} check must not be executed by levels % but on the complete list, it is taken out of the \myenv*[no-index]{enumext*} % environment using the \emph{\enquote{hook}} function \myhlc|\@@_after_env:nn|. % \begin{macrocode} \@@_after_env:nn {enumext*} { \@@_execute_after_env: } % \end{macrocode} % % \subsection{The environment \env{keyans*}}\label{env:keyans-starred} % % \begin{macro}{keyans*} % The implementation of \myenv*{keyans*} environment is the % similar as that used by the \myenv*[no-index]{enumext*} environment except for the % \myhlc|\@@_check_starred_cmd:n| function added in the second part. It accepts % an optional \myoarg{key \textnormal{\textcolor{gray}{=}} val} argument in `|#1|' that is processed after checking that the % \mykey[env]{save-ans} key is active and where the environment is running. % \begin{macrocode} \NewDocumentEnvironment{keyans*}{ o } { \@@_safe_exec_viii: \@@_parse_keys_viii:n {#1} \@@_before_list_viii: \@@_nested_save: \@@_start_list:nn { } { \@@_list_arg_two_viii: \@@_before_keys_exec_viii: } \IfDocumentMetadataT { \tag_suspend:n {keyans*} } \@@_starred_columns_set_viii: \item[] \scan_stop: % Set start counter \setcounter { enumXviii } { \int_eval:n { \int_use:c { l_@@_start_viii_int } - 1 } } \cs_set_eq:NN \@@_stop_item_tmp_viii: \@@_first_item_tmp_viii: \cs_set_eq:NN \item \@@_item_switch_viii: \int_set:Nn \l_@@_base_depth_int { \@listdepth } \bool_set_false:N \l_@@_trivlist_bool \ignorespaces } { % {tag=text-unit} \IfDocumentMetadataT { \tag_struct_end:n {tag=semantic-para} } \@@_stop_item_tmp_viii: \@@_remove_extra_parsep_viii: \@@_check_starred_cmd:n { item } \@@_after_list_viii: } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_safe_exec_viii:} % The \myhlc|\@@_safe_exec_viii:| function first checks if the % \mykey[env]{save-ans} key is active; only when this is true is the % environment available. It increments the value of % \myhlc|\l_@@_keyans_level_h_int| and returns an error message when the % environment is nested, then calls the % \myhlc|\@@_keyans_name_and_start:| function in charge of saving the name of % the environment and the line it is running on, then checks if % \myenv*[no-index]{keyans*} is being nested in \myenv*[no-index]{enumext*}, returning an % error, and sets \myhlc|\l_@@_starred_bool| to true; finally it % checks if it is at the appropriate level within the % \myenv*[no-index]{enumext} environment. % \begin{macrocode} \cs_new_protected:Nn \@@_safe_exec_viii: { \bool_lazy_or:nnF { \l_@@_store_active_bool } { \@@_in_keyans_p: } { \msg_error:nnnn { enumext } { wrong-place }{ keyans* }{ save-ans } } \int_incr:N \l_@@_keyans_level_h_int \int_compare:nNnT { \l_@@_keyans_level_h_int } > { 1 } { \msg_error:nn { enumext } { nested } } \@@_keyans_name_and_start: \bool_if:NT \l_@@_starred_bool { \msg_error:nnn { enumext } { nested-horizontal } { enumext* } } \bool_set_true:N \l_@@_starred_bool % Set false for interfering with enumext nested in keyans* % (yes, its possible and crayze) \bool_set_false:N \l_@@_store_active_bool \int_compare:nNnT { \l_@@_level_int } > { 1 } { \msg_error:nn { enumext } { keyans-wrong-level } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_parse_keys_viii:n} % Parse \myoarg{key \textnormal{\textcolor{gray}{=}} val} % for \myenv*[no-index]{keyans*}. % \begin{macrocode} \cs_new_protected:Nn \@@_parse_keys_viii:n { \tl_if_novalue:nF {#1} { \keys_set:nn { enumext / keyans* } {#1} } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_before_list_viii:} % The function \myhlc|\@@_before_list_viii:| will add the vertical % spacing on the environment if the \mykey[env]{above} key is active next to % the \mymarg{code} defined by the \mykey[env]{before*} key if % it is active (function \myhlc|\@@_before_args_exec_viii:|), then call the % function \myhlc|\@@_start_mini_viii:| handled by % \mykey[env]{mini-env}. % \begin{macrocode} \cs_new_protected:Nn \@@_before_list_viii: { \@@_vspace_above_viii: \@@_before_args_exec_viii: \@@_start_mini_viii: } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_after_list_viii:} % The function \myhlc|\@@_after_list_viii:| first calls the function \myhlc|\@@_stop_mini_viii:|, % then apply the \mymarg{code} handled by the \mykey[env,foreachkeyans]{after} key % together with the \emph{vertical space} handled by the \mykey[env]{below} key if % they are present. % \begin{macrocode} \cs_new_protected:Nn \@@_after_list_viii: { \@@_stop_mini_viii: \@@_after_stop_list_viii: \@@_vspace_below_viii: } % \end{macrocode} % \end{macro} % % \subsubsection{The command \cs{item} in \env{keyans*}}\label{cmd:item-keyans-starred} % % The idea here is to make the |\item| command behave in the same way as % in the \myenv*[no-index]{keyans} environment with the difference of the \emph{optional argument} % \myparg{number} which works in the same way as in the \myenv*[no-index]{enumext*} % environment. % % In simple terms, the goal is to store the \mymeta{label} next to the \myoarg{content} if it is present % in the \emph{sequence} and \emph{prop list} defined by \mykey{save-ans} key for % |\item*|, |\item*|\myoarg{content}, |\item|\myparg{number}|*| and % |\item|\myparg{number}|*|\myoarg{content} commands. % % \begin{macro}[int]{\@@_first_item_tmp_viii:} % The \myhlc|\@@_first_item_tmp_viii:| function will remove horizontal space % equal to |\labelwidth| plus |\labelsep| to the left of the \emph{\enquote{first}} % |\item| in the environment at the point of execution of this function, % where it is equal to the \myhlc|\@@_stop_item_tmp_viii:| function inside the % environment body definition. % \begin{macrocode} \cs_new_protected_nopar:Nn \@@_first_item_tmp_viii: { \skip_horizontal:n { -\l_@@_labelwidth_viii_dim - \l_@@_labelsep_viii_dim } \ignorespaces } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_start_item_tmp_viii:, \@@_item_peek_args_viii:, % \@@_joined_item_viii:w, \@@_standard_item_viii:w} % First the function \myhlc|\@@_stop_item_tmp_viii:| is called, which is % redefined later, then the value of % \myhlc|\l_@@_item_column_pos_viii_int|, which counts the items by rows, and % the value of \myhlc|\g_@@_item_count_all_viii_int|, which counts the % total of items in the environment, are incremented. After that the % function \myhlc|\@@_item_peek_args_viii:| is called, which handles the % arguments passed to |\item|. % \begin{macrocode} \cs_new_protected_nopar:Nn \@@_start_item_tmp_viii: { \@@_stop_item_tmp_viii: \int_incr:N \l_@@_item_column_pos_viii_int \int_gincr:N \g_@@_item_count_all_viii_int \@@_item_peek_args_viii: } % \end{macrocode} % The function \myhlc|\@@_item_peek_args_viii:| handles the |\item|\myparg{number}. % It looks for the argument \enquote{\textcolor{star}{\ttfamily (}}; if it is % present, it calls the function \myhlc|\@@_joined_item_viii:w| \myparg{number}, % which is in charge of joining the items in the same row; if it is % not present, it sets the default value \textcolor{gray}{\ttfamily(\mydim{1})}. % \begin{macrocode} \cs_new_protected:Nn \@@_item_peek_args_viii: { \peek_meaning:NTF ( { \@@_joined_item_viii:w } { \@@_joined_item_viii:w (1) } } % \end{macrocode} % The function \myhlc|\@@_joined_item_viii:w| will first call the % function \myhlc|\@@_starred_joined_item_viii:n| in charge of setting the % \emph{width} of the box that stores the content passed to |\item|. Then it % looks for the argument \enquote{\textcolor{star}{\ttfamily *}}; if it is present, it calls the % function \myhlc|\@@_starred_item_viii:w|, otherwise it calls the % function \myhlc|\@@_standard_item_viii:w|. % \begin{macrocode} \cs_new_protected:Npn \@@_joined_item_viii:w (#1) { \@@_starred_joined_item_viii:n {#1} \peek_meaning_remove:NTF * { \@@_starred_item_viii:w } { \@@_standard_item_viii:w } } % \end{macrocode} % The function \myhlc|\@@_standard_item_viii:w| will first look for the % argument `|[|', if present it will set the state of the variable % \myhlc|\l_@@_wrap_label_viii_bool| equal to the state of the variable % \myhlc|\l_@@_wrap_label_opt_viii_bool| handled by the key % \mykey[env]{wrap-label*} and finally execute the \emph{non-enumerated} % version |\item|\myoarg{custom} by means of the function % \myhlc|\@@_start_item_viii:w|; otherwise it sets the value of the % variable \myhlc|\l_@@_wrap_label_viii_bool| handled by the % \mykey[env]{wrap-label} key to true and set the switch |\if@noitemarg| to % true to execute the enumerated version of |\item| by means of the % function \myhlc|\@@_start_item_viii:w| |[| \myhlc|\l_@@_label_viii_tl| |]|. % \begin{macrocode} \cs_new_protected:Npn \@@_standard_item_viii:w { \bool_set_false:N \l_@@_item_starred_viii_bool \bool_set_false:N \l_@@_item_wrap_key_bool \peek_meaning:NTF [ { \bool_set_eq:NN \l_@@_wrap_label_viii_bool \l_@@_wrap_label_opt_viii_bool \@@_start_item_viii:w } { \bool_set_true:N \l_@@_wrap_label_viii_bool \legacy_if_set_true:n { @noitemarg } \@@_start_item_viii:w [ \l_@@_label_viii_tl ] \ignorespaces } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_starred_item_viii:w, \@@_starred_item_viii_aux_i:w, % \@@_starred_item_viii_aux_ii:w, \@@_keyans_starred_item_star:} % The function \myhlc|\@@_starred_item_viii:w| together with the specified % auxiliary functions \myhlc|aux_i:w| and \myhlc|aux_ii:w| execute |\item*| % and |\item*|\myoarg{content}. % \begin{macrocode} \cs_new_protected:Npn \@@_starred_item_viii:w { \bool_set_true:N \l_@@_item_starred_viii_bool \bool_set_true:N \l_@@_item_wrap_key_bool \bool_set_true:N \l_@@_wrap_label_viii_bool \peek_meaning:NTF [ { \@@_starred_item_viii_aux_i:w } { \@@_starred_item_viii_aux_ii:w } } % \end{macrocode} % The function \myhlc|\@@_starred_item_viii_aux_i:w| will save the % \emph{optional argument} to |\item*| in \myhlc|\l_@@_store_current_opt_arg_tl| % and will save this argument along with the spacing set by the key \mykey[env]{save-sep} in % variable \myhlc|\l_@@_store_current_label_tl| if present, then call the % function \myhlc|\@@_starred_item_viii_aux_ii:w|. % \begin{macrocode} \cs_new_protected:Npn \@@_starred_item_viii_aux_i:w [#1] { \tl_clear:N \l_@@_store_current_label_tl \tl_if_novalue:nF {#1} { \tl_if_empty:NF \l_@@_store_keyans_item_opt_sep_viii_tl { \tl_put_right:NV \l_@@_store_current_label_tl \l_@@_store_keyans_item_opt_sep_viii_tl \tl_put_right:Nn \l_@@_store_current_label_tl {#1} } \tl_set:Nn \l_@@_store_current_opt_arg_tl {#1} } \@@_starred_item_viii_aux_ii:w } \cs_new_protected:Npn \@@_starred_item_viii_aux_ii:w { \legacy_if_set_true:n { @noitemarg } \@@_start_item_viii:w [ \l_@@_label_viii_tl ] \ignorespaces } % \end{macrocode} % The function \myhlc|\@@_keyans_starred_item_star:| will be in charge of storing % the current \mymeta{label} for |\item*| followed by the % \myoarg{content} for |\item*|\myoarg{content} if % present in the \emph{sequence} and \emph{prop list} set by the % \mykey[env]{save-ans} key. In this same function the keys \mykey[env]{show-ans}, % \mykey[env]{show-pos}, \mykey[env]{mark-sep} and \mykey[env]{save-ref} are implemented. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_starred_item_star: { \tl_put_left:Ne \l_@@_store_current_label_tl { \l_@@_label_viii_tl } \@@_store_addto_prop:V \l_@@_store_current_label_tl \@@_keyans_store_ref: \tl_put_left:Nn \l_@@_store_current_label_tl { \item } \@@_keyans_addto_seq_link: \int_gincr:N \g_@@_check_starred_cmd_int \dim_compare:nNnT { \l_@@_mark_sym_sep_viii_dim } = { \c_zero_dim } { \dim_set:Nn \l_@@_mark_sym_sep_viii_dim { \l_@@_labelsep_viii_dim } } \bool_if:NT \l_@@_show_answer_bool { \tl_set_eq:NN \l_@@_mark_answer_sym_tl \l_@@_mark_answer_sym_viii_tl \str_set_eq:NN \l_@@_mark_position_str \l_@@_mark_position_viii_str \@@_print_keyans_box:NN \l_@@_labelwidth_viii_dim \l_@@_mark_sym_sep_viii_dim } \bool_if:NT \l_@@_show_position_bool { \tl_set:Ne \l_@@_mark_answer_sym_tl { \group_begin: \exp_not:N \normalfont \exp_not:N \footnotesize [ \int_eval:n { \prop_count:c { g_@@_ \l_@@_store_name_tl _prop } } ] \group_end: } \str_set_eq:NN \l_@@_mark_position_str \l_@@_mark_position_viii_str \@@_print_keyans_box:NN \l_@@_labelwidth_viii_dim \l_@@_mark_sym_sep_viii_dim } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_keyans_wrapper_label_viii:n, \@@_fake_make_label_viii:n, % \@@_wrapper_label_viii:n} % The implementation at this point is very similar to that of the % \myenv*[no-index]{enumext*} environment. % \begin{macrocode} \cs_new_protected:Nn \@@_keyans_wrapper_label_viii:n { \bool_lazy_all:nT { { \bool_if_p:N \l_@@_wrap_label_viii_bool } { \bool_if_p:N \l_@@_show_answer_bool } { \bool_if_p:N \l_@@_item_wrap_key_bool } { \cs_if_exist_p:N \@@_keyans_wrapper_item_viii:n } } { \cs_set_eq:NN \@@_wrapper_label_viii:n \@@_keyans_wrapper_item_viii:n } \bool_if:NTF \l_@@_wrap_label_viii_bool { \@@_wrapper_label_viii:n {#1} } {#1} } \cs_new_protected_nopar:Nn \@@_fake_make_label_viii:n { \legacy_if:nT { @noitemarg } { \legacy_if_set_false:n { @noitemarg } \legacy_if:nT { @nmbrlist } { \IfDocumentMetadataT { \bool_if:NT \l_@@_hyperref_bool { \legacy_if_set_true:n { @hyper@item } } } \refstepcounter{enumXviii} } } \bool_if:NT \l_@@_item_starred_viii_bool { \@@_keyans_starred_item_star: } \makebox[ \l_@@_labelwidth_viii_dim ][ \l_@@_align_label_viii_str ] { \tl_use:N \l_@@_label_font_style_viii_tl \@@_keyans_wrapper_label_viii:n {#1} } \skip_horizontal:N \l_@@_labelsep_viii_dim \ignorespaces } % \end{macrocode} % \end{macro} % % \subsubsection{Real definition of \cs{item} in \env{keyans*}} % % \begin{macro}[int]{\@@_start_item_viii:w, \@@_start_item_box_viii:w, \@@_stop_item_viii:} % The implementation at this point is very similar to that of the % \myenv*[no-index]{enumext*} environment; the function % \myhlc|\@@_start_item_viii:w| chooses between % \myhlc|\@@_start_item_break_viii:n| and \myhlc|\@@_start_item_box_viii:w| % in the same way. % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_start_item_viii:w [#1] { \bool_lazy_and:nnTF { \l_@@_item_break_viii_bool } { \int_compare_p:nNn { \l_@@_joined_item_viii_int } = { \l_@@_columns_viii_int } } { \@@_start_item_break_viii:n {#1} } { \@@_start_item_box_viii:w [#1] } } \cs_new_protected_nopar:Npn \@@_start_item_box_viii:w [#1] { \cs_set_eq:NN \@@_stop_item_tmp_viii: \@@_stop_item_viii: \hbox_set_to_wd:Nnw \l_@@_item_text_viii_box { \l_@@_joined_width_viii_dim + \l_@@_labelwidth_viii_dim + \l_@@_labelsep_viii_dim } \@@_renew_footnote_starred: \@@_start_list_tag:n {keyans*} \@@_fake_make_label_viii:n {#1} \@@_stop_start_list_tag: \@@_minipage:w [ t ]{ \l_@@_joined_width_viii_dim } \@@_nested_reset: \dim_set_eq:NN \parindent \l_@@_listparindent_viii_dim \skip_set_eq:NN \parskip \l_@@_parsep_viii_skip \@@_unskip_unkern: \@@_unskip_unkern: \skip_horizontal:n { -\l_@@_listparindent_viii_dim } \ignorespaces \tl_use:N \l_@@_fake_item_indent_viii_tl \bool_if:NT \l_@@_item_starred_viii_bool { \@@_keyans_show_item_opt_viii: } \tl_use:N \l_@@_after_list_args_viii_tl } \cs_new_protected_nopar:Nn \@@_stop_item_viii: { \@@_endminipage: \@@_stop_list_tag:n {keyans*} \hbox_set_end: \int_set:Nn \hbadness { 10000 } \box_use_drop:N \l_@@_item_text_viii_box \int_compare:nNnTF { \l_@@_item_column_pos_viii_int } = { \l_@@_columns_viii_int } { \par\noindent \int_zero:N \l_@@_item_column_pos_viii_int } { \skip_horizontal:N \l_@@_columns_sep_viii_dim } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_start_item_break_viii:n, \@@_stop_item_break_viii:} % Same implementation as \myhlc|\@@_start_item_break_vii:n| and % \myhlc|\@@_stop_item_break_vii:| for the \myenv*[no-index]{keyans*} environment. % The item option shown by \myhlc|\item*| is placed at the beginning of the % \mymeta{content}. % \begin{macrocode} \cs_new_protected_nopar:Nn \@@_start_item_break_viii:n { \cs_set_eq:NN \@@_stop_item_tmp_viii: \@@_stop_item_break_viii: \group_begin: \dim_add:Nn \@totalleftmargin { \l_@@_labelwidth_viii_dim + \l_@@_labelsep_viii_dim } \dim_sub:Nn \linewidth { \l_@@_labelwidth_viii_dim + \l_@@_labelsep_viii_dim } \parshape \c_one_int \@totalleftmargin \linewidth \skip_horizontal:n { -\l_@@_labelwidth_viii_dim - \l_@@_labelsep_viii_dim } \@@_start_list_tag:n {keyans*} \@@_fake_make_label_viii:n {#1} \@@_nested_reset: \@@_stop_start_break_tag: \dim_set_eq:NN \parindent \l_@@_listparindent_viii_dim \skip_set_eq:NN \parskip \l_@@_parsep_viii_skip \tl_use:N \l_@@_fake_item_indent_viii_tl \bool_if:NT \l_@@_item_starred_viii_bool { \@@_keyans_show_item_opt_viii: } \tl_use:N \l_@@_after_list_args_viii_tl } \cs_new_protected_nopar:Nn \@@_stop_item_break_viii: { \@@_stop_item_break_tag:n {keyans*} \par \group_end: \int_zero:N \l_@@_item_column_pos_viii_int \noindent } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_remove_extra_parsep_viii:} % The implementation at this point is very similar to that of the % \myenv*[no-index]{enumext*} environment. % \begin{macrocode} \cs_new_protected:Nn \@@_remove_extra_parsep_viii: { \int_compare:nNnT { \int_mod:nn { \g_@@_item_count_all_viii_int } { \l_@@_columns_viii_int } } = { 0 } { \para_end: \skip_vertical:n { -\l_@@_itemsep_viii_skip } \skip_vertical:N \c_zero_skip \int_gzero:N \g_@@_item_count_all_viii_int } } % \end{macrocode} % \end{macro} % % \subsection{The command \cs{getkeyans}}\label{cmd:getkeyans} % % \subsubsection{Definition of error messages for \cs[no-index]{getkeyans}} % % \begin{macro}[int]{missing-colon} % Message used by |\getkeyans| command. % \begin{macrocode} \msg_new:nnnn { enumext } { missing-colon } { The~argument~'#1'~has~no~colon~\msg_line_context:. } { The~argument~of~'\token_to_str:N \getkeyans'~must~have~the~form~ 'store~name:position'. } % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions for \cs[no-index]{getkeyans}} % % \begin{macro}[int]{\@@_getkeyans_aux:n, \@@_getkeyans:nn} % The internal function \myhlc|\@@_getkeyans_aux:n| is in charge of % \emph{splitting} the \emph{mandatory argument} using \enquote{\textcolor{red}{:}}. % If \enquote{\textcolor{red}{:}} is omitted it will return an error. % \begin{macrocode} \cs_new_protected:Nn \@@_getkeyans_aux:n { \str_if_in:nnTF {#1} { : } { \use:e { \cs_set:Npn \exp_not:N \@@_tmp:w ##1 \c_colon_str ##2 \scan_stop: { {##1} {##2} } } \exp_after:w \@@_getkeyans:nn \@@_tmp:w #1 \scan_stop: } { \msg_error:nnn { enumext } { missing-colon } {#1} } } % \end{macrocode} % The internal function \myhlc|\@@_getkeyans:nn| will check for the existence % of the \emph{prop list}, if it does not exist it will return an error % message, then it will fetch the content specified by the \emph{second argument} % from \emph{prop list}. % \begin{macrocode} \cs_new_protected:Nn \@@_getkeyans:nn { \prop_if_exist:cTF { g_@@_ #1 _prop } { \prop_item:cn { g_@@_ #1 _prop }{#2} } { \msg_error:nnn { enumext } { undefined-storage-anskey } {#1} } } % \end{macrocode} % \end{macro} % % \begin{macro}{\getkeyans} % The \ics*{getkeyans} command takes a \emph{mandatory argument} of the % form \mymarg{store name \textcolor{red}{:} position} in `|#1|'. The argument % is expanded and converted to a string before it is processed. % Retrieve a \emph{\enquote{single content}} stored by |\anskey|, |\anspic*| % and |\item*| and \myenv*[no-index]{anskey*} from \emph{prop list} defined by \mykey[env]{save-ans} key. % \begin{macrocode} \NewDocumentCommand \getkeyans { m } { \exp_args:Ne \@@_getkeyans_aux:n { \tl_to_str:e { \text_expand:n {#1} } } } % \end{macrocode} % \end{macro} % % \subsection{The command \cs{printkeyans}}\label{cmd:printkeyans} % % The |\printkeyans| command prints \emph{\enquote{all stored % content}} in the \emph{sequence} defined by the \mykey{save-ans} key. % % \subsubsection{Definition of variables for \cs[no-index]{printkeyans}} % % \begin{variable}[int]{\c_@@_print_envs_clist, \c_@@_default_vars_clist, % \c_@@_default_label_X_tl} % The command \ics*{printkeyans} must not depend on the values that % \ics*{setenumext} sets for the environments, so the default values of the % package are saved when it is loaded. The constant % \myhlc|\c_@@_print_envs_clist| lists the environments that % \ics*{printkeyans} can open and the constant % \myhlc|\c_@@_default_vars_clist| lists, as pairs \mymeta{name}\mymeta{type}, % the local variables of each environment whose default value is saved. Each % value is saved in a global variable with the same name as the local one, but % starting with \myhlc|\g_@@_default_| instead of \myhlc|\l_@@_|, for example % \myhlc|\g_@@_default_labelsep_ii_dim| for \myhlc|\l_@@_labelsep_ii_dim|. % The default \mymeta{label} is saved by the \mykey[env]{label} key in % \myhlc|\c_@@_default_label_X_tl|. % \begin{macrocode} \clist_const:Nn \c_@@_print_envs_clist { {level-1}{i}, {level-2}{ii}, {level-3}{iii}, {level-4}{iv}, {enumext*}{vii} } \clist_const:Nn \c_@@_default_vars_clist { {labelsep}{dim}, {labelwidth}{dim}, {fake_item_indent}{dim}, {listoffset}{dim}, {rightmargin}{dim}, {listparindent}{dim}, {leftmargin_tmp}{dim}, {leftmargin_tmp}{bool}, {columns_sep}{dim}, {minipage_hsep}{dim}, {topsep}{skip}, {partopsep}{skip}, {parsep}{skip}, {itemsep}{skip}, {columns}{int}, {start}{int}, {beginparpenalty}{int}, {itempenalty}{int}, {endparpenalty}{int}, {label_fill_left}{tl}, {label_fill_right}{tl}, {align_label_pos}{str}, {label_font_style}{tl}, {after_list_args}{tl}, {wrap_label_opt}{bool}, {item_break}{bool} } % \end{macrocode} % \end{variable} % % \begin{variable}[int]{\l_@@_print_keyans_starred_tl} % The token list \myhlc|\l_@@_print_keyans_starred_tl| is used by the % command \ics*{printkeyans} (\S\ref{cmd:printkeyans}). % \begin{macrocode} \tl_new:N \l_@@_print_keyans_starred_tl % \end{macrocode} % \end{variable} % % \subsubsection{Definition of error messages for \cs[no-index]{printkeyans}} % % \begin{macro}[int]{print-starred} % Messages used by |\printkeyans*| command. % \begin{macrocode} \msg_new:nnnn { enumext } { print-starred } { '\token_to_str:N \printkeyans*':~The~sequence~'#1'~already~contains~ #2~environment~\msg_line_context:. } { '\token_to_str:N \printkeyans*'~opens~'enumext*';~use~ '\token_to_str:N \printkeyans'~without~the~star. } % \end{macrocode} % \end{macro} % % \subsubsection{Definition of keys for \cs[no-index]{printkeyans}} % % \begin{macro}[int]{print*, print-*, print-1, print-2, print-3, print-4} % First a set of \mymeta{filtered keys} is defined, with % which the options of the different nesting levels are controlled for % the environments \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} by storing their % values in the list of tokens \myhlc|\l_@@_print_keyans_X_tl|. % % The default values only contain what the printed content changes with respect % to the default values of the package: \mykey[env]{nosep}, \mykey[env]{first} and % \mykey[env]{font}, plus \mykey[env]{columns} for the \emph{\enquote{first level}}. % The remaining values are restored by the function \myhlc|\@@_default_restore:| % before these \mymeta{keys} are run (\S\ref{cmd:printkeyans}). % % The variable \myhlc|\l_@@_print_keyans_starred_tl| will have the default \mymeta{keys} % for \ics*{printkeyans*} and will be set by |\setenumext|\myoarg{print\textnormal{\textcolor{star}{\texttt{*}}}} % and the variable \myhlc|\l_@@_print_keyans_vii_tl| will have the default % keys for the environment \myenv*[no-index]{enumext*} nested within the \emph{sequence} % and will be set by |\setenumext|\myoarg{print \textnormal{\textcolor{gray}{,}}\textnormal{\textcolor{star}{\texttt{*}}}}, % the rest of the variables will be for the environment \myenv*[no-index]{enumext} and will be set % by |\setenumext|\myoarg{print \textnormal{\textcolor{gray}{,}} level}. % % \begin{macrocode} \keys_define:nn { enumext / print } { print* .code:n = { \keys_precompile:neN { enumext / enumext* } { \@@_filter_save_key:n {#1} } \l_@@_print_keyans_starred_tl }, % starred cmd print* .initial:n = { nosep, columns = 2, first = \small, font = \small }, print-1 .code:n = { \keys_precompile:neN { enumext / level-1 } { \@@_filter_save_key:n {#1} } \l_@@_print_keyans_i_tl }, print-1 .initial:n = { nosep, columns = 2, first = \small, font = \small }, print-2 .code:n = { \keys_precompile:neN { enumext / level-2 } { \@@_filter_save_key:n {#1} } \l_@@_print_keyans_ii_tl }, print-2 .initial:n = { nosep, first = \small, font = \small }, print-3 .code:n = { \keys_precompile:neN { enumext / level-3 } { \@@_filter_save_key:n {#1} } \l_@@_print_keyans_iii_tl }, print-3 .initial:n = { nosep, first = \small, font = \small }, print-4 .code:n = { \keys_precompile:neN { enumext / level-4 } { \@@_filter_save_key:n {#1} } \l_@@_print_keyans_iv_tl }, print-4 .initial:n = { nosep, first = \small, font = \small }, print-* .code:n = { \keys_precompile:neN { enumext / enumext* } { \@@_filter_save_key:n {#1} } \l_@@_print_keyans_vii_tl }, % starred nested print-* .initial:n = { nosep, first = \small, font = \small }, } % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions for \cs[no-index]{printkeyans}} % % \begin{macro}[int]{\@@_default_save:nnn, \@@_default_restore:nnn, % \@@_default_save_env:nn, \@@_default_restore_env:nn, % \@@_default_restore:} % The function \myhlc|\@@_default_save:nnn| saves the value of a local variable, % if it exists, in the global variable with the same name that starts with % \myhlc|\g_@@_default_|, and the function \myhlc|\@@_default_restore:nnn| % copies it back. % \begin{macrocode} \cs_new_protected:Nn \@@_default_save:nnn { \cs_if_exist:cT { l_@@_ #1 _ #3 _ #2 } { \use:c { #2 _new:c } { g_@@_default_ #1 _ #3 _ #2 } \use:c { #2 _gset_eq:cc } { g_@@_default_ #1 _ #3 _ #2 } { l_@@_ #1 _ #3 _ #2 } } } \cs_new_protected:Nn \@@_default_restore:nnn { \cs_if_exist:cT { g_@@_default_ #1 _ #3 _ #2 } { \use:c { #2 _set_eq:cc } { l_@@_ #1 _ #3 _ #2 } { g_@@_default_ #1 _ #3 _ #2 } } } % \end{macrocode} % The function \myhlc|\@@_default_save_env:nn| saves all the variables of % \myhlc|\c_@@_default_vars_clist| for one environment, together with the % function of the \mykey[env]{wrap-label} key. The function % \myhlc|\@@_default_restore_env:nn| restores them and runs the % \mykey[env]{label} key with the saved \mymeta{label}, since this key also % defines the counter style and the width of the label. % \begin{macrocode} \cs_new_protected:Nn \@@_default_save_env:nn { \clist_map_inline:Nn \c_@@_default_vars_clist { \@@_default_save:nnn ##1 {#2} } \cs_gset_eq:cc { @@_default_wrapper_label_ #2 :n } { @@_wrapper_label_ #2 :n } } \cs_new_protected:Nn \@@_default_restore_env:nn { \clist_map_inline:Nn \c_@@_default_vars_clist { \@@_default_restore:nnn ##1 {#2} } \cs_set_eq:cc { @@_wrapper_label_ #2 :n } { @@_default_wrapper_label_ #2 :n } \keys_set:ne { enumext / #1 } { label = { \exp_not:v { c_@@_default_label_ #2 _tl } } } } % \end{macrocode} % Finally the function \myhlc|\@@_default_restore:| restores, for all the % environments, the values saved when the package was loaded. % \begin{macrocode} \cs_new_protected:Nn \@@_default_restore: { \clist_map_inline:Nn \c_@@_print_envs_clist { \@@_default_restore_env:nn ##1 } } \clist_map_inline:Nn \c_@@_print_envs_clist { \@@_default_save_env:nn #1 } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_printkeyans:nnn} % The internal function \myhlc|\@@_printkeyans:nnn| will check % for the existence of the \emph{sequence}, if it does not exist % it will return an error message, then it will check if not empty. % \begin{macrocode} \cs_new_protected:Nn \@@_printkeyans:nnn { \seq_if_exist:cTF { g_@@_ #3 _seq } { \seq_if_empty:cF { g_@@_ #3 _seq } { % \end{macrocode} % If the \emph{starred argument} `|*|' is present, it checks that % the environment \myenv*[no-index]{enumext*} is not saved in the \emph{sequence}, % then executes the variable \myhlc|\l_@@_print_keyans_starred_tl| that % contains the default \mymeta{keys} for the environment \myenv*[no-index]{enumext*}, % sets \myhlc|\l_@@_base_line_fix_bool| and \myhlc|\l_@@_print_keyans_star_bool| % to true for \emph{baseline correction}, opens the \myenv*[no-index]{enumext*} % environment passing the \emph{optional argument} and maps the \emph{sequence}, % then sets \myhlc|\l_@@_base_line_fix_bool| and \myhlc|\l_@@_print_keyans_star_bool| % to false. % \begin{macrocode} \bool_if:nTF {#1} { \seq_if_in:cnTF { g_@@_ #3 _seq } { \end{enumext*} } { \msg_error:nnnn { enumext } { print-starred } {#3} { enumext* } } { \tl_use:N \l_@@_print_keyans_starred_tl \bool_set_true:N \l_@@_base_line_fix_bool \bool_set_true:N \l_@@_print_keyans_star_bool \begin{enumext*}[#2] \seq_map_inline:cn { g_@@_ #3 _seq } {##1} \end{enumext*} \bool_set_false:N \l_@@_base_line_fix_bool \bool_set_false:N \l_@@_print_keyans_star_bool } } % \end{macrocode} % Otherwise it will open the environment \myenv*[no-index]{enumext} passing % the \emph{optional argument} to the \emph{\enquote{first level}} % then map the \emph{sequence}. % \begin{macrocode} { \begin{enumext}[#2] \seq_map_inline:cn { g_@@_ #3 _seq } {##1} \end{enumext} } } } { \msg_error:nnn { enumext } { undefined-storage-anskey } {#3} } } % \end{macrocode} % \end{macro} % % \begin{macro}{\printkeyans} % The command accepts a \emph{starred argument} `|*|' in `|#1|', an optional % \myoarg{key \textnormal{\textcolor{gray}{=}} val} in `|#2|' and a mandatory \mymarg{store name} in `|#3|'. % Create a user command to print \emph{\enquote{all stored content}} % in \emph{sequence} for |\anskey|, \myenv*[no-index]{anskey*}, |\item*| and |\anspic*|. % Within a group the default values saved when the package was loaded are % restored, then the \emph{\enquote{precompiled keys}} are run and finally the % stored content is printed. % \begin{macrocode} \NewDocumentCommand \printkeyans { s O{} m } { \group_begin: \@@_default_restore: \bool_set_true:N \l_@@_print_keyans_cmd_bool \tl_use:N \l_@@_print_keyans_i_tl \tl_use:N \l_@@_print_keyans_ii_tl \tl_use:N \l_@@_print_keyans_iii_tl \tl_use:N \l_@@_print_keyans_iv_tl \tl_use:N \l_@@_print_keyans_vii_tl \@@_printkeyans:nnn {#1} {#2} {#3} \bool_set_false:N \l_@@_print_keyans_cmd_bool \group_end: } % \end{macrocode} % \end{macro} % % \begin{important}* % The reason for storing \mymeta{keys} in token lists using % \cs{keys_precompile:neN} is because the keys are set via % |\setenumext| but are later executed by running the command % |\printkeyans| and they are not handled directly by its % \emph{optional argument}, except those related to the \emph{first} % opening level. % \end{important} % % \subsection{The command \cs{setenumext}}\label{cmd:setenumext} % % The command |\setenumext| is in charge of managing the % \mymeta{keys} passed to all environments and to the |\printkeyans| % command. Precautions must be taken with the \myenv*[no-index]{enumext*} and \myenv*[no-index]{enumext} % environments so as not to capture \mymeta{keys} that cause problems. % % \subsubsection{Definition of variables for \cs[no-index]{setenumext}} % % \begin{variable}[int]{ % \l_@@_setkey_tmpa_tl, % \l_@@_setkey_tmpb_tl, % \l_@@_setkey_tmpa_int, % \l_@@_setkey_tmpa_seq, % \l_@@_setkey_tmpb_seq, % } % Internal variables used by the command |\setenumext| (\S\ref{cmd:setenumext}). % \begin{macrocode} \tl_new:N \l_@@_setkey_tmpa_tl \tl_new:N \l_@@_setkey_tmpb_tl \int_new:N \l_@@_setkey_tmpa_int \seq_new:N \l_@@_setkey_tmpa_seq \seq_new:N \l_@@_setkey_tmpb_seq % \end{macrocode} % \end{variable} % % \subsubsection{Definition of error messages for \cs[no-index]{setenumext}} % % \begin{macro}[int]{invalid-level, unknown-key-family} % Messages used by the |\setenumext| command. % \begin{macrocode} \msg_new:nnnn { enumext } { invalid-level } { The~level~'#1'~is~not~valid~\msg_line_context:. } { The~optional~argument~must~be~a~family~followed~by~the~levels~ 1,~2,~3,~4~or~'*',~for~example~'print,1'. } \msg_new:nnnn { enumext } { unknown-key-family } { Unknown~key~family~'\l_keys_key_str'~for~enumext~\msg_line_context:. } { The~first~element~of~the~optional~argument~must~be~ 'enumext',~'enumext*',~'keyans',~'keyans*'~or~'print'. } % \end{macrocode} % \end{macro} % % \subsubsection{Definition of keys for \cs[no-index]{setenumext}} % % \begin{macro}[int]{enumext-1, enumext-2, enumext-3, enumext-4, enumext*, % keyans, keyans*, print*, print-1, print-2, print-3, % print-4, print-*, unknown} % Now define a \emph{\enquote{meta families}} of \mymeta{keys} % to access from |\setenumext|. % % \begin{macrocode} \keys_define:nn { enumext / meta-families } { enumext-1 .code:n = { \keys_set:ne { enumext / level-1 } { \@@_filter_level:n {#1} } }, enumext-2 .code:n = { \keys_set:ne { enumext / level-2 } { \@@_filter_level:n {#1} } }, enumext-3 .code:n = { \keys_set:ne { enumext / level-3 } { \@@_filter_level:n {#1} } }, enumext-4 .code:n = { \keys_set:ne { enumext / level-4 } { \@@_filter_level:n {#1} } }, enumext* .code:n = { \keys_set:ne { enumext / enumext* } { \@@_filter_level:n {#1} } }, keyans .meta:nn = { enumext / keyans } {#1}, keyans* .meta:nn = { enumext / keyans* } {#1}, print* .meta:nn = { enumext / print } { print* = {#1} }, print-1 .meta:nn = { enumext / print } { print-1 = {#1} }, print-2 .meta:nn = { enumext / print } { print-2 = {#1} }, print-3 .meta:nn = { enumext / print } { print-3 = {#1} }, print-4 .meta:nn = { enumext / print } { print-4 = {#1} }, print-* .meta:nn = { enumext / print } { print-* = {#1} }, unknown .code:n = { \msg_error:nn { enumext } { unknown-key-family } }, } % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions for \cs[no-index]{setenumext}} % % \begin{macro}[int]{\@@_filter_level:n, \@@_filter_level_key:n, % \@@_filter_level_pair:nn} % The function \myhlc|\@@_filter_level:n| will be in charge of % filtering the \mymeta{keys} passed to the \myenv*[no-index]{enumext} % and \myenv*[no-index]{enumext*} environments. % \begin{macrocode} \cs_new:Nn \@@_filter_level:n { \use:e { \keyval_parse:NNn \@@_filter_level_key:n \@@_filter_level_pair:nn {#1} } } % \end{macrocode} % The function \myhlc|\@@_filter_level_key:n| will be responsible for % filtering the \mymeta{keys} that are passed \emph{\enquote{without value}} by % excluding the keys \mykey[env]{resume*}, \mykey[env]{reset} and \mykey[env]{reset*} % passed to the \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} environments. % \begin{macrocode} \cs_new:Nn \@@_filter_level_key:n { \str_case:nnF {#1} { { resume* } { } { reset } { } { reset* } { } } { , { \exp_not:n {#1} } } } % \end{macrocode} % The function \myhlc|\@@_filter_level_pair:nn| will be responsible for % filtering the \mymeta{keys} that are passed \emph{\enquote{with value}} by % excluding the \mykey[env]{series}, \mykey[env]{resume} and \mykey[env]{save-ans} keys % passed to the \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} environments. % \begin{macrocode} \cs_new:Nn \@@_filter_level_pair:nn { \str_case:nnF {#1} { { series } { } { save-ans } { } { resume } { } } { , { \exp_not:n {#1} } = { \exp_not:n {#2} } } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_set_parse:n, \@@_set_error:n} % Internal functions used by the |\setenumext| command. % \begin{macrocode} \cs_new_protected:Nn \@@_set_parse:n { \tl_set:Ne \l_@@_setkey_tmpb_tl { \tl_trim_spaces:n {#1} } \clist_map_inline:nn { 0, 1, 2, 3, 4, * } % <- max level { \tl_remove_all:Nn \l_@@_setkey_tmpb_tl {##1} } \tl_if_empty:NTF \l_@@_setkey_tmpb_tl { \seq_put_right:Ne \l_@@_setkey_tmpa_seq { \tl_trim_spaces:n {#1} } } { \@@_set_error:n {#1} } } \cs_new_protected:Nn \@@_set_error:n { \msg_error:nnn { enumext } { invalid-level } {#1} } % \end{macrocode} % \end{macro} % % \begin{macro}{\setenumext} % Defines the user command \ics*{setenumext}. It accepts an optional argument % in `|#1|' that selects the environments and levels, with default value % |enumext,1|, and a mandatory \myoarg{key \textnormal{\textcolor{gray}{=}} val} argument in `|#2|'. The optional % argument is split into the families to be modified and the \mymeta{keys} are % passed to each one of them. % \begin{macrocode} \NewDocumentCommand \setenumext { O{enumext,1} +m } { \seq_clear:N \l_@@_setkey_tmpa_seq \seq_set_from_clist:Nn \l_@@_setkey_tmpb_seq {#1} \int_set:Nn \l_@@_setkey_tmpa_int { \seq_count:N \l_@@_setkey_tmpb_seq } \int_compare:nNnTF { \l_@@_setkey_tmpa_int } > { 1 } { \seq_pop_left:NN \l_@@_setkey_tmpb_seq \l_@@_setkey_tmpa_tl \seq_map_function:NN \l_@@_setkey_tmpb_seq \@@_set_parse:n \seq_set_map_e:NNn \l_@@_setkey_tmpa_seq \l_@@_setkey_tmpa_seq { \tl_use:N \l_@@_setkey_tmpa_tl - ##1 } } { \seq_put_right:Ne \l_@@_setkey_tmpa_seq { \tl_trim_spaces:n {#1} } } \seq_map_inline:Nn \l_@@_setkey_tmpa_seq { \keys_set:nn { enumext / meta-families } { ##1 = {#2} } } } % \end{macrocode} % \end{macro} % % \subsection{The command \cs{setenumextmeta}}\label{cmd:setenumextmeta} % % The command \ics*{setenumextmeta} will be responsible for adding new % \emph{\enquote{meta-keys}} for the \myenv*[no-index]{enumext} and \myenv*[no-index]{enumext*} environments. % The implementation code was given by Jonathan P. Spratte (\texttt{@Skillmon}) % answer in \href{https://tex.stackexchange.com/a/747159}{Simplify syntax for command that adds \texttt{.meta} key to existing keys (l3keys)}. % % \subsubsection{Definition of variables for \cs[no-index]{setenumextmeta}} % % \begin{variable}[int]{\l_@@_meta_path_str} % The string \myhlc|\l_@@_meta_path_str| is used by the |\setenumextmeta| % command (\S\ref{cmd:setenumextmeta}). % \begin{macrocode} \str_new:N \l_@@_meta_path_str % \end{macrocode} % \end{variable} % % \subsubsection{Definition of error messages for \cs[no-index]{setenumextmeta}} % % \begin{macro}[int]{already-defined, prohibited-unknown} % Messages used by |\setenumextmeta| command. % \begin{macrocode} \msg_new:nnnn { enumext } { already-defined } { The~key~'#1'~is~already~defined~\msg_line_context:. } { Choose~another~name~for~the~meta~key. } \msg_new:nnnn { enumext } { prohibited-unknown } { The~name~'unknown'~can't~be~chosen~for~a~meta~key~\msg_line_context:. } { 'unknown'~is~reserved~by~the~package;~choose~another~name. } % \end{macrocode} % \end{macro} % % \subsubsection{Definition of keys for \cs[no-index]{setenumextmeta}} % % \begin{macro}[int]{enumext, enumext*} % These \mymeta{keys} are the selectors that can be passed in the \emph{optional argument} % of |\setenumextmeta| (\S\ref{cmd:setenumextmeta}) and |\setenumext| (\S\ref{cmd:setenumext}). % First, the selectors for each level, |1|, |2|, |3| and |4|, of type \myhlc|.code:n| % are created for \emph{\enquote{all levels}} of the \myenv*[no-index]{enumext} environment. % \begin{macrocode} \int_step_inline:nn { 4 } { \keys_define:nn { enumext } { #1 .code:n = { \str_set:Nn \l_@@_meta_path_str { level-#1 } }, #1 .value_forbidden:n = true, } } % \end{macrocode} % And now the \mymeta{keys} are defined for the environments using % \myhlc|.code:n| for the \myenv*[no-index]{enumext} environment and \myhlc|.meta:n| for the % \myenv*[no-index]{enumext*} environment. % \begin{macrocode} \clist_map_inline:nn { enumext } { \keys_define:nn { enumext } { % ignored for now, might do something useful in the future #1 .code:n = { }, #1 .value_forbidden:n = true, #1* .code:n = { \str_set:Nn \l_@@_meta_path_str { #1* } }, #1* .value_forbidden:n = true, } } \keys_define:nn { enumext } { * .meta:n = enumext*, * .value_forbidden:n = true, } % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions for \cs[no-index]{setenumextmeta}} % % \begin{macro}[int]{\@@_key_set_meta:nnn, \@@_key_def_meta:nnn, % \@@_key_def_meta:Vnn} % The internal functions \myhlc|\@@_key_set_meta:nnn| and \myhlc|\@@_key_def_meta:nnn| % will check the \emph{optional argument} and create the \emph{\enquote{meta-key}}. % \begin{macrocode} \cs_new_protected:Npn \@@_key_set_meta:nnn #1 { \keys_set:nn { enumext } {#1} \@@_key_def_meta:Vnn \l_@@_meta_path_str } \cs_new_protected:Nn \@@_key_def_meta:nnn { \bool_lazy_or:nnTF { \keys_if_exist_p:nn { enumext / #1} {#2} } { \keys_if_exist_p:nn { enumext / enumext* } {#2} } { \msg_error:nnn { enumext } { already-defined } {#2} } { \keys_define:nn { enumext / #1 } { #2 .meta:n = {#3}, #2 .value_forbidden:n = true } } } \cs_generate_variant:Nn \@@_key_def_meta:nnn { V } % \end{macrocode} % \end{macro} % % \begin{macro}{\setenumextmeta} % Now the user command is created, taking care that \texttt{unknown} % cannot be passed as an argument. It accepts a \emph{starred argument} `|*|' % in `|#1|', an optional argument in `|#2|' that selects the environments and % levels, with default value |enumext,1|, the name of the new \emph{\enquote{meta-key}} % in `|#3|' and the \mymeta{keys} it sets in `|#4|'. With the \emph{starred argument} % the \emph{\enquote{meta-key}} is defined for the four levels of % \myenv*[no-index]{enumext} and for \myenv*[no-index]{enumext*}. % \begin{macrocode} \NewDocumentCommand \setenumextmeta { s O{enumext,1} m +m } { \str_if_eq:eeTF { \tl_trim_spaces:n {#3} } { unknown } { \msg_error:nn { enumext } { prohibited-unknown } } { \bool_if:nTF {#1} { \int_step_inline:nn { 4 } { \@@_key_set_meta:nnn { enumext, ##1 } {#3} {#4} } \@@_key_set_meta:nnn { enumext* } {#3} {#4} } { \@@_key_set_meta:nnn {#2} {#3} {#4} } } } % \end{macrocode} % \end{macro} % % \subsection{The command \cs{foreachkeyans}}\label{cmd:foreachkeyans} % % The command \ics*{foreachkeyans} will execute a \emph{loop} over the \emph{prop list} and return its contents. % The implementation code is adapted from the answer provided by Enrico Gregorio (\texttt{@egreg}) in % \href{https://tex.stackexchange.com/a/721130}{Expand a \texttt{.cs} defined by key inside the function}. % % \subsubsection{Definition of variables for \cs[no-index]{foreachkeyans}} % % \begin{variable}[int]{ % \l_@@_foreach_print_seq, % \l_@@_foreach_name_prop_tl, % \l_@@_foreach_default_keys_tl, % } % Internal variables used by the |\foreachkeyans| command (\S\ref{cmd:foreachkeyans}). % \begin{macrocode} \seq_new:N \l_@@_foreach_print_seq \tl_new:N \l_@@_foreach_name_prop_tl \tl_new:N \l_@@_foreach_default_keys_tl % \end{macrocode} % \end{variable} % % \subsubsection{Definition of error messages for \cs[no-index]{foreachkeyans}} % % \begin{macro}[int]{for-key-unknown, for-key-value-unknown} % Message used by unknown \mymeta{keys} in |\foreachkeyans|. % \begin{macrocode} \msg_new:nnnn { enumext } { for-key-unknown } { The~key~'#1'~is~unknown~by~'\token_to_str:N \foreachkeyans'~and~is~being~ ignored~\msg_line_context:. } { The~command~'\token_to_str:N \foreachkeyans'~does~not~have~a~key~called~ '#1'.~Check~that~you~have~spelled~the~key~name~correctly. } \msg_new:nnnn { enumext } { for-key-value-unknown } { The~key~'#1=#2'~is~unknown~by~'\token_to_str:N \foreachkeyans'~and~is~ being~ignored~\msg_line_context:. } { The~command~'\token_to_str:N \foreachkeyans'~does~not~have~a~key~called~ '#1'.~Check~that~you~have~spelled~the~key~name~correctly. } % \end{macrocode} % \end{macro} % % \subsubsection{Definition of keys for \cs[no-index]{foreachkeyans}} % % \begin{macro}[int]{before, after, sep, start, step, stop, wrapper, unknown} % A set of \mymeta{keys} is defined for the command and the % default values of these are saved in \myhlc|\l_@@_foreach_default_keys_tl| to avoid % the use of a group. % \begin{macrocode} \keys_define:nn { enumext / foreach } { before .tl_set:N = \l_@@_foreach_before_tl, before .value_required:n = true, after .tl_set:N = \l_@@_foreach_after_tl, after .value_required:n = true, start .int_set:N = \l_@@_foreach_start_int, start .value_required:n = true, stop .int_set:N = \l_@@_foreach_stop_int, stop .value_required:n = true, step .int_set:N = \l_@@_foreach_step_int, step .value_required:n = true, wrapper .cs_set_protected:Np = \@@_foreach_wrapper:n #1, wrapper .value_required:n = true, sep .tl_set:N = \l_@@_foreach_sep_tl, sep .value_required:n = true, unknown .code:n = { \@@_parse_foreach_keys:n {#1} } } \keys_precompile:nnN { enumext / foreach } { before={},after={},start=1,step=1,stop=0,wrapper=#1,sep={; } } \l_@@_foreach_default_keys_tl % \end{macrocode} % \end{macro} % % \subsubsection{Internal functions for \cs[no-index]{foreachkeyans}} % % \begin{macro}[int]{\@@_parse_foreach_keys:nn, \@@_parse_foreach_keys:n} % Functions for handling unknown \mymeta{keys}. % \begin{macrocode} \cs_new_protected:Nn \@@_parse_foreach_keys:nn { \tl_if_blank:nTF {#2} { \msg_error:nnn { enumext } { for-key-unknown } {#1} } { \msg_error:nnnn { enumext } { for-key-value-unknown } {#1} {#2} } } \cs_new_protected:Nn \@@_parse_foreach_keys:n { \exp_args:NV \@@_parse_foreach_keys:nn \l_keys_key_str {#1} } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_foreach_keyans:nn, \@@_foreach_add_body:n} % The internal functions \myhlc|\@@_foreach_keyans:nn| and % \myhlc|\@@_foreach_add_body:n| will loop through the prop list and print % the contents. % \begin{macrocode} \cs_new_protected:Nn \@@_foreach_keyans:nn { \tl_use:N \l_@@_foreach_default_keys_tl \keys_set:nn { enumext / foreach } {#1} \tl_set:Nn \l_@@_foreach_name_prop_tl {#2} \prop_if_exist:cF { g_@@_ #2 _prop } { \msg_error:nnn { enumext } { undefined-storage-anskey } {#2} } \int_compare:nNnT { \l_@@_foreach_stop_int } = { 0 } { \int_set:Nn \l_@@_foreach_stop_int { \prop_count:c { g_@@_ #2 _prop } } } \seq_clear:N \l_@@_foreach_print_seq \int_step_function:nnnN { \l_@@_foreach_start_int } { \l_@@_foreach_step_int } { \l_@@_foreach_stop_int } \@@_foreach_add_body:n \seq_use:NV \l_@@_foreach_print_seq \l_@@_foreach_sep_tl } \cs_new_protected:Nn \@@_foreach_add_body:n { \seq_put_right:Ne \l_@@_foreach_print_seq { \exp_not:V \l_@@_foreach_before_tl \@@_foreach_wrapper:n { \prop_item:cn { g_@@_ \l_@@_foreach_name_prop_tl _prop }{#1} } \exp_not:V \l_@@_foreach_after_tl } } % \end{macrocode} % \end{macro} % % \begin{macro}{\foreachkeyans} % The command accepts an optional \myoarg{key \textnormal{\textcolor{gray}{=}} val} argument in `|#1|' and a mandatory % \mymarg{store name} in `|#2|', and runs the loop over the content stored in it. % \begin{macrocode} \NewDocumentCommand \foreachkeyans { +O{} m } { \@@_foreach_keyans:nn {#1} {#2} } % \end{macrocode} % \end{macro} % % \subsection{General messages}\label{subsec:messages} % % Messages shared by several sections of the implementation; the messages used by only % one command, key or environment are defined in its own section. % % \begin{macro}[int]{package-load, package-not-load} % Messages used when checking the \mypkg[no-index]{multicol} package in \S\ref{subsec:declaration} % and the \mypkg[no-index]{hyperref} and \mypkg[no-index]{footnotehyper} packages in % \S\ref{subsec:hyperref}. % \begin{macrocode} \msg_new:nnn { enumext } { package-load } { The~'#1'~package~is~already~loaded. } \msg_new:nnn { enumext } { package-not-load } { The~'#1'~package~will~be~loaded~as~a~dependency. } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{unknown-choice} % Message used by the keys \mykey[env]{align} in \S\ref{key:label}, \mykey[env]{mark-pos} in % \S\ref{subsec:storage-system} and \mykey[env]{label-pos} in \S\ref{env:keyanspic}. % \begin{macrocode} \msg_new:nnnn { enumext } { unknown-choice } { Invalid~value~'#3'~for~key~'#1';~use~one~of:~#2~\msg_line_context:. } { Use~one~of~the~listed~values. } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{command-wrong-place} % Message used by the commands |\anskey| in \S\ref{cmd:anskey} and |\anspic| in % \S\ref{cmd:anspic} when they are used in the wrong place. % \begin{macrocode} \msg_new:nnnn { enumext } { command-wrong-place } { Wrong~place~for~command~'\c_backslash_str #1'~\msg_line_context:. } { '\c_backslash_str #1'~works~outside~the~environment~'#2'. } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{undefined-storage-anskey} % Message used by the commands |\getkeyans| in \S\ref{cmd:getkeyans}, |\printkeyans| in % \S\ref{cmd:printkeyans} and |\foreachkeyans| in \S\ref{cmd:foreachkeyans} % when the storage is not defined. % \begin{macrocode} \msg_new:nnnn { enumext } { undefined-storage-anskey } { Storage~named~'#1'~is~not~defined~\msg_line_context:. } { Store~content~first~with~the~key~'save-ans=#1'. } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{missing-miniright} % Message used by \myenv*[no-index]{enumext} in \S\ref{env:enumext} and \myenv*[no-index]{keyans} % in \S\ref{env:keyans} when the key \mykey[env]{mini-env} needs |\miniright| % from \S\ref{cmd:miniright}. % \begin{macrocode} \msg_new:nnn { enumext } { missing-miniright } { Missing~'\token_to_str:N \miniright'~\msg_line_context:.\\ The~key~'mini-env'~needs~'\token_to_str:N \miniright'. } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{nested} % Message used when an environment is nested in itself, raised by \myenv*[no-index]{enumext*} % in \S\ref{env:starred} and \myenv*[no-index]{keyans*} in \S\ref{env:keyans-starred}. % \begin{macrocode} \msg_new:nnnn { enumext } { nested } { The~environment~\l_@@_envir_name_tl \c_space_tl can't~be~nested~ \msg_line_context:. } { Starred~environments~are~horizontal~lists~and~can't~be~nested. } % \end{macrocode} % \end{macro} % % \subsection{Finish package}\label{subsec:finish} % % Finish package implementation. % % \begin{macrocode} \file_input_stop: % % \end{macrocode} % \Finale