% \iffalse meta-comment % %% File: latex-lab-l3doc-tagging.dtx % Copyright (C) 2022-2025 The LaTeX Project % % It may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this % license or (at your option) any later version. The latest version % of this license is in the file % % https://www.latex-project.org/lppl.txt % % % The development version of the bundle can be found below % % https://github.com/latex3/latex2e/required/latex-lab % % for those people who are interested or want to report an issue. % \def\ltlabdoctaggingdate{2025-05-07} \def\ltlabdoctaggingversion{0.80b} %<*driver> \DocumentMetadata { lang=en, pdfstandard=ua-2, tagging=on } \tagpdfsetup{table/header-rows=1} \documentclass{l3doc} \usepackage{latex-lab-testphase-l3doc} \EnableCrossrefs \CodelineIndex \NewDocElement[envlike, idxtype=instance, idxgroup=instances, printtype=\textit{inst.}] {Instance}{instance} \begin{document} \DocInput{latex-lab-l3doc-tagging.dtx} \end{document} % % % \fi % % % \title{The \texttt{latex-lab-testphase-l3doc} package\thanks{}} % \author{Ulrike Fischer, \LaTeX{} Project} % % \maketitle % % \tableofcontents % % \begin{documentation} % \section{Introduction} % % This package provides tagging support for the l3doc class. % It is work in progress. It is neither garantied that every element % is correctly tagged nor that the output looks identical to the untagged version. % % If a documentation is tagged with this code, it is important to check the log-file % for warnings, the tag structure for missing parts and the output for deviations! % % Feedback at \url{https://github.com/latex3/tagging-project} is welcome! % % TODO: Index? % % TODO: update key names if block key names change % % \end{documentation} % % \begin{implementation} % \section{implementation} % % \begin{macrocode} %<*package> % \end{macrocode} % % \subsection{Declaration} % % \begin{macrocode} \ProvidesExplPackage {latex-lab-testphase-l3doc} {2025-05-07} {0.80b} { Tagging Support for the l3doc class } % \end{macrocode} % some minimal error checking % \begin{macrocode} \IfClassLoadedF{l3doc} {\PackageError{latex-lab-testphase-l3doc}{This~package~requires~the~l3doc~class!}{}} % \end{macrocode} % % \begin{macrocode} \IfDocumentMetadataF {\PackageError{latex-lab-testphase-l3doc}{This~package~requires~the~PDF~management!}{}} % \end{macrocode} % % \subsection{Tag and roles} % % The exact tagging structure is not yet clear. Especially for verbatim and % code material. So we define roles that we can exchange when needed. % \begin{macrocode} \tagpdfsetup { role/new-tag=function/Sect, role/new-tag=functionnames/Caption, role/new-tag=functionname/Code, role/new-tag=functionnamepart/Span, role/new-tag=syntax/Sect, role/new-tag=function-description/Div, role/new-tag=macro/Sect, role/new-tag=macronames/Caption, role/new-tag=macroname/Span, role/new-tag=variable/Sect, role/new-tag=variablenames/Caption, role/new-tag=variablename/Span, role/new-tag=codelinenum/Span, role/new-tag=part/H1 } % \end{macrocode} % % \subsection{Variables} % % % \begin{variable}{\l__codedoc_current_names_struct_tl} % The structure around the command names in the margin must be moved around. % For this we define a variable that will hold the relevant current structure. % \begin{macrocode} \tl_new:N\l__codedoc_current_names_struct_tl % \end{macrocode} % \end{variable} % % \begin{variable}{\g__codedoc_macroname_structnum_seq} % This holds the structure numbers of the % structure around every command name in a macro environment. As the % structures are created inside a box this is a global variable, which is cleared % at the end of the outer macro environment. % \begin{macrocode} \seq_new:N\g__codedoc_macroname_structnum_seq % \end{macrocode} % \end{variable} % % % \subsection{The \env{function} enviroment} % % \begin{macro}{\__codedoc_function_typeset_start:} % This command starts the typesetting and opens the structure. % \begin{macrocode} \cs_set_protected:Npn \__codedoc_function_typeset_start: { \par \bigskip \tagstructbegin{tag=function} % \end{macrocode} % The paragraph structure should start after the building of the macronames. % TODO: check if we can simply move ... % \begin{macrocode} \tagpdfparaOff \noindent } % \end{macrocode} % \end{macro} % % % \begin{macro}{\__codedoc_typeset_functions:} % TODO: \cs{toprule} and \cs{bottomrule} should be artifacts with pdflatex % (they are already with lualatex). % \begin{macrocode} \cs_set_protected:Npn \__codedoc_typeset_functions: { % \small\ttfamily \__codedoc_target: \Hy@MakeCurrentHref { HD. \int_use:N \c@HD@hypercount } % \end{macrocode} % The function names are typeset as a tabular. We use % the table code to add the tagging. % \begin{macrocode} \tagstructbegin{tag=functionnames} \tagmcbegin{} \tagpdfsetup{table/tagging=div} \tl_set:Nn\l__tbl_rowtag_tl {functionname} \tl_set:Nn\l__tbl_celltag_tl {functionnamepart} \begin{tabular} [t] { @{} l @{} >{\hspace{\tabcolsep}} r @{} } \toprule \__codedoc_function_extra_labels: \__codedoc_names_typeset: \__codedoc_typeset_dates: \bottomrule \end{tabular} \tagmcend \tagstructend \normalfont\normalsize\par } % \end{macrocode} % \end{macro} % % \begin{macro}{\__codedoc_function_descr_start:w} % The function enviroment is mainly a box. We store the structure % for the syntax environment. % \begin{macrocode} \cs_set_protected:Npn \__codedoc_function_descr_start:w { \vcoffin_set:Nnw \l__codedoc_descr_coffin { \textwidth } \tagpdfparaOn \tagstructbegin{tag=function-description} \tl_set:Ne\l__codedoc_current_names_struct_tl{\tag_get:n{struct_num}} \noindent \ignorespaces } % \end{macrocode} % \end{macro} % % \begin{macro}{\__codedoc_function_typeset_stop:} % At the end we must close the two main structures. % \begin{macrocode} \cs_set_protected:Npn \__codedoc_function_typeset_stop: { \par \tagstructend % function-description \tagstructend % function \dim_set:Nn \prevdepth { \coffin_dp:N \l__codedoc_descr_coffin } \allowbreak } % \end{macrocode} % \end{macro} % % \subsection{The \env{syntax} environment} % % These environments are full of boxes that are moved around. % Getting the mc-chunks right is not trivial. % % TODO: check if one should change/simplify the tagging of the inner minipage. % \begin{macro}{\__codedoc_syntax:w} % \begin{macrocode} \cs_set_protected:Npn \__codedoc_syntax:w { \box_if_empty:NF \g__codedoc_syntax_box { \msg_error:nn { l3doc } { multiple-syntax } } \dim_set:Nn \l__codedoc_syntax_dim { \textwidth \bool_if:NT \l__codedoc_long_name_bool { + \marginparwidth - \l__codedoc_trial_width_dim } } \tag_mc_end_push: \hbox_gset:Nw \g__codedoc_syntax_box \tl_if_empty:NTF\l__codedoc_current_names_struct_tl { \tagstructbegin{tag=syntax} } { % \end{macrocode} % TODO: check if firstkid is the right thing. % \begin{macrocode} \tagstructbegin{tag=syntax,firstkid,parent=\l__codedoc_current_names_struct_tl} } \small \ttfamily \tagpdfsetup{table/tagging=false} \tagpdfparaOff \arrayrulecolor{white} \begin{tabular} { @{} p{\l__codedoc_syntax_dim} @{} } \toprule \begin{minipage}[t]{\l__codedoc_syntax_dim} \raggedright \obeyspaces \obeylines } % \end{macrocode} % \end{macro} % % % \begin{macro}{\__codedoc_syntax_end:} % \begin{macrocode} \cs_set_protected:Npn \__codedoc_syntax_end: { \end{minipage} \end{tabular} \arrayrulecolor{black} \tagstructend \hbox_gset_end: \tag_mc_begin_pop:n{} \bool_if:NF \l__codedoc_in_function_bool { \begin{quote} \mode_leave_vertical: \box_use_drop:N \g__codedoc_syntax_box \end{quote} } } % \end{macrocode} % \end{macro} % % \subsection{The \env{macro} environment} % The macro environment is difficult: It collects various content % in boxes and outputs everything at the end in \cs{__codedoc_macro_dump:}, % including the command names in the argument which are output in the margin. % A macro environment can have more than one name in % the argument and the environment be nested and the respective command names % are then combined with the outer names. % A command name can link to a \env{function} environment, % which mean that it isn't simple text but contains a structure. % This means that one has to collect structure numbers to insert them when needed. % % % \begin{macro}{\__codedoc_macro_dump:} % Here we have larger changes as we need also to replace the trivlist by a displayblock. % \begin{macrocode} \cs_set_protected:Npn \__codedoc_macro_dump: { \int_compare:nNnF{\l__codedoc_nested_macro_int}>{1} { \begin{displayblock} [tag-name=macro,beginsep=\MacroTopsep] % \end{macrocode} % we add here a container for the macronames which are built later and use % the structures from the list. % \begin{macrocode} \tagstructbegin{tag=macronames} \tl_set:Ne \l__codedoc_current_names_struct_tl {\tag_get:n{struct_num}} \seq_map_inline:Nn \g__codedoc_macroname_structnum_seq {\tag_struct_use_num:n {##1}} \seq_gclear:N \g__codedoc_macroname_structnum_seq \tagstructend } \noindent\llap { \tagmcend \hbox_unpack_drop:N \l__codedoc_macro_index_box \vtop to \baselineskip { \vbox_unpack_drop:N \l__codedoc_macro_box \vss } \hspace{\labelsep} \tagmcbegin{} } } % \end{macrocode} % \end{macro} % % \begin{macro}{\__codedoc_macro_typeset_one:nN} % The \cs{__codedoc_macro_typeset_one:nN} command appends one macro name % to the \cs{l__codedoc_macro_box}. We have to add a structure. % If we are on the outer level we have to record the structure number. % In the inner level we can use the existing structure. % As the structures are used in another place, we have to push/pop the mc. % \begin{macrocode} \cs_set_protected:Npn \__codedoc_macro_typeset_one:nN #1#2 { \tag_mc_end_push: \vbox_set:Nn \l__codedoc_macro_box { \vbox_unpack_drop:N \l__codedoc_macro_box \int_compare:nNnTF { \l__codedoc_nested_macro_int } = { 1 } { \tagstructbegin{tag=macroname,stash} \seq_gput_right:Ne \g__codedoc_macroname_structnum_seq{\tag_get:n{struct_num}} } { \tagstructbegin{tag=macroname,parent=\l__codedoc_current_names_struct_tl} } \tagmcbegin{} \hbox { \llap { \__codedoc_print_macroname:nN {#1} #2 \MacroFont \ } } \tagmcend \tagstructend } \tag_mc_begin_pop:n{} \int_incr:N \l__codedoc_macro_int } % \end{macrocode} % \end{macro} % % \begin{macro}{\__codedoc_macro_reset:} % As we have no nested lists, we need to ignore spaces explicitly % \begin{macrocode} \cs_set_protected:Npn \__codedoc_macro_reset: { \tl_set:Nn \l__codedoc_override_module_tl { \q_no_value } \ignorespaces } % \end{macrocode} % \end{macro} % % \begin{macro}{\__codedoc_macro_end:} % \begin{macrocode} \cs_set_protected:Npn \__codedoc_macro_end: { \__codedoc_macro_end_check_tested: \int_compare:nNnT \l__codedoc_nested_macro_int = 1 { \par \__codedoc_macro_end_style:n { \__codedoc_print_end_definition: } \end{displayblock} } } % \end{macrocode} % \end{macro} % % \subsection{The \env{macrocode} environment} % % % \begin{macro}[no-user-doc]{\legacymacrocodesetup} % We want to base the environment on the new template code. % This is a counterpart to the \cs{legacyverbatimsetup} % command in the latex-lab-block code. % \begin{macrocode} \def\legacymacrocodesetup{% \macro@font \blank@linefalse \def\par{\ifblank@line \leavevmode \else \fi % \end{macrocode} % Similar to the case for verbatim we must group the % \cs{@@par} so that we do not loose indentation on the first % line % \begin{macrocode} \blank@linetrue{\@@par} \penalty\interlinepenalty} \obeylines \@noligs \let\do\@makeother \dospecials \global\@newlistfalse \global\@minipagefalse \ifcodeline@index \everypar{\global\advance\c@CodelineNo\@ne \llap{\tagmcend\tagstructbegin{tag=codelinenum} \tagmcbegin{} \theCodelineNo\pdffakespace \tagmcend\tagstructend \tagmcbegin{}% \ }% \check@module}% \else \everypar{\check@module}% \fi \tagtool{paratag=codeline}% check tagging } % \end{macrocode} % \end{macro} % \begin{instance}{blockenv macrocode} % \begin{macrocode} \DeclareInstance{blockenv}{macrocode}{display} { env-name = macrocode, tag-name = verbatim, tag-class = , tagging-recipe = standard, inner-level-counter = , level-increase = false, setup-code = , block-instance = verbatimblock , inner-instance = , final-code = \legacymacrocodesetup , para-instance = justify, para-flattened= true } % \end{macrocode} % \end{instance} % % \begin{environment}{macrocode} % \begin{macrocode} \RenewDocumentEnvironment{macrocode}{!O{}} {\UseInstance{blockenv}{macrocode} {beginpenalty=\predisplaypenalty, begin-skip=\MacrocodeTopsep, leftmargin=\MacroIndent, parindent=0pt,#1}% \@setupverbinvisiblespace \init@crossref \frenchspacing \@vobeyspaces \xmacro@code } { \ifpm@module \endgroup \pm@modulefalse \fi \everypar{} \endblockenv \close@crossref } % \end{macrocode} % \end{environment} % % \subsection{New doc elements} % Various documentation elements are declare with the \cs{NewDocElement} % command. Here we patch the relevant commands to get tagged versions. % % \begin{macro}[no-user-doc]{\@doc@env@} % \begin{macrocode} \long\def\@doc@env@#1#2#3{% % \end{macrocode} % we setup a new role: % \begin{macrocode} \tagpdfsetup{role/new-tag=#2/Sect} \int_incr:N\l__codedoc_nested_macro_int \int_compare:nNnF{\l__codedoc_nested_macro_int}>{1} {\UseInstance{blockenv}{displayblock} {level-increase=false,tag-name=#2,beginsep=\MacroTopsep} % \end{macrocode} % A container for the function names. % \begin{macrocode} \tagstructbegin{tag=macronames} \tl_set:Ne \l__codedoc_current_names_struct_tl {\tag_get:n{struct_num}} \tagstructend } \edef\saved@macroname{\string#3}% \if #1% \edef\saved@indexname{\expandafter\@gobble\saved@macroname}% \expandafter\ifx \csname Code#2Index\endcsname \CodeMacroIndex \else \record@index@type@save {\saved@indexname}{#2}% \fi \else \let\saved@indexname\saved@macroname \fi \def\makelabel##1{\noindent\llap{ \tagmcend \tagstructbegin{tag=macroname,parent=\l__codedoc_current_names_struct_tl} \tagmcbegin{} ##1\hspace{\itemsep} \tagmcend \tagstructend \tagmcbegin{} }}% \int_compare:nNnTF{\l__codedoc_nested_macro_int}>{1} { \let\@tempa\@empty \count@\macro@cnt \loop\ifnum\count@>\z@ \edef\@tempa{\@tempa\hbox{\strut}}\advance\count@\m@ne \repeat \edef\makelabel##1{\noindent\llap{ \tagmcend \tagstructbegin{tag=macroname,parent=\l__codedoc_current_names_struct_tl} \tagmcbegin{} \vtop to\baselineskip{\@tempa\hbox{##1\kern\labelsep}\vss} \tagmcend \tagstructend \tagmcbegin{} }}% \advance\macro@cnt\@ne } { \macro@cnt\@ne } \ifdoc@noprint \else \edef\@tempa{% \noexpand\makelabel{ \noexpand\doc@providetarget \noexpand\strut \noexpand\@nameuse{Print#2Name}{\saved@macroname}}}% \@tempa \fi \ifdoc@noindex\else \global\advance\c@CodelineNo\@ne \csname SpecialMain#2Index\expandafter\endcsname \expandafter{\saved@macroname}\nobreak \global\advance\c@CodelineNo\m@ne \fi \if#1\expandafter\DoNotIndex \expandafter {\saved@macroname}\fi \ignorespaces} % \end{macrocode} % \end{macro} % % \begin{macro}[no-user-doc]{\doc@createenv} % We must use \cs{endblockenv}. % \begin{macrocode} \def\doc@createenv#1#2#3{% \@namedef{#3}{% \@ifnextchar[%] {\doc@env{#1}{#2}}{\doc@env{#1}{#2}[]}}% \@namedef{end#3}{\endblockenv}% } % \end{macrocode} % \end{macro} % % We must renew the environment doc element so that is uses the new code: % \begin{macrocode} \RenewDocElement[macrolike = false , idxtype = env. , idxgroup = environments , printtype = \textit{env.} ]{Env}{environment} % \end{macrocode} % % \subsection{\cs{maketitle}} % The \pkg{doc} package redefines \cs{maketitle}. So we have to reinstate the % version from the title module. % % \begin{macrocode} \cs_if_exist:NT \__tag_patch_maketitle: { \cs_set_eq:NN \maketitle \__tag_patch_maketitle: } % \end{macrocode} % % \subsection{Sectioning commands and table of contents} % % \cs{l@section} must get the hooks: % \begin{macro}[no-user-doc]{\l@section} % \begin{macrocode} \cs_gset:Npn \l@section #1#2 { \ifnum \c@tocdepth >\z@ \addpenalty\@secpenalty \addvspace{1.0em \@plus\p@} \setlength\@tempdima{2.5em} % was 1.5em \begingroup \parindent \z@ \rightskip \@pnumwidth \parfillskip -\@pnumwidth \leavevmode \bfseries \advance\leftskip\@tempdima \hskip -\leftskip \UseHookWithArguments{contentsline/text/before}{4} {\toclevel@section}{#1}{#2}{\@contentsline@destination}% \csname contentsline@text@1@format\endcsname{#1} \UseHookWithArguments{contentsline/text/after}{4} {\toclevel@chapter}{#1}{#2}{\@contentsline@destination}% \nobreak\hfil \nobreak\hb@xt@\@pnumwidth{\hss \UseHookWithArguments{contentsline/page/before}{4} {\toclevel@section}{#1}{#2}{\@contentsline@destination}% #2 \UseHookWithArguments{contentsline/page/after}{4} {\toclevel@section}{#1}{#2}{\@contentsline@destination}% }\par \endgroup \fi } % \end{macrocode} % \end{macro} % % \subsection{Support \pkg{fancyvrb}} % l3doc uses \pkg{fancyvrb}. % As the block code redefines \env{verbatim} at begin document, % we have to overwrite that again: % \begin{macrocode} \AtBeginDocument { \cs_gset_eq:NN \verbatim \Verbatim \cs_gset_eq:NN \endverbatim \endVerbatim } % \end{macrocode} % % \begin{macrocode} % % \end{macrocode} % \end{implementation} \endinput