I have a horizontal list environment mylist
created with expl3
with key=val
support based on code from the shortlst
package. The environment works similarly to the tasks
or enumerate*
environment from the enumitem
package, it works OK and compiles without errors when using \DocumentMetadata
, but the structure created is not correct.
In order for it to work as I want the command \item
has the form (in terms of ltcmd
/xparse
) \item{ D() s o o }
, but I have not been able to use \RenewDocumentCommand
(does not work in this case) and I have had to make a cascade of functions using \cs_new_protected...
and \peek_meaning:NTF
.
The \item
and \item[opt]
commands work in the usual way, and the optionals arguments I have added are:
\item(join)
: It is the first optional argument and joins columns, that is, it increases the width occupied bylabel+labelsep+item-content
.\item*
: It is the second optional argument and works like a numbered item, but adding a symbol to the left of the label. When*
is present two optional arguments may be used\item*[sym][sep]
and may also be used in conjunction with\item(join)*[sym][sep]
.\item(join)[opt]
: Works like\item[opt]
(not numbered), but joining columns.
All contents of label
, labelsep
, item-content
are captured in a \hbox+\minipage
, processed and then printed horizontally leaving the column-sep
space between them.
When comparing the output of the enumerate
environment with my environment mylist*
delivered by ngpdf.com the differences are observed:
The first structure is correct and the second one should look the same when using columns=1
, but it doesn't. In the documentation for tagpdf-code
and latex-lab-block
I can see a couple of functions that I think are the ones I need to put here:
\tag_stop:
\tag_start:
\tagpdfparaOn
\tagpdfparaOff
\tag_struct_end:
\tag_mc_end:
\tag_struct_begin:n {tag=LI}
\tag_struct_begin:n {tag=Lbl}
\tag_struct_begin:n {tag=LBody}
\tag_mc_begin:n {tag=Lbl}
So my question is:
How can modify my redefinition of \item
to be compatible with tagging?
That is, where to put the commands shown above to stop automatic tagging and get a correct list structure.
The non-MWE is the following:
\DocumentMetadata{ lang=en-US, pdfversion=2.0, testphase={phase-III,math,table,title,firstaid}, uncompress }% pdfstandard=ua-2,
\documentclass{article}
% \usepackage{hyperref}
\ExplSyntaxOn
% Copy list with tagging support (https://tex.stackexchange.com/a/725389)
\hook_gput_code:nnn {begindocument} { mylist }
{
\cs_new_eq:NN \__mylist_start_list:nn \list
\cs_new_eq:NN \__mylist_stop_list: \endlist
\NewCommandCopy \__mylist_item_std:w \item
}
% Some vars
\int_new:N \l_mylist_level_int
\tl_new:N \g_mylist_counter_styles_tl
\box_new:N \l_mylist_label_width_by_box
\dim_new:N \l_mylist_current_widest_dim
\dim_new:N \itemwidth % public
\bool_new:N \l_mylist_hyperref_bool
% Hyperref support
\IfPackageLoadedTF { hyperref }
{
\bool_set_true:N \l_mylist_hyperref_bool
}{}
% Counter
\cs_new_protected:Npn \__mylist_counters:n #1
{
\tl_new:c { l_mylist_counter_#1_tl }
\tl_set:cn { l_mylist_counter_#1_tl } { mycounx#1 }
\newcounter{ mycounx#1 }
}
\__mylist_counters:n {vii}
% Width label
\cs_new_protected:Npn \__mylist_label_width_by_box:Nn #1#2
{
\hbox_set:Nn \l_mylist_label_width_by_box {#2}
\dim_set:Nn #1 { \box_wd:N \l_mylist_label_width_by_box }
}
% Register counters and set default labelwidth
\cs_new_protected:Npn \__mylist_register_counter_style:Nn #1 #2
{
\tl_const:cn { c_mylist_widest_ \cs_to_str:N #1 _tl } {#2}
\tl_gput_right:Nn \g_mylist_counter_styles_tl {#1}
}
\__mylist_register_counter_style:Nn \arabic { 0 }
\__mylist_register_counter_style:Nn \Alph { M }
\__mylist_register_counter_style:Nn \alph { m }
\__mylist_register_counter_style:Nn \Roman { VIII }
\__mylist_register_counter_style:Nn \roman { viii }
% Style for label
\cs_new_protected:Npn \__mylist_label_style:Nnn #1#2#3
{
\tl_clear_new:N #1
\tl_put_right:Ne #1 { \tl_trim_spaces:n {#3} }
\tl_gset_eq:NN \g_mylist_widest_label_tl #1
\tl_map_inline:Nn \g_mylist_counter_styles_tl
{
\tl_replace_all:Nne #1 { ##1* } { \exp_not:N ##1 {#2} }
\tl_greplace_all:Nne \g_mylist_widest_label_tl { ##1* }
{ \tl_use:c { c_mylist_widest_ \cs_to_str:N ##1 _tl } }
}
\__mylist_label_width_by_box:Nn \l_mylist_current_widest_dim
{ \tl_use:N \g_mylist_widest_label_tl }
\tl_set_eq:cN { the #2 } #1
}
\cs_generate_variant:Nn \__mylist_label_style:Nnn { cvn }
% Keys and vars for levels
\cs_new_protected:Npn \__mylist_keys_and_vars:nnnnnn #1#2#3#4#5#6
{
\bool_new:c { l_mylist_leftmargin_tmp_#1_bool }
\bool_new:c { l_mylist_wrap_label_opt_#1_bool }
\bool_new:c { l_mylist_wrap_label_#1_bool }
\dim_new:c { l_mylist_leftmargin_tmp_#1_dim }
\dim_new:c { l_mylist_leftmargin_#1_dim }
\dim_new:c { l_mylist_itemindent_#1_dim }
\tl_new:c { l_mylist_fake_item_indent_#1_tl }
\tl_new:c { l_mylist_label_#1_tl }
\str_new:c { l_mylist_align_label_#1_str }
\bool_new:c { l_mylist_item_starred_#1_bool }
\int_new:c { l_mylist_item_column_pos_#1_int }
\int_new:c { l_mylist_item_label_#1_int }
\int_new:c { g_mylist_item_count_all_#1_int }
\int_new:c { l_mylist_joined_item_#1_int }
\int_new:c { l_mylist_joined_item_aux_#1_int }
\int_new:c { l_mylist_tmpa_#1_int }
\dim_new:c { l_mylist_tmpa_#1_dim }
\box_new:c { l_mylist_item_text_#1_box }
\dim_new:c { l_mylist_joined_width_#1_dim }
\dim_new:c { l_mylist_item_width_#1_dim }
\tl_new:c { g_mylist_item_symbol_aux_#1_tl }
\keys_define:nn { mylist / level-#1 }
{
font .tl_set:c = { l_mylist_label_font_style_#1_tl },
itemindent .dim_set:c = { l_mylist_fake_item_indent_#1_dim },
labelsep .dim_set:c = { l_mylist_labelsep_#1_dim },
labelsep .initial:n = {0.3333em},
labelwidth .dim_set:c = { l_mylist_labelwidth_#1_dim },
label .code:n = {
\__mylist_label_style:cvn { l_mylist_label_#1_tl }
{ l_mylist_counter_#1_tl } {##1}
\dim_set_eq:cN
{ l_mylist_labelwidth_#1_dim } \l_mylist_current_widest_dim
},
label .initial:n = {#2},
wrap-label .cs_set_protected:cp = { __mylist_wrapper_label_#1:n } ##1,
wrap-label .initial:n = {##1},
wrap-label* .code:n = {
\bool_set_true:c { l_mylist_wrap_label_opt_#1_bool }
\keys_set:nn { mylist / level-#1 } { wrap-label = {##1} }
},
item-sym* .tl_set:c = { l_mylist_item_symbol_#1_tl },
item-sym* .initial:n = {\textasteriskcentered},
item-pos* .dim_set:c = { l_mylist_item_symbol_sep_#1_dim },
align .choice:,
align / left .code:n = \str_set:cn { l_mylist_align_label_#1_str } { l },
align / right .code:n = \str_set:cn { l_mylist_align_label_#1_str } { r },
align / center .code:n = \str_set:cn { l_mylist_align_label_#1_str } { c },
align .initial:n = left,
list-offset .dim_set:c = { l_mylist_listoffset_#1_dim },
list-indent .meta:n = { list-offset = ##1 },
columns-sep .dim_set:c = { l_mylist_columns_sep_#1_dim },
columns .int_set:c = { l_mylist_columns_#1_int },
columns .initial:n = 2,
topsep .skip_set:c = { l_mylist_topsep_#1_skip },
topsep .initial:n = {#3},
partopsep .skip_set:c = { l_mylist_partopsep_#1_skip },
partopsep .initial:n = {#4},
parsep .skip_set:c = { l_mylist_parsep_#1_skip },
parsep .initial:n = {#5},
itemsep .skip_set:c = { l_mylist_itemsep_#1_skip },
itemsep .initial:n = {#6},
rightmargin .dim_set:c = { l_mylist_rightmargin_#1_dim },
listparindent .dim_set:c = { l_mylist_listparindent_#1_dim },
}
}
% Set keys and vars
\__mylist_keys_and_vars:nnnnnn { vii } { \arabic*.} { 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 }
% Internal function for fake |\itemindent|
\cs_set_protected:Nn \__mylist_fake_item_vii:
{
\dim_compare:nNnT
{ \l_mylist_fake_item_indent_vii_dim } > { \c_zero_dim }
{
\tl_set:Ne \l_mylist_fake_item_indent_vii_tl
{
\exp_not:N \mode_leave_vertical:
\exp_not:N \skip_horizontal:N \l_mylist_fake_item_indent_vii_dim
}
}
}
% Calc \itemindent and \leftmargin
% #1: \l_mylist_labelwidth_i_dim #2: \l_mylist_labelsep_i_dim #3: \l_mylist_listoffset_i_dim
% #4: \l_mylist_leftmargin_tmp_i_dim #5: \l_mylist_leftmargin_i_dim #6: \l_mylist_itemindent_i_dim
% #7: \l_mylist_custom_margin_i_bool
\cs_new_protected:Npn \__mylist_calc_hspace:NNNNNNN #1#2#3#4#5#6#7
{
\bool_if:nF #7 { \dim_set:Nn #4 { #1 + #2} }
\dim_compare:nNnTF {#4} < { 0pt }
{
\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 { 0pt} }
\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 \__mylist_calc_hspace:NNNNNNN { ccccccc }
% Second argument of list
\cs_set_protected:Npn \__mylist_make_second_arg:n #1
{
\cs_new_protected:cpn { __mylist_list_arg_two_#1: }
{
\bool_set_true:c { l_mylist_leftmargin_tmp_#1_bool }
\dim_zero:c { l_mylist_leftmargin_tmp_#1_dim }
\__mylist_calc_hspace:ccccccc
{ l_mylist_labelwidth_#1_dim } { l_mylist_labelsep_#1_dim }
{ l_mylist_listoffset_#1_dim } { l_mylist_leftmargin_tmp_#1_dim }
{ l_mylist_leftmargin_#1_dim } { l_mylist_itemindent_#1_dim }
{ l_mylist_leftmargin_tmp_#1_bool }
\clist_map_inline:nn
{ labelsep, labelwidth, itemindent, leftmargin, rightmargin, listparindent }
{ \dim_set_eq:cc {####1} { l_mylist_####1_#1_dim } }
\clist_map_inline:nn { topsep, parsep, partopsep, itemsep }
{ \skip_set_eq:cc {####1} { l_mylist_####1_#1_skip } }
\skip_set_eq:Nc \parsep { l_mylist_itemsep_#1_skip }
\skip_zero:N \partopsep
\usecounter { mycounx#1 }
\__mylist_fake_item_vii:
}
}
\__mylist_make_second_arg:n {vii}
% Define default item-width (columns width).
\cs_new_protected:Nn \__mylist_starred_columns_set_vii:
{
\dim_compare:nNnT { \l_mylist_columns_sep_vii_dim } = { \c_zero_dim }
{
\dim_set:Nn \l_mylist_columns_sep_vii_dim
{
( \l_mylist_labelwidth_vii_dim + \l_mylist_labelsep_vii_dim )
/ \l_mylist_columns_vii_int
}
}
\int_set:Nn \l_mylist_tmpa_vii_int { \l_mylist_columns_vii_int - 1 }
\dim_set:Nn \l_mylist_item_width_vii_dim
{
( \linewidth - \l_mylist_columns_sep_vii_dim * \l_mylist_tmpa_vii_int )
/ \l_mylist_columns_vii_int
- \l_mylist_labelwidth_vii_dim
- \l_mylist_labelsep_vii_dim
}
\dim_compare:nNnT { \l_mylist_rightmargin_vii_dim } > { \c_zero_dim }
{
\dim_sub:Nn \l_mylist_item_width_vii_dim
{
( \l_mylist_rightmargin_vii_dim * \l_mylist_tmpa_vii_int )
/ \l_mylist_columns_vii_int
}
\dim_add:Nn \l_mylist_columns_sep_vii_dim
{
\l_mylist_rightmargin_vii_dim
}
}
}
% Set width for joined item's
\cs_new_protected:Npn \__mylist_starred_joined_item_vii:n #1
{
\int_set:Nn \l_mylist_joined_item_vii_int {#1}
\int_compare:nNnT { \l_mylist_joined_item_vii_int } > { \l_mylist_columns_vii_int }
{
\int_set:Nn \l_mylist_joined_item_vii_int
{
\l_mylist_columns_vii_int - \l_mylist_item_column_pos_vii_int + 1
}
}
\int_compare:nNnT
{ \l_mylist_joined_item_vii_int }
>
{ \l_mylist_columns_vii_int - \l_mylist_item_column_pos_vii_int + 1 }
{
\int_set:Nn \l_mylist_joined_item_vii_int
{
\l_mylist_columns_vii_int - \l_mylist_item_column_pos_vii_int + 1
}
}
\int_compare:nNnTF { \l_mylist_joined_item_vii_int } > { 1 }
{
\int_set_eq:NN \l_mylist_joined_item_aux_vii_int \l_mylist_joined_item_vii_int
\int_decr:N \l_mylist_joined_item_aux_vii_int
\int_add:Nn \l_mylist_item_column_pos_vii_int { \l_mylist_joined_item_aux_vii_int }
\int_gadd:Nn \g_mylist_item_count_all_vii_int { \l_mylist_joined_item_aux_vii_int }
\dim_set:Nn \l_mylist_joined_width_vii_dim
{
\l_mylist_item_width_vii_dim * \l_mylist_joined_item_vii_int
+ ( \l_mylist_labelwidth_vii_dim + \l_mylist_labelsep_vii_dim
+ \l_mylist_columns_sep_vii_dim
)*\l_mylist_joined_item_aux_vii_int
}
\dim_set_eq:NN \itemwidth \l_mylist_joined_width_vii_dim
}
{
\dim_set_eq:NN \l_mylist_joined_width_vii_dim \l_mylist_item_width_vii_dim
\dim_set_eq:NN \itemwidth \l_mylist_item_width_vii_dim
}
}
% key =val
\cs_new_protected:Npn \__mylist_parse_keys_vii:n #1
{
\tl_if_novalue:nF {#1}
{
\keys_set:nn { mylist / level-vii } {#1}
}
}
% Environment
\NewDocumentEnvironment{mylist*}{ O{} }
{
\int_incr:N \l_mylist_level_int
\__mylist_parse_keys_vii:n {#1}
\__mylist_start_list:nn { }
{
\__mylist_list_arg_two_vii:
}
\__mylist_starred_columns_set_vii:
\item[] \scan_stop:
\cs_set_eq:NN \__mylist_stop_item_tmp_vii: \__mylist_first_item_tmp:
\cs_set_eq:NN \item \__mylist_start_item_tmp_vii:
\ignorespaces
}
{
\__mylist_stop_item_tmp_vii:
\__mylist_remove_extra_parsep_vii:
\__mylist_stop_list:
}
% Remove unwanted space at start first item
\cs_new_protected_nopar:Nn \__mylist_first_item_tmp:
{
\skip_horizontal:n { - \l_mylist_labelwidth_vii_dim - \l_mylist_labelsep_vii_dim }
}
% Now implement boxed \item's
\cs_new_protected_nopar:Nn \__mylist_start_item_tmp_vii:
{
\__mylist_stop_item_tmp_vii:
\int_incr:N \l_mylist_item_label_vii_int % Need for tag maybe?
\int_incr:N \l_mylist_item_column_pos_vii_int
\int_gincr:N \g_mylist_item_count_all_vii_int
\__mylist_item_peek_args_vii:
}
% Peek argument for \item(join)*[sym][sep]
\cs_new_protected:Nn \__mylist_item_peek_args_vii:
{
\peek_meaning:NTF (
{ \__mylist_joined_item_vii:w }
{ \__mylist_joined_item_vii:w (1) }
}
% Joined item's \item(join)
\cs_new_protected:Npn \__mylist_joined_item_vii:w (#1)
{
\__mylist_starred_joined_item_vii:n {#1}
\peek_meaning_remove:NTF *
{ \__mylist_starred_item_vii:w }
{ \__mylist_standar_item_vii:w }
}
% Set \item[opt]
\cs_new_protected:Npn \__mylist_standar_item_vii:w
{
\bool_set_false:N \l_mylist_item_starred_vii_bool
\peek_meaning:NTF [
{
\bool_set_eq:NN \l_mylist_wrap_label_vii_bool \l_mylist_wrap_label_opt_vii_bool
\__mylist_start_item_vii:w
}
{
\bool_set_true:N \l_mylist_wrap_label_vii_bool
\legacy_if_set_true:n { @noitemarg }
\__mylist_start_item_vii:w [ \l_mylist_label_vii_tl ]
}
}
% Set \item*[sym][sep]
\cs_new_protected:Npn \__mylist_starred_item_vii:w
{
\bool_set_true:N \l_mylist_item_starred_vii_bool
\bool_set_true:N \l_mylist_wrap_label_vii_bool
\peek_meaning:NTF [
{ \__mylist_starred_item_vii_aux_i:w }
{ \__mylist_starred_item_vii_aux_ii:w }
}
\cs_new_protected:Npn \__mylist_starred_item_vii_aux_i:w [#1]
{
\tl_gset:Nn \g_mylist_item_symbol_aux_vii_tl {#1}
\__mylist_starred_item_vii_aux_ii:w
}
\cs_new_protected:Npn \__mylist_starred_item_vii_aux_ii:w
{
\peek_meaning:NTF [
{ \__mylist_starred_item_vii_aux_iii:w }
{
\dim_set_eq:NN \l_mylist_item_symbol_sep_vii_dim \l_mylist_labelsep_vii_dim
\legacy_if_set_true:n { @noitemarg }
\__mylist_start_item_vii:w [ \l_mylist_label_vii_tl ]
}
}
\cs_new_protected:Npn \__mylist_starred_item_vii_aux_iii:w [#1]
{
\dim_set:Nn \l_mylist_item_symbol_sep_vii_dim {#1}
\legacy_if_set_true:n { @noitemarg }
\__mylist_start_item_vii:w [ \l_mylist_label_vii_tl ]
}
% Print numbered \item [ \legacy_if_set_true:n { @hyper@item } (hyperref-doc p170) ]
\cs_new_protected:Nn \__mylist_print_number_item_vii:
{
\legacy_if:nT { @noitemarg }
{
\legacy_if_set_false:n { @noitemarg }
\legacy_if:nT { @nmbrlist }
{
\bool_if:NT \l_mylist_hyperref_bool
{
\legacy_if_set_true:n { @hyper@item }
}
\refstepcounter{mycounxvii}
}
}
}
% Fake \makelabel using \makebox
\cs_new_protected:Npn \__mylist_fake_make_label_vii:n #1
{
\bool_if:NT \l_mylist_item_starred_vii_bool
{
\tl_if_blank:VT \g_mylist_item_symbol_aux_vii_tl
{
\tl_gset_eq:NN \g_mylist_item_symbol_aux_vii_tl \l_mylist_item_symbol_vii_tl
}
\mode_leave_vertical:
\skip_horizontal:n { -\l_mylist_item_symbol_sep_vii_dim }
\hbox_overlap_left:n { \g_mylist_item_symbol_aux_vii_tl }
\skip_horizontal:N \l_mylist_item_symbol_sep_vii_dim
\tl_gclear:N \g_mylist_item_symbol_aux_vii_tl
}
\bool_if:NTF \l_mylist_wrap_label_vii_bool
{
\makebox[ \l_mylist_labelwidth_vii_dim ][ \l_mylist_align_label_vii_str ]
{
\tl_use:N \l_mylist_label_font_style_vii_tl
\__mylist_wrapper_label_vii:n {#1}
}
}
{
\makebox[ \l_mylist_labelwidth_vii_dim ][ \l_mylist_align_label_vii_str ]
{
\tl_use:N \l_mylist_label_font_style_vii_tl #1
}
}
\skip_horizontal:N \l_mylist_labelsep_vii_dim
}
% Real \item definition
\cs_new_protected_nopar:Npn \__mylist_start_item_vii:w [#1]
{
\cs_set_eq:NN \__mylist_stop_item_tmp_vii: \__mylist_stop_item_vii:
\__mylist_print_number_item_vii:
\box_clear:N \l_mylist_item_text_vii_box
\hbox_set_to_wd:Nnw \l_mylist_item_text_vii_box
{
\l_mylist_joined_width_vii_dim
+ \l_mylist_labelwidth_vii_dim
+ \l_mylist_labelsep_vii_dim
}
\__mylist_fake_make_label_vii:n {#1}
\begin{minipage}[t]{ \l_mylist_joined_width_vii_dim }
\dim_set_eq:NN \parindent \l_mylist_listparindent_vii_dim
\skip_set_eq:NN \parskip \l_mylist_parsep_vii_skip
\tl_use:N \l_mylist_fake_item_indent_vii_tl
}
\cs_new_protected_nopar:Nn \__mylist_stop_item_vii:
{
\end{minipage}
\hbox_set_end:
\int_set:Nn \hbadness { 10000 }
\box_use_drop:N \l_mylist_item_text_vii_box
\int_compare:nNnTF
{ \l_mylist_item_column_pos_vii_int } = { \l_mylist_columns_vii_int }
{
\par\noindent
\int_zero:N \l_mylist_item_column_pos_vii_int
}
{
\skip_horizontal:N \l_mylist_columns_sep_vii_dim
}
}
% Remove extra \parsep (\itemsep)
\cs_new_protected:Nn \__mylist_remove_extra_parsep_vii:
{
\int_compare:nNnT
{
\int_mod:nn
{ \g_mylist_item_count_all_vii_int } { \l_mylist_columns_vii_int }
}
=
{ 0 }
{
\para_end:
\skip_vertical:n { -\l_mylist_itemsep_vii_skip }
\skip_vertical:N \c_zero_skip
\int_gzero:N \g_mylist_item_count_all_vii_int
}
}
\ExplSyntaxOff
\begin{document}
\begin{enumerate}
\item Using \texttt{enumerate} first \verb|\item| here.
\item Using \texttt{enumerate} second \verb|\item| here.
\end{enumerate}
\begin{mylist*}[columns=1]
\item Using \texttt{mylist*} first \verb|\item| here.
\item Using \texttt{mylist*} first \verb|\item| here.
\end{mylist*}
\end{document}
@hyper@item
should not be needed.tagging
when using\item
(which caused problems), the real capture that I want is in the function\__mylist_start_item_vii:w
and that is where I must applytagging
to generate the list.