From c528b15d140e943c90fe291699b2fa080fcb4ac2 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Tue, 1 Mar 2022 21:53:05 +0000 Subject: tabularray (1mar22) git-svn-id: svn://tug.org/texlive/trunk@62328 c570f23f-e606-0410-a88d-b1316a301751 --- .../tex/latex/tabularray/tabularray-2021.sty | 3234 ++++++++++++++++---- .../texmf-dist/tex/latex/tabularray/tabularray.sty | 909 ++++-- 2 files changed, 3307 insertions(+), 836 deletions(-) (limited to 'Master/texmf-dist/tex/latex') diff --git a/Master/texmf-dist/tex/latex/tabularray/tabularray-2021.sty b/Master/texmf-dist/tex/latex/tabularray/tabularray-2021.sty index 8e5c2b93694..f5ad547d716 100644 --- a/Master/texmf-dist/tex/latex/tabularray/tabularray-2021.sty +++ b/Master/texmf-dist/tex/latex/tabularray/tabularray-2021.sty @@ -12,13 +12,12 @@ \NeedsTeXFormat{LaTeX2e} \RequirePackage{expl3} -\ProvidesExplPackage{tabularray}{2021-06-05}{2021K} +\ProvidesExplPackage{tabularray}{2021-12-01}{2021Q} {Typeset tabulars and arrays with LaTeX3} \RequirePackage{xparse} -\AtBeginDocument{\@ifpackageloaded{xcolor}{\RequirePackage{ninecolors}}{}} -\ExplSyntaxOn +\AtBeginDocument{\@ifpackageloaded{xcolor}{\RequirePackage{ninecolors}}{}} %% Backport \tl_if_eq:NnTF for old texlive 2020 \cs_if_exist:NF \tl_if_eq:NnTF @@ -53,10 +52,12 @@ \cs_generate_variant:Nn \tl_const:Nn { ce } \cs_generate_variant:Nn \tl_log:n { x } \cs_generate_variant:Nn \tl_gput_right:Nn { Nf } +\cs_generate_variant:Nn \tl_put_left:Nn { Nv } \prg_generate_conditional_variant:Nnn \clist_if_in:Nn { Nx } { TF } \prg_generate_conditional_variant:Nnn \prop_if_in:Nn { c } { T } \prg_generate_conditional_variant:Nnn \str_if_eq:nn { xn } { TF } \prg_generate_conditional_variant:Nnn \tl_if_eq:nn { en } { T, TF } +\prg_generate_conditional_variant:Nnn \tl_if_head_eq_catcode:nN { VN } { TF } \prg_generate_conditional_variant:Nnn \tl_if_head_eq_meaning:nN { VN } { T, TF } \tl_new:N \l__tblr_a_tl @@ -97,11 +98,33 @@ \box_new:N \l__tblr_c_box % for cell box \box_new:N \l__tblr_d_box -%% Some counters for row and column numbering -\newcounter{rownum} -\newcounter{colnum} -\newcounter{rowcount} -\newcounter{colcount} +%% Total number of tblr tables +\int_new:N \g__tblr_table_count_int + +%% Some commands for horizontal alignment +\cs_new_eq:NN \__tblr_halign_command_l: \raggedright +\cs_new_eq:NN \__tblr_halign_command_c: \centering +\cs_new_eq:NN \__tblr_halign_command_r: \raggedleft + +%% Some counters for row and column numbering. +%% We may need to restore all LaTeX counters in measuring and building cells, +%% so we must not define these counters with \newcounter command. +\int_new:N \c@rownum +\int_new:N \c@colnum +\int_new:N \c@rowcount +\int_new:N \c@colcount + +%% Add missing \therownum, \thecolnum, \therowcount, \thecolcount (issue #129) +\NewExpandableDocumentCommand \therownum {} { \@arabic \c@rownum } +\NewExpandableDocumentCommand \thecolnum {} { \@arabic \c@colnum } +\NewExpandableDocumentCommand \therowcount {} { \@arabic \c@rowcount } +\NewExpandableDocumentCommand \thecolcount {} { \@arabic \c@colcount } + +%% Some dimensions for row and column spacing +\dim_new:N \abovesep +\dim_new:N \belowsep +\dim_new:N \leftsep +\dim_new:N \rightsep %%% -------------------------------------------------------- %% \section{Data Structures Based on Property Lists} @@ -113,7 +136,10 @@ { \prop_gclear_new:c { g__tblr_text_ \int_use:N \g_tblr_level_int _prop } \prop_gclear_new:c { g__tblr_command_ \int_use:N \g_tblr_level_int _prop } - \prop_gclear_new:c { g__tblr_table_ \int_use:N \g_tblr_level_int _prop } + \prop_gclear_new:c { g__tblr_inner_ \int_use:N \g_tblr_level_int _prop } + \prop_gclear_new:c { g__tblr_note_ \int_use:N \g_tblr_level_int _prop } + \prop_gclear_new:c { g__tblr_remark_ \int_use:N \g_tblr_level_int _prop } + \prop_gclear_new:c { g__tblr_more_ \int_use:N \g_tblr_level_int _prop } \prop_gclear_new:c { g__tblr_row_ \int_use:N \g_tblr_level_int _prop } \prop_gclear_new:c { g__tblr_column_ \int_use:N \g_tblr_level_int _prop } \prop_gclear_new:c { g__tblr_cell_ \int_use:N \g_tblr_level_int _prop } @@ -184,7 +210,7 @@ { \dim_compare_p:nNn { #3 } > { \l__tblr_put_if_larger_tl } } { \prop_put:Nnn #1 { #2 } { #3 } } } -\cs_generate_variant:Nn \__tblr_put_if_larger:Nnn { Nnx, Nxn, Nxx } +\cs_generate_variant:Nn \__tblr_put_if_larger:Nnn { Nnx, Nxn, Nxx, NnV } \cs_new_protected:Npn \__tblr_gput_if_larger:Nnn #1 #2 #3 { @@ -215,63 +241,78 @@ %% \section{Data Structures Based on Token Lists} %%% -------------------------------------------------------- -\cs_new_protected:Npn \__tblr_clear_text_lists: +\cs_new_protected:Npn \__tblr_clear_spec_lists: { - \__tblr_clear_one_text_lists:n { text } - \__tblr_clear_one_text_lists:n { hline } - \__tblr_clear_one_text_lists:n { vline } + %\__tblr_clear_one_spec_lists:n { row } + %\__tblr_clear_one_spec_lists:n { column } + %\__tblr_clear_one_spec_lists:n { cell } + \__tblr_clear_one_spec_lists:n { text } + \__tblr_clear_one_spec_lists:n { hline } + \__tblr_clear_one_spec_lists:n { vline } + \__tblr_clear_one_spec_lists:n { outer } } -\cs_new_protected:Npn \__tblr_clear_one_text_lists:n #1 +\cs_new_protected:Npn \__tblr_clear_one_spec_lists:n #1 { \clist_if_exist:cTF { g__tblr_#1_ \int_use:N \g_tblr_level_int _clist } { \clist_map_inline:cn { g__tblr_#1_ \int_use:N \g_tblr_level_int _clist } { - \tl_gclear:c { g__tblr_text_ \int_use:N \g_tblr_level_int _#1_##1_tl } + \tl_gclear:c { g__tblr_spec_ \int_use:N \g_tblr_level_int _#1_##1_tl } } } { \clist_new:c { g__tblr_#1_ \int_use:N \g_tblr_level_int _clist } } } -\cs_new_protected:Npn \__tblr_text_gput:nnn #1 #2 #3 +\cs_new_protected:Npn \__tblr_spec_gput:nnn #1 #2 #3 { \tl_gset:cn - { g__tblr_text_ \int_use:N \g_tblr_level_int _#1_#2_tl } {#3} + { g__tblr_spec_ \int_use:N \g_tblr_level_int _#1_#2_tl } {#3} \clist_gput_right:cx { g__tblr_#1_ \int_use:N \g_tblr_level_int _clist } {#2} } -\cs_generate_variant:Nn \__tblr_text_gput:nnn { nne, nnV, nen, nee, neV } +\cs_generate_variant:Nn \__tblr_spec_gput:nnn { nne, nnV, nen, nee, neV } -\cs_new:Npn \__tblr_text_item:nn #1 #2 +\cs_new:Npn \__tblr_spec_item:nn #1 #2 { - \tl_if_exist:cT { g__tblr_text_ \int_use:N \g_tblr_level_int _#1_#2_tl } + \tl_if_exist:cT { g__tblr_spec_ \int_use:N \g_tblr_level_int _#1_#2_tl } { \exp_args:Nv \exp_not:n - { g__tblr_text_ \int_use:N \g_tblr_level_int _#1_#2_tl } + { g__tblr_spec_ \int_use:N \g_tblr_level_int _#1_#2_tl } } } -\cs_generate_variant:Nn \__tblr_text_item:nn { ne } +\cs_generate_variant:Nn \__tblr_spec_item:nn { ne } -\cs_new_protected:Npn \__tblr_text_gput_if_larger:nnn #1 #2 #3 +\cs_new_protected:Npn \__tblr_spec_gput_if_larger:nnn #1 #2 #3 { - \tl_set:Nx \l__tblr_put_if_larger_tl { \__tblr_text_item:nn {#1} {#2} } + \tl_set:Nx \l__tblr_put_if_larger_tl { \__tblr_spec_item:nn {#1} {#2} } \bool_lazy_or:nnT { \tl_if_empty_p:N \l__tblr_put_if_larger_tl } { \dim_compare_p:nNn {#3} > { \l__tblr_put_if_larger_tl } } - { \__tblr_text_gput:nnn {#1} {#2} {#3} } + { \__tblr_spec_gput:nnn {#1} {#2} {#3} } + } +\cs_generate_variant:Nn \__tblr_spec_gput_if_larger:nnn { nne, nnV, nen, nee, neV } + +\cs_new_protected:Npn \__tblr_spec_gadd_dimen_value:nnn #1 #2 #3 + { + \__tblr_spec_gput:nne {#1} {#2} + { \dim_eval:n { \__tblr_spec_item:ne {#1} {#2} + #3 } } } -\cs_generate_variant:Nn \__tblr_text_gput_if_larger:nnn { nne, nnV, nen, nee, neV } +\cs_generate_variant:Nn \__tblr_spec_gadd_dimen_value:nnn { nne, nnV, nen, nee } -\cs_new_protected:Npn \__tblr_text_log:n #1 +\cs_new_protected:Npn \__tblr_spec_log:n #1 { \clist_gremove_duplicates:c { g__tblr_#1_ \int_use:N \g_tblr_level_int _clist } - \tl_log:n { ----------~----------~----------~----------~---------- } + \tl_log:x + { + The ~ spec ~ list ~ #1 _ \int_use:N \g_tblr_level_int + \space contains ~ the ~ pairs: + } \clist_map_inline:cn { g__tblr_#1_ \int_use:N \g_tblr_level_int _clist } { \tl_log:x { - \space { #1 ##1 } ~\space=>~\space { \__tblr_text_item:nn {#1} {##1} } + \space { ##1 } ~\space=>~\space { \__tblr_spec_item:nn {#1} {##1} } } } } @@ -321,6 +362,7 @@ \__tblr_data_new_key:nnn { row } { @row-foot } { dim } \__tblr_data_new_key:nnn { row } { @row-upper } { dim } \__tblr_data_new_key:nnn { row } { @row-lower } { dim } +\__tblr_data_new_key:nnn { row } { break } { int } \int_new:N \g__tblr_data_column_key_count_int \__tblr_data_new_key:nnn { column } { width } { dim } @@ -336,6 +378,10 @@ \__tblr_data_new_key:nnn { cell } { halign } { str } \__tblr_data_new_key:nnn { cell } { valign } { str } \__tblr_data_new_key:nnn { cell } { background } { str } +\__tblr_data_new_key:nnn { cell } { foreground } { str } +\__tblr_data_new_key:nnn { cell } { font } { str } +\__tblr_data_new_key:nnn { cell } { mode } { str } +\__tblr_data_new_key:nnn { cell } { cmd } { str } \__tblr_data_new_key:nnn { cell } { omit } { int } \__tblr_data_new_key:nnn { cell } { @cell-width } { dim } \__tblr_data_new_key:nnn { cell } { @cell-height } { dim } @@ -350,12 +396,12 @@ \tl_const:Nn \g__tblr_data_cell_index_number_tl {2} \int_new:N \g__tblr_array_int -\cs_new_protected:Npn \__tblr_initial_table_data: +\cs_new_protected:Npn \__tblr_init_table_data: { - \clist_map_function:NN \g__tblr_data_clist \__tblr_initial_one_data:n + \clist_map_function:NN \g__tblr_data_clist \__tblr_init_one_data:n } -\cs_new_protected:Npn \__tblr_initial_one_data:n #1 +\cs_new_protected:Npn \__tblr_init_one_data:n #1 { \int_gincr:N \g__tblr_array_int \intarray_new:cn { g__tblr_#1_ \int_use:N \g__tblr_array_int _intarray } @@ -507,18 +553,18 @@ \cs_new_protected:Npn \__tblr_data_int_from_str:n #1 { - \tl_if_exist:cTF { g__tblr_data_#1_to_int_tl } + \tl_if_exist:cTF { g__tblr_data_ \tl_to_str:n {#1} _to_int_tl } { \tl_gset_eq:Nc \g__tblr_data_int_from_value_tl - { g__tblr_data_#1_to_int_tl } + { g__tblr_data_ \tl_to_str:n {#1} _to_int_tl } } { \int_gincr:N \g__tblr_data_str_value_count_int - \tl_gset:cx { g__tblr_data_#1_to_int_tl } + \tl_gset:cx { g__tblr_data_ \tl_to_str:n {#1} _to_int_tl } { \int_use:N \g__tblr_data_str_value_count_int } - \tl_gset:cx + \tl_gset:cn { g__tblr_data_ \int_use:N \g__tblr_data_str_value_count_int _to_str_tl } - { #1 } + { \exp_not:n {#1} } \tl_gset:Nx \g__tblr_data_int_from_value_tl { \int_use:N \g__tblr_data_str_value_count_int } } @@ -661,7 +707,8 @@ { \__tblr_data_key_to_int:nnn {#1} {#2} {#3} } { \g__tblr_data_int_from_value_tl } } -\cs_generate_variant:Nn \__tblr_data_gadd_dimen_value:nnnn { nnne, nnnV, nene } +\cs_generate_variant:Nn \__tblr_data_gadd_dimen_value:nnnn + { nnne, nnnV, nenn, nene } \cs_new_protected:Npn \__tblr_array_gadd_value:Nnn #1 #2 #3 { @@ -678,39 +725,39 @@ { \cs_set_protected:Npn \__tblr_data_gput:nnnn #1 #2 #3 #4 { - \__tblr_prop_gput:nnn {#1} { [#2] / #3 } {#4} + \__tblr_spec_gput:nnn {#1} { [#2] / #3 } {#4} } \cs_set_protected:Npn \__tblr_data_gput:nnnnn #1 #2 #3 #4 #5 { - \__tblr_prop_gput:nnn {#1} { [#2][#3] / #4 } {#5} + \__tblr_spec_gput:nnn {#1} { [#2][#3] / #4 } {#5} } \cs_set:Npn \__tblr_data_item:nnn #1 #2 #3 { - \__tblr_prop_item:nn {#1} { [#2] / #3 } + \__tblr_spec_item:nn {#1} { [#2] / #3 } } \cs_set:Npn \__tblr_data_item:nnnn #1 #2 #3 #4 { - \__tblr_prop_item:nn {#1} { [#2][#3] / #4 } + \__tblr_spec_item:nn {#1} { [#2][#3] / #4 } } \cs_set_protected:Npn \__tblr_data_log:n #1 { - \__tblr_prop_log:n {#1} + \__tblr_spec_log:n {#1} } \cs_set_protected:Npn \__tblr_data_gput_if_larger:nnnn #1 #2 #3 #4 { - \__tblr_prop_gput_if_larger:nnn {#1} { [#2] / #3 } {#4} + \__tblr_spec_gput_if_larger:nnn {#1} { [#2] / #3 } {#4} } \cs_set_protected:Npn \__tblr_data_gput_if_larger:nnnnn #1 #2 #3 #4 #5 { - \__tblr_prop_gput_if_larger:nnn {#1} { [#2][#3] / #4 } {#5} + \__tblr_spec_gput_if_larger:nnn {#1} { [#2][#3] / #4 } {#5} } \cs_set_protected:Npn \__tblr_data_gadd_dimen_value:nnnn #1 #2 #3 #4 { - \__tblr_prop_gadd_dimen_value:nnn {#1} { [#2] / #3 } {#4} + \__tblr_spec_gadd_dimen_value:nnn {#1} { [#2] / #3 } {#4} } \cs_set_protected:Npn \__tblr_data_gadd_dimen_value:nnnnn #1 #2 #3 #4 #5 { - \__tblr_prop_gadd_dimen_value:nnn {#1} { [#2][#3] / #4 } {#5} + \__tblr_spec_gadd_dimen_value:nnn {#1} { [#2][#3] / #4 } {#5} } } } @@ -818,12 +865,30 @@ } } +\tl_new:N \l__tblr_child_from_tl +\tl_new:N \l__tblr_child_to_tl + \cs_new_protected_nopar:Npn \__tblr_get_childs_normal_aux:w #1 - #2 \scan_stop { - \int_step_inline:nnn {#1} {#2} + \__tblr_child_name_to_index:nN {#1} \l__tblr_child_from_tl + \__tblr_child_name_to_index:nN {#2} \l__tblr_child_to_tl + \int_step_inline:nnn { \l__tblr_child_from_tl } { \l__tblr_child_to_tl } { \clist_put_right:Nn \l_tblr_childs_clist {##1} } } +\regex_const:Nn \c__tblr_child_name_regex { ^ [X-Z] $ } + +%% Convert X, Y, Z to the indexes of the last three childs, respectively +\cs_new_protected_nopar:Npn \__tblr_child_name_to_index:nN #1 #2 + { + \regex_match:NnTF \c__tblr_child_name_regex {#1} + { + \tl_set:Nx #2 + { \int_eval:n { \l_tblr_childs_total_tl + \int_from_alph:n {#1} - 26 } } + } + { \tl_set:Nx #2 { #1 } } + } + %%% -------------------------------------------------------- %% \section{New Table Commands} %%% -------------------------------------------------------- @@ -889,6 +954,54 @@ \int_set:Nn \c@colnum {#2} } +%% Table commands are defined only inside tblr environments, +%% but some packages such as csvsimple need to use them outside tblr environments, +%% therefore we define some of them first here. +\ProvideDocumentCommand \SetHlines { o m m } {} +\ProvideDocumentCommand \SetHline { o m m } {} +\ProvideDocumentCommand \SetVlines { o m m } {} +\ProvideDocumentCommand \SetVline { o m m } {} +\ProvideDocumentCommand \SetCells { o m } {} +\ProvideDocumentCommand \SetCell { o m } {} +\ProvideDocumentCommand \SetRows { o m } {} +\ProvideDocumentCommand \SetRow { o m } {} +\ProvideDocumentCommand \SetColumns { o m } {} +\ProvideDocumentCommand \SetColumn { o m } {} + +%%% -------------------------------------------------------- +%%> \section{New Content Commands} +%%% -------------------------------------------------------- + +%% We need to emulate or fix some commands such as \diagbox in other packages +%% These commands must be defined with \NewContentCommand command +%% We only enable them inside tblr environment to avoid potential conflict + +\clist_new:N \g__tblr_content_commands_clist + +\msg_new:nnn { tabularray } { defined-content-command } + { Content ~ commnad ~ #1 has ~ been ~ defined! } + +\NewDocumentCommand \NewContentCommand { m O{0} o m } + { + \clist_if_in:NnTF \g__tblr_content_commands_clist { #1 } + { + \msg_warning:nnn { tabularray } { defined-content-command } { #1 } + \clist_log:N \g__tblr_content_commands_clist + } + { + \__tblr_make_xparse_arg_spec:nnN { #2 } { #3 } \l__tblr_a_tl + \exp_args:NcV \NewDocumentCommand + { __tblr_content_command_ \cs_to_str:N #1 :w } \l__tblr_a_tl { #4 } + \clist_gput_right:Nn \g__tblr_content_commands_clist { #1 } + } + } + +\cs_new_protected:Npn \__tblr_enable_content_commands: + { + \clist_map_inline:Nn \g__tblr_content_commands_clist + { \cs_set_eq:Nc ##1 { __tblr_content_command_ \cs_to_str:N ##1 :w } } + } + %%% -------------------------------------------------------- %% \section{New Dash Styles} %%% -------------------------------------------------------- @@ -1007,11 +1120,18 @@ \tl_new:N \l__tblr_hline_dash_tl % dash style \tl_new:N \l__tblr_hline_fg_tl % dash foreground \tl_new:N \l__tblr_hline_wd_tl % dash width +\tl_new:N \l__tblr_hline_leftpos_tl % left position +\tl_new:N \l__tblr_hline_rightpos_tl % right position +\bool_new:N \l__tblr_hline_endpos_bool % whether set positions only for both ends \NewTableCommand \cline [2] [] { \SetHline [=] {#2} {#1} } \NewTableCommand \hline [1] [] { \SetHline [+] {-} {#1} } +%% Some keys can be set by any hline, such as abovespace and belowspace keys. +%% Using special hline of index 0, you can set these keys without adding any hlines. +\NewTableCommand \SetVspace [1] { \SetHline [0] {-} {#1} } + %% #1: the index of the hline (may be + or =) %% #2: which columns of the hline, separate by commas %% #3: key=value pairs @@ -1025,13 +1145,19 @@ \cs_new_protected:Npn \tblr_set_hline:nnn #1 #2 #3 { \group_begin: - \keys_set_groups:nnn { tblr-hline } { text } {#3} - \tl_if_eq:NnF \l__tblr_hline_dash_tl { \exp_not:N \@tblr@text } + %% We can not use \int_compare:nNnTF here since #1 may be + or = . + %% Also we treat hline of index 0 specially, not adding hline count. + \tl_if_eq:nnTF {#1} {0} + { \keys_set:nn { tblr-hline } {#3} } { - \__tblr_set_hline_num:n {#1} - \tl_clear:N \l__tblr_hline_dash_tl - \keys_set:nn { tblr-hline } { dash = solid, #3 } - \__tblr_set_hline_cmd:n {#2} + \keys_set_groups:nnn { tblr-hline } { text } {#3} + \tl_if_eq:NnF \l__tblr_hline_dash_tl { \exp_not:N \@tblr@text } + { + \__tblr_set_hline_num:n {#1} + \tl_clear:N \l__tblr_hline_dash_tl + \keys_set:nn { tblr-hline } { dash = solid, #3 } + \__tblr_set_hline_cmd:n {#2} + } } \group_end: } @@ -1068,12 +1194,12 @@ { \tl_clear:N \l__tblr_hline_num_tl \tl_set:Nx \l__tblr_hline_count_tl - { \__tblr_text_item:ne { hline } { [\int_use:N \c@rownum] / @hline-count } } + { \__tblr_spec_item:ne { hline } { [\int_use:N \c@rownum] / @hline-count } } %% \l__tblr_hline_count_tl may be empty when rowspec has extra |'s \int_compare:nNnTF { \l__tblr_hline_count_tl + 0 } = {0} { \tl_set:Nx \l__tblr_hline_num_tl { 1 } - \__tblr_text_gput:nen { hline } + \__tblr_spec_gput:nen { hline } { [\int_use:N \c@rownum] / @hline-count } { 1 } } { @@ -1095,7 +1221,7 @@ { \tl_set:Nx \l__tblr_hline_count_tl { \int_eval:n { \l__tblr_hline_count_tl + 1 } } - \__tblr_text_gput:nee { hline } + \__tblr_spec_gput:nee { hline } { [\int_use:N \c@rownum] / @hline-count } { \l__tblr_hline_count_tl } \tl_set_eq:NN \l__tblr_hline_num_tl \l__tblr_hline_count_tl } @@ -1108,6 +1234,21 @@ wd .code:n = \tl_set:Nn \l__tblr_hline_wd_tl { \dim_eval:n {#1} }, fg .code:n = \tl_set:Nn \l__tblr_hline_fg_tl {#1}, baseline .code:n = \__tblr_hline_set_baseline:n {#1}, + leftpos .code:n = \tl_set:Nx \l__tblr_hline_leftpos_tl {#1}, + rightpos .code:n = \tl_set:Nx \l__tblr_hline_rightpos_tl {#1}, + l .meta:n = { leftpos = #1 }, + l .default:n = { -0.8 }, + r .meta:n = { rightpos = #1 }, + r .default:n = { -0.8 }, + lr .meta:n = { leftpos = #1, rightpos = #1 }, + lr .default:n = { -0.8 }, + endpos .bool_set:N = \l__tblr_hline_endpos_bool, + abovespace .code:n = \__tblr_row_gput_above:ne { belowsep } { \dim_eval:n {#1} }, + belowspace .code:n = \__tblr_row_gput:ne { abovesep } { \dim_eval:n {#1} }, + abovespace+ .code:n = \__tblr_row_gadd_dimen_above:ne + { belowsep } { \dim_eval:n {#1} }, + belowspace+ .code:n = \__tblr_row_gadd_dimen:ne + { abovesep } { \dim_eval:n {#1} }, unknown .code:n = \__tblr_hline_unknown_key:V \l_keys_key_str, } @@ -1131,24 +1272,59 @@ \__tblr_get_childs:nx {#1} { \int_use:N \c@colcount } \clist_map_inline:Nn \l_tblr_childs_clist { - \__tblr_text_gput:nee { hline } - { [\int_use:N \c@rownum][##1](\l__tblr_hline_num_tl) / @dash } - { \l__tblr_hline_dash_tl } + \__tblr_set_hline_option:nnn { ##1 } { @dash } { \l__tblr_hline_dash_tl } \tl_if_empty:NF \l__tblr_hline_wd_tl { - \__tblr_text_gput:nee { hline } - { [\int_use:N \c@rownum][##1](\l__tblr_hline_num_tl) / wd } - { \l__tblr_hline_wd_tl } + \__tblr_set_hline_option:nnn { ##1 } { wd } { \l__tblr_hline_wd_tl } } \tl_if_empty:NF \l__tblr_hline_fg_tl { - \__tblr_text_gput:nee { hline } - { [\int_use:N \c@rownum][##1](\l__tblr_hline_num_tl) / fg } - { \l__tblr_hline_fg_tl } + \__tblr_set_hline_option:nnn { ##1 } { fg } { \l__tblr_hline_fg_tl } + } + } + \tl_if_empty:NF \l__tblr_hline_leftpos_tl + { + \bool_if:NTF \l__tblr_hline_endpos_bool + { + \__tblr_set_hline_option:nnn + { \clist_item:Nn \l_tblr_childs_clist {1} } + { leftpos } + { \l__tblr_hline_leftpos_tl } + } + { + \clist_map_inline:Nn \l_tblr_childs_clist + { + \__tblr_set_hline_option:nnn + { ##1 } { leftpos } { \l__tblr_hline_leftpos_tl } + } + } + } + \tl_if_empty:NF \l__tblr_hline_rightpos_tl + { + \bool_if:NTF \l__tblr_hline_endpos_bool + { + \__tblr_set_hline_option:nnn + { \clist_item:Nn \l_tblr_childs_clist {-1} } + { rightpos } + { \l__tblr_hline_rightpos_tl } + } + { + \clist_map_inline:Nn \l_tblr_childs_clist + { + \__tblr_set_hline_option:nnn + { ##1 } { rightpos } { \l__tblr_hline_rightpos_tl } + } } } } +%% #1: column; #2: key; #3: value +\cs_new_protected_nopar:Npn \__tblr_set_hline_option:nnn #1 #2 #3 + { + \__tblr_spec_gput:nee { hline } + { [\int_use:N \c@rownum][#1](\l__tblr_hline_num_tl) / #2 } { #3 } + } + \NewTableCommand \firsthline [1] [] { \SetHline [+] {-} { #1, baseline=below } } \NewTableCommand \lasthline [1] [] { \SetHline [+] {-} { #1, baseline=above } } @@ -1156,13 +1332,13 @@ { \tl_if_eq:nnTF {#1} {above} { - \__tblr_prop_gput:nnx { table } + \__tblr_prop_gput:nnx { inner } { baseline } { \int_eval:n { \c@rownum - 1 } } } { \tl_if_eq:nnT {#1} {below} { - \__tblr_prop_gput:nnx { table } { baseline } { \int_use:N \c@rownum } + \__tblr_prop_gput:nnx { inner } { baseline } { \int_use:N \c@rownum } } } } @@ -1206,6 +1382,8 @@ \tl_new:N \l__tblr_vline_dash_tl % dash style \tl_new:N \l__tblr_vline_fg_tl % dash foreground \tl_new:N \l__tblr_vline_wd_tl % dash width +\tl_new:N \l__tblr_vline_abovepos_tl % above position +\tl_new:N \l__tblr_vline_belowpos_tl % below position \NewTableCommand \rline [2] [] { \SetVline [=] {#2} {#1} } @@ -1267,12 +1445,12 @@ { \tl_clear:N \l__tblr_vline_num_tl \tl_set:Nx \l__tblr_vline_count_tl - { \__tblr_text_item:ne { vline } { [\int_use:N \c@colnum] / @vline-count } } + { \__tblr_spec_item:ne { vline } { [\int_use:N \c@colnum] / @vline-count } } %% \l__tblr_vline_count_tl may be empty when colspec has extra |'s \int_compare:nNnTF { \l__tblr_vline_count_tl + 0 } = {0} { \tl_set:Nx \l__tblr_vline_num_tl { 1 } - \__tblr_text_gput:nen { vline } + \__tblr_spec_gput:nen { vline } { [\int_use:N \c@colnum] / @vline-count } { 1 } } { @@ -1294,7 +1472,7 @@ { \tl_set:Nx \l__tblr_vline_count_tl { \int_eval:n { \l__tblr_vline_count_tl + 1 } } - \__tblr_text_gput:nee { vline } + \__tblr_spec_gput:nee { vline } { [\int_use:N \c@colnum] / @vline-count } { \l__tblr_vline_count_tl } \tl_set_eq:NN \l__tblr_vline_num_tl \l__tblr_vline_count_tl } @@ -1306,6 +1484,8 @@ text .groups:n = { text }, wd .code:n = \tl_set:Nn \l__tblr_vline_wd_tl { \dim_eval:n {#1} }, fg .code:n = \tl_set:Nn \l__tblr_vline_fg_tl {#1}, + abovepos .code:n = \tl_set:Nx \l__tblr_vline_abovepos_tl {#1}, + belowpos .code:n = \tl_set:Nx \l__tblr_vline_belowpos_tl {#1}, unknown .code:n = \__tblr_vline_unknown_key:V \l_keys_key_str, } @@ -1329,21 +1509,33 @@ \__tblr_get_childs:nx {#1} { \int_use:N \c@rowcount } \clist_map_inline:Nn \l_tblr_childs_clist { - \__tblr_text_gput:nee { vline } + \__tblr_spec_gput:nee { vline } { [##1][\int_use:N \c@colnum](\l__tblr_vline_num_tl) / @dash } { \l__tblr_vline_dash_tl } \tl_if_empty:NF \l__tblr_vline_wd_tl { - \__tblr_text_gput:nee { vline } + \__tblr_spec_gput:nee { vline } { [##1][\int_use:N \c@colnum](\l__tblr_vline_num_tl) / wd } { \l__tblr_vline_wd_tl } } \tl_if_empty:NF \l__tblr_vline_fg_tl { - \__tblr_text_gput:nee { vline } + \__tblr_spec_gput:nee { vline } { [##1][\int_use:N \c@colnum](\l__tblr_vline_num_tl) / fg } { \l__tblr_vline_fg_tl } } + \tl_if_empty:NF \l__tblr_vline_abovepos_tl + { + \__tblr_spec_gput:nee { vline } + { [##1][\int_use:N \c@colnum](\l__tblr_vline_num_tl) / abovepos } + { \l__tblr_vline_abovepos_tl } + } + \tl_if_empty:NF \l__tblr_vline_belowpos_tl + { + \__tblr_spec_gput:nee { vline } + { [##1][\int_use:N \c@colnum](\l__tblr_vline_num_tl) / belowpos } + { \l__tblr_vline_belowpos_tl } + } } } @@ -1440,36 +1632,45 @@ \keys_define:nn { tblr-cell-spec } { - l .code:n = \__tblr_data_gput:neenn { cell } - { \int_use:N \c@rownum } { \int_use:N \c@colnum } { halign } {l}, - c .code:n = \__tblr_data_gput:neenn { cell } - { \int_use:N \c@rownum } { \int_use:N \c@colnum } { halign } {c}, - r .code:n = \__tblr_data_gput:neenn { cell } - { \int_use:N \c@rownum } { \int_use:N \c@colnum } { halign } {r}, - t .code:n = \__tblr_data_gput:neenn { cell } - { \int_use:N \c@rownum } { \int_use:N \c@colnum } { valign} {t}, - p .code:n = \__tblr_data_gput:neenn { cell } - { \int_use:N \c@rownum } { \int_use:N \c@colnum } { valign} {t}, - m .code:n = \__tblr_data_gput:neenn { cell } - { \int_use:N \c@rownum } { \int_use:N \c@colnum } { valign} {m}, - b .code:n = \__tblr_data_gput:neenn { cell } - { \int_use:N \c@rownum } { \int_use:N \c@colnum } { valign} {b}, - h .code:n = \__tblr_data_gput:neenn { cell } - { \int_use:N \c@rownum } { \int_use:N \c@colnum } { valign} {h}, - f .code:n = \__tblr_data_gput:neenn { cell } - { \int_use:N \c@rownum } { \int_use:N \c@colnum } { valign} {f}, - wd .code:n = \__tblr_data_gput:neene { cell } - { \int_use:N \c@rownum } { \int_use:N \c@colnum } { width } {#1}, - bg .code:n = \__tblr_data_gput:neene { cell } - { \int_use:N \c@rownum } { \int_use:N \c@colnum } - { background } {#1}, - preto .code:n = \__tblr_cell_preto_text:n {#1}, - appto .code:n = \__tblr_cell_appto_text:n {#1}, - fg .code:n = \__tblr_cell_preto_text:n { \color{#1} }, - font .code:n = \__tblr_cell_preto_text:n { #1 \selectfont }, + halign .code:n = \__tblr_cell_gput:nn { halign } {#1}, + valign .code:n = \__tblr_cell_gput:nn { valign } {#1}, + j .meta:n = { halign = j }, + l .meta:n = { halign = l }, + c .meta:n = { halign = c }, + r .meta:n = { halign = r }, + t .meta:n = { valign = t }, + p .meta:n = { valign = t }, + m .meta:n = { valign = m }, + b .meta:n = { valign = b }, + h .meta:n = { valign = h }, + f .meta:n = { valign = f }, + wd .code:n = \__tblr_cell_gput:ne { width } {#1}, + bg .code:n = \__tblr_cell_gput:ne { background } {#1}, + fg .code:n = \__tblr_cell_gput:ne { foreground } {#1}, + font .code:n = \__tblr_cell_gput:nn { font } { #1 \selectfont }, + mode .code:n = \__tblr_cell_gput:nn { mode } {#1}, + $ .meta:n = { mode = math }, + $$ .meta:n = { mode = dmath }, + cmd .code:n = \__tblr_cell_gput:nn { cmd } {#1}, + preto .code:n = \__tblr_cell_preto_text:n {#1}, + appto .code:n = \__tblr_cell_appto_text:n {#1}, unknown .code:n = \__tblr_cell_unknown_key:V \l_keys_key_str, } +\cs_new_protected:Npn \__tblr_cell_gput:nn #1 #2 + { + \__tblr_data_gput:neenn { cell } + { \int_use:N \c@rownum } { \int_use:N \c@colnum } {#1} {#2} + } +\cs_generate_variant:Nn \__tblr_cell_gput:nn { ne } + +\cs_new_protected:Npn \__tblr_cell_gput:nnnn #1 #2 #3 #4 + { + \__tblr_data_gput:nnnnn { cell } {#1} {#2} {#3} {#4} + } +\cs_generate_variant:Nn \__tblr_cell_gput:nnnn + { nenn, ennn, eenn, nene, enne, eene } + \tl_new:N \l__tblr_cell_text_tl \cs_new_protected:Npn \__tblr_cell_preto_text:n #1 @@ -1480,9 +1681,9 @@ \cs_new_protected:Npn \__tblr_cell_preto_text:nnn #1 #2 #3 { - \tl_set:Nx \l__tblr_cell_text_tl { \__tblr_text_item:nn { text } { [#1][#2] } } + \tl_set:Nx \l__tblr_cell_text_tl { \__tblr_spec_item:nn { text } { [#1][#2] } } \tl_put_left:Nn \l__tblr_cell_text_tl {#3} - \__tblr_text_gput:nnV { text } { [#1][#2] } \l__tblr_cell_text_tl + \__tblr_spec_gput:nnV { text } { [#1][#2] } \l__tblr_cell_text_tl } \cs_generate_variant:Nn \__tblr_cell_preto_text:nnn { nen, enn, een } @@ -1494,9 +1695,9 @@ \cs_new_protected:Npn \__tblr_cell_appto_text:nnn #1 #2 #3 { - \tl_set:Nx \l__tblr_cell_text_tl { \__tblr_text_item:ne { text } { [#1][#2] } } + \tl_set:Nx \l__tblr_cell_text_tl { \__tblr_spec_item:ne { text } { [#1][#2] } } \tl_put_right:Nn \l__tblr_cell_text_tl {#3} - \__tblr_text_gput:neV { text } { [#1][#2] } \l__tblr_cell_text_tl + \__tblr_spec_gput:neV { text } { [#1][#2] } \l__tblr_cell_text_tl } \cs_generate_variant:Nn \__tblr_cell_appto_text:nnn { nen, enn, een } @@ -1520,13 +1721,13 @@ { \int_compare:nNnT { #1 } > { 1 } { - \__tblr_prop_gput:nnn {table} {rowspan} {true} + \__tblr_prop_gput:nnn { inner } { rowspan } { true } \__tblr_data_gput:neenn { cell } { \int_use:N \c@rownum } { \int_use:N \c@colnum } { rowspan } {#1} } \int_compare:nNnT { #2 } > { 1 } { - \__tblr_prop_gput:nnn {table} {colspan} {true} + \__tblr_prop_gput:nnn { inner } { colspan } { true } \__tblr_data_gput:neenn { cell } { \int_use:N \c@rownum } { \int_use:N \c@colnum } { colspan } {#2} } @@ -1546,16 +1747,33 @@ } \int_compare:nNnF { \l__tblr_i_tl } = { \c@rownum } { - \__tblr_text_gput:nen { hline } + \__tblr_spec_gput:nen { hline } { [\l__tblr_i_tl][\l__tblr_j_tl] / omit } {true} } \int_compare:nNnF { \l__tblr_j_tl } = { \c@colnum } { - \__tblr_text_gput:nee { vline } + \__tblr_spec_gput:nee { vline } { [\l__tblr_i_tl][\l__tblr_j_tl] / omit } {true} } } } + %% Make continuous borders for multirow cells + \tl_set:Nx \l__tblr_n_tl + { + \int_max:nn + { + \__tblr_spec_item:ne { vline } { [\int_use:N \c@colnum] / @vline-count } + } + { 1 } + } + \int_step_variable:nnNn + { \c@rownum } { \int_eval:n { \c@rownum + #1 -1 } } \l__tblr_i_tl + { + \__tblr_spec_gput:nee { vline } + { [\l__tblr_i_tl][\int_use:N \c@colnum](\l__tblr_n_tl) / belowpos } {1} + \__tblr_spec_gput:nee { vline } + { [\l__tblr_i_tl][\int_eval:n {\c@colnum + #2}](1) / belowpos } {1} + } } \cs_generate_variant:Nn \__tblr_set_span_spec:nn { VV } @@ -1678,53 +1896,63 @@ \keys_define:nn { tblr-column } { - l .code:n = \__tblr_set_key_for_every_column_cell:nnn - { \int_use:N \c@colnum } { halign } {l}, - c .code:n = \__tblr_set_key_for_every_column_cell:nnn - { \int_use:N \c@colnum } { halign } {c}, - r .code:n = \__tblr_set_key_for_every_column_cell:nnn - { \int_use:N \c@colnum } { halign } {r}, - t .code:n = \__tblr_set_key_for_every_column_cell:nnn - { \int_use:N \c@colnum } { valign } {t}, - p .code:n = \__tblr_set_key_for_every_column_cell:nnn - { \int_use:N \c@colnum } { valign } {t}, - m .code:n = \__tblr_set_key_for_every_column_cell:nnn - { \int_use:N \c@colnum } { valign } {m}, - b .code:n = \__tblr_set_key_for_every_column_cell:nnn - { \int_use:N \c@colnum } { valign } {b}, - h .code:n = \__tblr_set_key_for_every_column_cell:nnn - { \int_use:N \c@colnum } { valign } {h}, - f .code:n = \__tblr_set_key_for_every_column_cell:nnn - { \int_use:N \c@colnum } { valign } {f}, - bg .code:n = \__tblr_set_key_for_every_column_cell:nnn - { \int_use:N \c@colnum } { background } {#1}, - fg .code:n = \__tblr_preto_text_for_every_column_cell:n { \color{#1} }, - font .code:n = \__tblr_preto_text_for_every_column_cell:n { #1 \selectfont }, - wd .code:n = \__tblr_data_gput:nene { column } - { \int_use:N \c@colnum } { width } { \dim_eval:n {#1} }, - co .code:n = \__tblr_data_gput:nene { column } - { \int_use:N \c@colnum } { coefficient } {#1}, - leftsep .code:n = \__tblr_data_gput:nene { column } - { \int_use:N \c@colnum } { leftsep } { \dim_eval:n {#1} }, - rightsep .code:n = \__tblr_data_gput:nene { column } - { \int_use:N \c@colnum } { rightsep } { \dim_eval:n {#1} }, - colsep .meta:n = { leftsep = #1, rightsep = #1}, - leftsep+ .code:n = \__tblr_data_gadd_dimen_value:nene { column } - { \int_use:N \c@colnum } { leftsep } { \dim_eval:n {#1} }, - rightsep+ .code:n = \__tblr_data_gadd_dimen_value:nene { column } - { \int_use:N \c@colnum } { rightsep } { \dim_eval:n {#1} }, - colsep+ .meta:n = { leftsep+ = #1, rightsep+ = #1}, - unknown .code:n = \__tblr_column_unknown_key:V \l_keys_key_str, - } - -%% #1: column number; #2: key; #3: value -\cs_new_protected:Npn \__tblr_set_key_for_every_column_cell:nnn #1 #2 #3 + halign .code:n = \__tblr_column_gput_cell:nn { halign } {#1}, + valign .code:n = \__tblr_column_gput_cell:nn { valign } {#1}, + j .meta:n = { halign = j }, + l .meta:n = { halign = l }, + c .meta:n = { halign = c }, + r .meta:n = { halign = r }, + t .meta:n = { valign = t }, + p .meta:n = { valign = t }, + m .meta:n = { valign = m }, + b .meta:n = { valign = b }, + h .meta:n = { valign = h }, + f .meta:n = { valign = f }, + bg .code:n = \__tblr_column_gput_cell:nn { background } {#1}, + fg .code:n = \__tblr_column_gput_cell:nn { foreground } {#1}, + font .code:n = \__tblr_column_gput_cell:nn { font } { #1 \selectfont }, + mode .code:n = \__tblr_column_gput_cell:nn { mode } {#1}, + $ .meta:n = { mode = math }, + $$ .meta:n = { mode = dmath }, + cmd .code:n = \__tblr_column_gput_cell:nn { cmd } {#1}, + wd .code:n = \__tblr_column_gput:ne { width } { \dim_eval:n {#1} }, + co .code:n = \__tblr_column_gput:ne { coefficient } {#1}, + preto .code:n = \__tblr_preto_text_for_every_column_cell:n {#1}, + appto .code:n = \__tblr_appto_text_for_every_column_cell:n {#1}, + leftsep .code:n = \__tblr_column_gput:ne { leftsep } { \dim_eval:n {#1} }, + rightsep .code:n = \__tblr_column_gput:ne { rightsep } { \dim_eval:n {#1} }, + colsep .meta:n = { leftsep = #1, rightsep = #1}, + leftsep+ .code:n = \__tblr_column_gadd_dimen:ne + { leftsep } { \dim_eval:n {#1} }, + rightsep+ .code:n = \__tblr_column_gadd_dimen:ne + { rightsep } { \dim_eval:n {#1} }, + colsep+ .meta:n = { leftsep+ = #1, rightsep+ = #1}, + unknown .code:n = \__tblr_column_unknown_key:V \l_keys_key_str, + } + +%% #1: key; #2: value +\cs_new_protected:Npn \__tblr_column_gput:nn #1 #2 + { + \__tblr_data_gput:nenn { column } { \int_use:N \c@colnum } {#1} {#2} + } +\cs_generate_variant:Nn \__tblr_column_gput:nn { ne } + +\cs_new_protected:Npn \__tblr_column_gadd_dimen:nn #1 #2 + { + \__tblr_data_gadd_dimen_value:nenn { column } + { \int_use:N \c@colnum } {#1} {#2} + } +\cs_generate_variant:Nn \__tblr_column_gadd_dimen:nn { ne } + +%% #1: key; #2: value +\cs_new_protected:Npn \__tblr_column_gput_cell:nn #1 #2 { \int_step_inline:nn { \c@rowcount } { - \__tblr_data_gput:neenn { cell } {##1} {#1} {#2} {#3} + \__tblr_cell_gput:nenn {##1} { \int_use:N \c@colnum } {#1} {#2} } } +\cs_generate_variant:Nn \__tblr_column_gput_cell:nn { ne } \cs_new_protected:Npn \__tblr_preto_text_for_every_column_cell:n #1 { @@ -1747,20 +1975,13 @@ \cs_new_protected:Npn \__tblr_column_unknown_key:n #1 { \regex_match:NnTF \c__tblr_is_number_key_regex {#1} - { - \__tblr_data_gput:nene { column } - { \int_use:N \c@colnum } { coefficient } {#1} - } + { \__tblr_column_gput:ne { coefficient } {#1} } { \regex_match:NnTF \c__tblr_is_color_key_regex {#1} - { - \__tblr_set_key_for_every_column_cell:nnn - { \int_use:N \c@colnum } { background } {#1} - } + { \__tblr_column_gput_cell:nn { background } {#1} } { \tl_set_rescan:Nnn \l__tblr_v_tl {} {#1} - \__tblr_data_gput:nene { column } - { \int_use:N \c@colnum } { width } { \dim_eval:n { \l__tblr_v_tl } } + \__tblr_column_gput:ne { width } { \dim_eval:n { \l__tblr_v_tl } } } } } @@ -1830,55 +2051,76 @@ \keys_define:nn { tblr-row } { - l .code:n = \__tblr_set_key_for_every_row_cell:nnn - { \int_use:N \c@rownum } { halign } {l}, - c .code:n = \__tblr_set_key_for_every_row_cell:nnn - { \int_use:N \c@rownum } { halign } {c}, - r .code:n = \__tblr_set_key_for_every_row_cell:nnn - { \int_use:N \c@rownum } { halign } {r}, - t .code:n = \__tblr_set_key_for_every_row_cell:nnn - { \int_use:N \c@rownum } { valign } {t}, - p .code:n = \__tblr_set_key_for_every_row_cell:nnn - { \int_use:N \c@rownum } { valign } {t}, - m .code:n = \__tblr_set_key_for_every_row_cell:nnn - { \int_use:N \c@rownum } { valign } {m}, - b .code:n = \__tblr_set_key_for_every_row_cell:nnn - { \int_use:N \c@rownum } { valign } {b}, - h .code:n = \__tblr_set_key_for_every_row_cell:nnn - { \int_use:N \c@rownum } { valign } {h}, - f .code:n = \__tblr_set_key_for_every_row_cell:nnn - { \int_use:N \c@rownum } { valign } {f}, - bg .code:n = \__tblr_set_key_for_every_row_cell:nnn - { \int_use:N \c@rownum } { background } {#1}, - fg .code:n = \__tblr_preto_text_for_every_row_cell:n { \color{#1} }, - font .code:n = \__tblr_preto_text_for_every_row_cell:n { #1 \selectfont }, - ht .code:n = \__tblr_data_gput:nene { row } { \int_use:N \c@rownum } - { height } { \dim_eval:n {#1} }, - co .code:n = \__tblr_data_gput:nene { row } { \int_use:N \c@rownum } - { coefficient } {#1}, - abovesep .code:n = \__tblr_data_gput:nene { row } { \int_use:N \c@rownum } - { abovesep } { \dim_eval:n {#1} }, - belowsep .code:n = \__tblr_data_gput:nene { row } { \int_use:N \c@rownum } - { belowsep } { \dim_eval:n {#1} }, - rowsep .meta:n = { abovesep = #1, belowsep = #1}, - abovesep+ .code:n = \__tblr_data_gadd_dimen_value:nene { row } - { \int_use:N \c@rownum } { abovesep } { \dim_eval:n {#1} }, - belowsep+ .code:n = \__tblr_data_gadd_dimen_value:nene { row } - { \int_use:N \c@rownum } { belowsep } { \dim_eval:n {#1} }, - rowsep+ .meta:n = { abovesep+ = #1, belowsep+ = #1}, - nobreak .code:n = \__tblr_prop_gput:nxx { row } - { [\int_eval:n {\c@rownum - 1}] / nobreak } { true }, - unknown .code:n = \__tblr_row_unknown_key:V \l_keys_key_str, - } - -%% #1: row number; #2: key; #3: value -\cs_new_protected:Npn \__tblr_set_key_for_every_row_cell:nnn #1 #2 #3 + halign .code:n = \__tblr_row_gput_cell:nn { halign } {#1}, + valign .code:n = \__tblr_row_gput_cell:nn { valign } {#1}, + j .meta:n = { halign = j }, + l .meta:n = { halign = l }, + c .meta:n = { halign = c }, + r .meta:n = { halign = r }, + t .meta:n = { valign = t }, + p .meta:n = { valign = t }, + m .meta:n = { valign = m }, + b .meta:n = { valign = b }, + h .meta:n = { valign = h }, + f .meta:n = { valign = f }, + bg .code:n = \__tblr_row_gput_cell:nn { background } {#1}, + fg .code:n = \__tblr_row_gput_cell:nn { foreground } {#1}, + font .code:n = \__tblr_row_gput_cell:nn { font } { #1 \selectfont }, + mode .code:n = \__tblr_row_gput_cell:nn { mode } {#1}, + $ .meta:n = { mode = math }, + $$ .meta:n = { mode = dmath }, + cmd .code:n = \__tblr_row_gput_cell:nn { cmd } {#1}, + ht .code:n = \__tblr_row_gput:ne { height } { \dim_eval:n {#1} }, + co .code:n = \__tblr_row_gput:ne { coefficient } {#1}, + preto .code:n = \__tblr_preto_text_for_every_row_cell:n {#1}, + appto .code:n = \__tblr_appto_text_for_every_row_cell:n {#1}, + abovesep .code:n = \__tblr_row_gput:ne { abovesep } { \dim_eval:n {#1} }, + belowsep .code:n = \__tblr_row_gput:ne { belowsep } { \dim_eval:n {#1} }, + rowsep .meta:n = { abovesep = #1, belowsep = #1}, + abovesep+ .code:n = \__tblr_row_gadd_dimen:ne { abovesep } { \dim_eval:n {#1} }, + belowsep+ .code:n = \__tblr_row_gadd_dimen:ne { belowsep } { \dim_eval:n {#1} }, + rowsep+ .meta:n = { abovesep+ = #1, belowsep+ = #1}, + break .code:n = \__tblr_row_gput:nn { break } {#1}, + pagebreak .meta:n = { break = 1 }, + nopagebreak .meta:n = { break = -1 }, + unknown .code:n = \__tblr_row_unknown_key:V \l_keys_key_str, + } + +%% #1: key; #2: value +\cs_new_protected:Npn \__tblr_row_gput:nn #1 #2 + { + \__tblr_data_gput:nenn { row } { \int_use:N \c@rownum } {#1} {#2} + } +\cs_generate_variant:Nn \__tblr_row_gput:nn { ne } + +\cs_new_protected:Npn \__tblr_row_gput_above:nn #1 #2 + { + \__tblr_data_gput:nenn { row } { \int_eval:n { \c@rownum - 1 } } {#1} {#2} + } +\cs_generate_variant:Nn \__tblr_row_gput_above:nn { ne } + +\cs_new_protected:Npn \__tblr_row_gadd_dimen:nn #1 #2 + { + \__tblr_data_gadd_dimen_value:nenn { row } { \int_use:N \c@rownum } {#1} {#2} + } +\cs_generate_variant:Nn \__tblr_row_gadd_dimen:nn { ne } + +\cs_new_protected:Npn \__tblr_row_gadd_dimen_above:nn #1 #2 + { + \__tblr_data_gadd_dimen_value:nenn { row } + { \int_eval:n { \c@rownum - 1 } } {#1} {#2} + } +\cs_generate_variant:Nn \__tblr_row_gadd_dimen_above:nn { ne } + +%% #1: key; #2: value +\cs_new_protected:Npn \__tblr_row_gput_cell:nn #1 #2 { \int_step_inline:nn { \c@colcount } { - \__tblr_data_gput:neenn { cell } {#1} {##1} {#2} {#3} + \__tblr_cell_gput:ennn { \int_use:N \c@rownum } {##1} {#1} {#2} } } +\cs_generate_variant:Nn \__tblr_row_gput_cell:nn { ne } \cs_new_protected:Npn \__tblr_preto_text_for_every_row_cell:n #1 { @@ -1905,19 +2147,25 @@ } { \regex_match:NnTF \c__tblr_is_color_key_regex {#1} + { \__tblr_row_gput_cell:nn { background } {#1} } { - \__tblr_set_key_for_every_row_cell:nnn - { \int_use:N \c@rownum } { background } {#1} - } - { - \tl_set_rescan:Nnn \l__tblr_v_tl {} {#1} - \__tblr_data_gput:nene { row } { \int_use:N \c@rownum } - { height } { \dim_eval:n { \l__tblr_v_tl } } + \tl_set_rescan:Nnn \l__tblr_v_tl {} {#1} + \__tblr_row_gput:ne { height } { \dim_eval:n { \l__tblr_v_tl } } } } } \cs_generate_variant:Nn \__tblr_row_unknown_key:n { V } +\NewTableCommand \pagebreak + { + \tblr_set_row:nn {} { break = 1 } + } + +\NewTableCommand \nopagebreak + { + \tblr_set_row:nn {} { break = -1 } + } + %%% -------------------------------------------------------- %% \section{Column Types and Row Types} %%% -------------------------------------------------------- @@ -2117,6 +2365,7 @@ \NewColumnRowType { l } { Q[l] } \NewColumnRowType { c } { Q[c] } \NewColumnRowType { r } { Q[r] } +\NewColumnRowType { j } { Q[j] } \NewColumnType { t } [1] { Q[t,wd=#1] } \NewColumnType { p } [1] { Q[p,wd=#1] } @@ -2179,7 +2428,10 @@ } { \str_if_in:cnTF { g_tblr_used_ \g__tblr_column_or_row_tl _types_str } {#1} - { \cs:w tblr_ \g__tblr_column_or_row_tl _type_ #1 \cs_end: } + { + %% Note that #1 may be an active character (see issue #58) + \cs:w tblr_ \g__tblr_column_or_row_tl _type_ \token_to_str:N #1 \cs_end: + } { \msg_error:nnVn { tabularray } { unknown-colrow-type } \g__tblr_column_or_row_tl {#1} @@ -2205,43 +2457,102 @@ } %%% -------------------------------------------------------- -%% \section{Tabularray Environments} +%% \section{Set Environments and New Environments} %%% -------------------------------------------------------- +\tl_new:N \l__tblr_initial_tblr_outer_tl +\tl_set:Nn \l__tblr_initial_tblr_outer_tl + { + halign = c, valign = m, headsep = 6pt, footsep = 6pt, + presep = 1.5\bigskipamount, postsep = 1.5\bigskipamount, + } + +%% #1: env name; #2: specifications +\NewDocumentCommand \SetTblrInner { O{tblr} m } + { + \tl_put_right:cn { l__tblr_default_ #1 _inner_tl } { , #2 } + \ignorespaces + } +\cs_new_eq:NN \SetTblrDefault \SetTblrInner + +%% #1: env name; #2: specifications +\NewDocumentCommand \SetTblrOuter { O{tblr} m } + { + \tl_put_right:cn { l__tblr_default_ #1 _outer_tl } { , #2 } + \ignorespaces + } + +%% #1: env name +\NewDocumentCommand \NewTblrEnviron { m } + { + \tl_new:c { l__tblr_default_ #1 _outer_tl } + \tl_set_eq:cN { l__tblr_default_ #1 _outer_tl } \l__tblr_initial_tblr_outer_tl + \tl_new:c { l__tblr_default_ #1 _inner_tl } + \NewDocumentEnvironment {#1} { O{c} m +b } + { + \__tblr_environ_code:nnnn {#1} {##1} {##2} {##3} + } { } + \ignorespaces + } + +%% Create tblr and longtblr environments +\NewTblrEnviron { tblr } +\NewTblrEnviron { longtblr } +\SetTblrOuter [ longtblr ] { long } +\NewTblrEnviron { talltblr } +\SetTblrOuter [ talltblr ] { tall } + \tl_new:N \l__tblr_env_name_tl \bool_new:N \l__tblr_math_mode_bool -\NewDocumentEnvironment { tblr } { O{c} m +b } +%% Main environment code +\cs_new_protected:Npn \__tblr_environ_code:nnnn #1 #2 #3 #4 { - \tl_set:Nn \l__tblr_env_name_tl { tblr } + \int_gincr:N \g__tblr_table_count_int + \tl_set:Nn \l__tblr_env_name_tl {#1} \mode_if_math:TF { \bool_set_true:N \l__tblr_math_mode_bool } { \bool_set_false:N \l__tblr_math_mode_bool } - \buildtblr {#1} {#2} {#3} - } { } + \__tblr_builder:nnn {#2} {#3} {#4} + } %% Read, split and build the table - -\cs_new_protected:Npn \buildtblr #1 #2 #3 +\cs_new_protected:Npn \__tblr_builder:nnn #1 #2 #3 { - \mode_leave_vertical: \int_gincr:N \g_tblr_level_int \__tblr_clear_prop_lists: - \__tblr_clear_text_lists: + \__tblr_clear_spec_lists: + \LogTblrTracing { step = init ~ table ~ outer ~ spec} + \__tblr_init_table_outer_spec: + \LogTblrTracing { step = parse ~ table ~ options } + \__tblr_parse_table_option:n {#1} + \LogTblrTracing { outer } + \LogTblrTracing { option } \__tblr_enable_table_commands: - \__tblr_split_table:n { #3 } + \LogTblrTracing { step = split ~ table} + \__tblr_split_table:n {#3} \LogTblrTracing { command } - \bool_if:NT \g__tblr_use_intarray_bool { \__tblr_initial_table_data: } - \__tblr_initial_table_spec: - \LogTblrTracing { table } - \__tblr_parse_table_spec:n { #2 } + \bool_if:NT \g__tblr_use_intarray_bool { \__tblr_init_table_data: } + \LogTblrTracing { step = init ~ table ~ inner ~ spec} + \__tblr_init_table_inner_spec: + \LogTblrTracing { inner } + \LogTblrTracing { step = parse ~ table ~ inner ~ spec} + \__tblr_parse_table_spec:n {#2} + \LogTblrTracing { step = execute ~ table ~ commands} \__tblr_execute_table_commands: \__tblr_disable_table_commands: + \LogTblrTracing { step = calculate ~ cell ~ and ~ line ~ sizes} + \__tblr_enable_content_commands: \__tblr_calc_cell_and_line_sizes: - \__tblr_build_whole:n { #1 } + \LogTblrTracing { step = build ~ the ~ whole ~ table} + \__tblr_build_whole: \int_gdecr:N \g_tblr_level_int } +%%% -------------------------------------------------------- +%% \section{Split Table Contents} +%%% -------------------------------------------------------- + %% Insert and remove braces for nesting environments inside cells %% These make line split and cell split workable %% We need to replace N times for N level nestings @@ -2272,35 +2583,54 @@ \regex_replace_all:NVN \c__tblr_remove_braces_regex \c__tblr_remove_braces_tl #1 } -%% Split table content to cells and store them -%% #1: table content +\tl_new:N \l__tblr_body_tl +\tl_new:N \l__tblr_expand_tl +\seq_new:N \l__tblr_lines_seq -\seq_new:N \l_tblr_lines_seq +%% Expand every occurrence of the specified macro once +%% #1: table content; #2: macro to be expanded +\cs_new_protected:Npn \__tblr_expand_table_body:nN #1 #2 + { + \tl_clear:N \l__tblr_body_tl + \cs_set_protected:Npn \__tblr_expand_table_body_aux:w ##1 #2 + { + \tl_put_right:Nn \l__tblr_body_tl {##1} + \peek_meaning:NTF \q_stop + { \use_none:n } + { \exp_last_unbraced:NV \__tblr_expand_table_body_aux:w #2 } + } + \__tblr_expand_table_body_aux:w #1 #2 \q_stop + } +%% Split table content to cells and store them +%% #1: table content \cs_new_protected:Npn \__tblr_split_table:n #1 { + \tl_set:Nx \l__tblr_expand_tl { \__tblr_spec_item:nn { outer } { expand } } + \tl_set:Nx \l__tblr_expand_tl { \tl_head:N \l__tblr_expand_tl } + \tl_if_empty:NTF \l__tblr_expand_tl + { \tl_set:Nn \l__tblr_body_tl {#1} } + { \exp_args:NnV \__tblr_expand_table_body:nN {#1} \l__tblr_expand_tl } \int_zero:N \c@rowcount \int_zero:N \c@colcount - \__tblr_split_table_to_lines:nN { #1 } \l_tblr_lines_seq - \__tblr_split_lines_to_cells:N \l_tblr_lines_seq + \__tblr_split_table_to_lines:NN \l__tblr_body_tl \l__tblr_lines_seq + \__tblr_split_lines_to_cells:N \l__tblr_lines_seq } %% Split table content to a sequence of lines -%% #1: table content, #2: resulting sequence of lines -\cs_new_protected:Npn \__tblr_split_table_to_lines:nN #1 #2 +%% #1: tl with table contents, #2: resulting sequence of lines +\cs_new_protected:Npn \__tblr_split_table_to_lines:NN #1 #2 { - \tl_set:Nn \l_tmpa_tl { #1 } - \__tblr_insert_braces:N \l_tmpa_tl - \seq_set_split:NnV \l_tmpa_seq { \\ } \l_tmpa_tl + \__tblr_insert_braces:N #1 + \seq_set_split:NnV \l_tmpa_seq { \\ } #1 \seq_clear:N #2 \seq_map_inline:Nn \l_tmpa_seq { \tl_if_head_eq_meaning:nNTF {##1} * { - \tl_set:Nn \l__tblr_b_tl { \SetRow{nobreak} } + \tl_set:Nn \l__tblr_b_tl { \SetRow { break = -1 } } \tl_set:Nx \l__tblr_c_tl { \tl_tail:n {##1} } \tl_trim_spaces:N \l__tblr_c_tl %% Ignore spaces between * and [dimen] - \tl_log:N \l__tblr_c_tl \tl_if_head_eq_meaning:VNT \l__tblr_c_tl [ { \tl_put_right:Nn \l__tblr_b_tl { \RowBefore@AddBelowSep } @@ -2346,16 +2676,21 @@ { \tl_set:Nn \l_tmpa_tl { ##1 } \__tblr_remove_braces:N \l_tmpa_tl + \__tblr_trim_par_space_tokens:N \l_tmpa_tl \int_incr:N \c@colnum \__tblr_extract_table_commands:N \l_tmpa_tl - \__tblr_text_gput:neV { text } { [#1][\int_use:N \c@colnum] } \l_tmpa_tl + \__tblr_trim_par_space_tokens:N \l_tmpa_tl + \__tblr_spec_gput:neV { text } { [#1][\int_use:N \c@colnum] } \l_tmpa_tl \__tblr_add_multicolumn_empty_cell: } %% Decrease row count by 1 if the last row has only one empty cell text %% We need to do it here since the > or < column type may add text to cells - \bool_lazy_and:nnTF - { \int_compare_p:nNn {\c@colnum} = {1} } - { \tl_if_empty_p:N \l_tmpa_tl } + \bool_lazy_all:nTF + { + { \int_compare_p:nNn {#1} = {\c@rowcount} } + { \int_compare_p:nNn {\c@colnum} = {1} } + { \tl_if_empty_p:N \l_tmpa_tl } + } { \int_decr:N \c@rowcount } { \__tblr_prop_gput:nnx @@ -2367,13 +2702,22 @@ } } +\regex_const:Nn \c__tblr_trim_left_par_space_regex { ^ \c{par} ? \s * } +\regex_const:Nn \c__tblr_trim_right_space_par_regex { \s * \c{par} ? $ } + +\cs_new_protected:Npn \__tblr_trim_par_space_tokens:N #1 + { + \regex_replace_once:NnN \c__tblr_trim_left_par_space_regex {} #1 + \regex_replace_once:NnN \c__tblr_trim_right_space_par_regex {} #1 + } + %% Add empty cells after the \multicolumn span cell \cs_new_protected:Npn \__tblr_add_multicolumn_empty_cell: { \int_step_inline:nn { \l__multicolumn_cell_number_int - 1 } { \int_incr:N \c@colnum - \__tblr_text_gput:nen { text } + \__tblr_spec_gput:nen { text } { [\int_use:N \c@rownum][\int_use:N \c@colnum] } { } } } @@ -2395,7 +2739,7 @@ \tl_clear:N \l__tblr_saved_table_commands_before_cell_text_tl \tl_clear:N \l__tblr_saved_cell_text_after_table_commands_tl \int_set:Nn \l__multicolumn_cell_number_int {1} - \exp_last_unbraced:NV \__tblr_extract_table_commands_next:w #1 \scan_stop: + \exp_last_unbraced:NV \__tblr_extract_table_commands_next:n #1 \q_stop \tl_if_empty:NF \l__tblr_saved_table_commands_before_cell_text_tl { \__tblr_prop_gput:nxV { command } @@ -2405,26 +2749,26 @@ \tl_set_eq:NN #1 \l__tblr_saved_cell_text_after_table_commands_tl } -%% #1 maybe a single token or multiple tokens given in braces -\cs_new_protected:Npn \__tblr_extract_table_commands_next:w #1 +%% #1 maybe a single token or multiple tokens from a pair of braces +\cs_new_protected:Npn \__tblr_extract_table_commands_next:n #1 { - \clist_if_in:NnTF \g__tblr_table_commands_clist { #1 } - { - \clist_if_in:NnTF \g__tblr_table_commands_unbrace_next_clist { #1 } - { \bool_set_true:N \l__tblr_table_command_unbrace_next_bool } - { \bool_set_false:N \l__tblr_table_command_unbrace_next_bool } - \token_if_eq_meaning:NNTF #1 \multicolumn - { \__tblr_extract_multicolumn_command:Nn #1 } - { \__tblr_extract_one_table_command:N #1 } - } + \tl_if_single_token:nTF {#1} { - \tl_if_single_token:nTF {#1} + \clist_if_in:NnTF \g__tblr_table_commands_clist { #1 } + { + \clist_if_in:NnTF \g__tblr_table_commands_unbrace_next_clist { #1 } + { \bool_set_true:N \l__tblr_table_command_unbrace_next_bool } + { \bool_set_false:N \l__tblr_table_command_unbrace_next_bool } + \token_if_eq_meaning:NNTF #1 \multicolumn + { \__tblr_extract_multicolumn_command:Nn #1 } + { \__tblr_extract_one_table_command:N #1 } + } { - \token_if_eq_meaning:NNF #1 \scan_stop: + \token_if_eq_meaning:NNF #1 \q_stop { \__tblr_save_real_cell_text:w #1 } } - { \__tblr_save_real_cell_text:w {#1} } } + { \__tblr_save_real_cell_text:w {#1} } } \cs_new_protected:Npn \__tblr_extract_multicolumn_command:Nn #1 #2 @@ -2469,30 +2813,30 @@ } { \bool_if:NTF \l__tblr_table_command_unbrace_next_bool - { \__tblr_last_unbraced:Nn \__tblr_extract_table_commands_next:w } - { \__tblr_extract_table_commands_next:w } + { \__tblr_last_unbraced:Nn \__tblr_extract_table_commands_next:n } + { \__tblr_extract_table_commands_next:n } } } \cs_new_protected:Npn \__tblr_last_unbraced:Nn #1 #2 { #1 #2 } %% The outermost set of braces of cell text #1 will be removed -\cs_new_protected:Npn \__tblr_save_real_cell_text:w #1 \scan_stop: +\cs_new_protected:Npn \__tblr_save_real_cell_text:w #1 \q_stop { \tl_set:Nn \l__tblr_saved_cell_text_after_table_commands_tl {#1} } %%% -------------------------------------------------------- -%% \section{Initial Table Specifications} +%% \section{Initialize Table Inner Specifications} %%% -------------------------------------------------------- -\prop_gset_from_keyval:Nn \g__tblr_default_tblr_table_prop +\prop_gset_from_keyval:Nn \g__tblr_initial_table_prop { stretch = 1, rulesep = 2pt, } -\prop_gset_from_keyval:Nn \g__tblr_default_tblr_rows_prop +\prop_gset_from_keyval:Nn \g__tblr_initial_rows_prop { abovesep = 2pt, belowsep = 2pt, @@ -2503,7 +2847,7 @@ @row-lower = 0pt, } -\prop_gset_from_keyval:Nn \g__tblr_default_tblr_columns_prop +\prop_gset_from_keyval:Nn \g__tblr_initial_columns_prop { leftsep = 6pt, rightsep = 6pt, @@ -2512,7 +2856,7 @@ @col-width = 0pt, } -\prop_gset_from_keyval:Nn \g__tblr_default_tblr_cells_prop +\prop_gset_from_keyval:Nn \g__tblr_initial_cells_prop { halign = l, valign = t, @@ -2522,97 +2866,93 @@ omit = 0, } -\prop_gset_from_keyval:Nn \g__tblr_default_tblr_hlines_prop +\prop_gset_from_keyval:Nn \g__tblr_initial_hlines_prop { @hline-count = 0, } -\prop_gset_from_keyval:Nn \g__tblr_default_tblr_vlines_prop +\prop_gset_from_keyval:Nn \g__tblr_initial_vlines_prop { @vline-count = 0, } -\cs_new_protected:Npn \__tblr_initial_table_spec: +\tl_new:N \l__tblr_inner_spec_measure_tl +\tl_new:N \l__tblr_inner_spec_verb_tl + +\cs_new_protected:Npn \__tblr_init_table_inner_spec: { - \prop_map_inline:cn { g__tblr_default_ \l__tblr_env_name_tl _table_prop } + \prop_map_inline:Nn \g__tblr_initial_table_prop { - \__tblr_prop_gput:nxn { table } { ##1 } {##2} + \__tblr_prop_gput:nxn { inner } { ##1 } {##2} } \int_step_variable:nNn { \c@rowcount } \l__tblr_i_tl { - \prop_map_inline:cn { g__tblr_default_ \l__tblr_env_name_tl _rows_prop } + \prop_map_inline:Nn \g__tblr_initial_rows_prop { \__tblr_data_gput:nVnn { row } \l__tblr_i_tl {##1} {##2} } - \prop_map_inline:cn { g__tblr_default_ \l__tblr_env_name_tl _hlines_prop } + \prop_map_inline:Nn \g__tblr_initial_hlines_prop { - \__tblr_text_gput:nen { hline } { [\l__tblr_i_tl] / ##1 } {##2} + \__tblr_spec_gput:nen { hline } { [\l__tblr_i_tl] / ##1 } {##2} } \int_step_variable:nNn { \c@colcount } \l__tblr_j_tl { - \prop_map_inline:cn - { g__tblr_default_ \l__tblr_env_name_tl _cells_prop } + \prop_map_inline:Nn \g__tblr_initial_cells_prop { \__tblr_data_gput:neeen { cell } { \l__tblr_i_tl } { \l__tblr_j_tl } {##1} {##2} } } } - \prop_map_inline:cn { g__tblr_default_ \l__tblr_env_name_tl _hlines_prop } + \prop_map_inline:Nn \g__tblr_initial_hlines_prop { - \__tblr_text_gput:nen { hline } + \__tblr_spec_gput:nen { hline } { [\int_eval:n { \c@rowcount + 1}] / ##1 } {##2} } \int_step_variable:nNn { \c@colcount } \l__tblr_j_tl { - \prop_map_inline:cn { g__tblr_default_ \l__tblr_env_name_tl _columns_prop } + \prop_map_inline:Nn \g__tblr_initial_columns_prop { \__tblr_data_gput:nenn { column } { \l__tblr_j_tl } {##1} {##2} } - \prop_map_inline:cn { g__tblr_default_ \l__tblr_env_name_tl _vlines_prop } + \prop_map_inline:Nn \g__tblr_initial_vlines_prop { - \__tblr_text_gput:nen { vline } { [\l__tblr_j_tl] / ##1 } {##2} + \__tblr_spec_gput:nen { vline } { [\l__tblr_j_tl] / ##1 } {##2} } } - \prop_map_inline:cn { g__tblr_default_ \l__tblr_env_name_tl _vlines_prop } + \prop_map_inline:Nn \g__tblr_initial_vlines_prop { - \__tblr_text_gput:nen { vline } + \__tblr_spec_gput:nen { vline } { [\int_eval:n { \c@colcount + 1}] / ##1 } {##2} } - \keys_set:nv { tblr } { l__tblr_default_ \l__tblr_env_name_tl _tl } + \tl_clear:N \l__tblr_inner_spec_measure_tl + \tl_clear:N \l__tblr_inner_spec_verb_tl + \keys_set:nv { tblr } { l__tblr_default_ \l__tblr_env_name_tl _inner_tl } } -\tl_new:N \l__tblr_default_tblr_tl - -%% #1: env name; #2: options -\NewDocumentCommand \SetTabularrayDefault { O{tblr} m } - { - \tl_put_right:cn { l__tblr_default_ #1 _tl } { , #2 } - } -\cs_new_eq:NN \SetTblrDefault \SetTabularrayDefault - %%% -------------------------------------------------------- -%% \section{Parse Table Specifications} +%%> \section{Parse Table Inner Specifications} %%% -------------------------------------------------------- \clist_new:N \g__tblr_table_known_keys_clist \clist_gset:Nn \g__tblr_table_known_keys_clist { - long, colspec, rowspec, width, hspan, stretch, + colspec, rowspec, width, hspan, vspan, stretch, verb, column, row, cell, vline, hline, columns, rows, cells, vlines, hlines, leftsep, rightsep, colsep, abovesep, belowsep, rowsep, rulesep, + rowhead, rowfoot, } -\bool_new:N \l__tblr_long_table_bool - \keys_define:nn { tblr } { - long .bool_set:N = \l__tblr_long_table_bool, colspec .code:n = \__tblr_parse_colrow_spec:nn { column } {#1}, rowspec .code:n = \__tblr_parse_colrow_spec:nn { row } {#1}, width .code:n = \__tblr_keys_gput:nx { width } { \dim_eval:n {#1} }, hspan .code:n = \__tblr_keys_gput:nn { hspan } {#1}, + vspan .code:n = \__tblr_keys_gput:nn { vspan } {#1}, stretch .code:n = \__tblr_keys_gput:nn { stretch } {#1}, + verb .tl_set:N = \l__tblr_inner_spec_verb_tl, + verb .default:n = lite, columns .code:n = \__tblr_set_every_column_aux:n {#1}, rows .code:n = \__tblr_set_every_row_aux:n {#1}, cells .code:n = \__tblr_set_every_cell_aux:n {#1}, @@ -2625,6 +2965,8 @@ belowsep .code:n = \tblr_set_every_row:nn { } { belowsep = #1 }, rowsep .meta:n = { abovesep = #1, belowsep = #1 }, rulesep .code:n = \__tblr_keys_gput:nn { rulesep } {#1}, + rowhead .code:n = \__tblr_keys_gput:nn { rowhead } {#1}, + rowfoot .code:n = \__tblr_keys_gput:nn { rowfoot } {#1}, unknown .code:n = \__tblr_table_special_key:Vn \l_keys_key_str {#1}, } @@ -2658,12 +3000,107 @@ { \__tblr_parse_colrow_spec:nn { column } {#1} } } -\cs_new_protected:Npn \__tblr_keys_gput:nn #1 #2 +\cs_new_protected:Npn \__tblr_keys_gput:nn #1 #2 { - \__tblr_prop_gput:nnn { table } {#1} {#2} + \__tblr_prop_gput:nnn { inner } {#1} {#2} } \cs_generate_variant:Nn \__tblr_keys_gput:nn { nx } +%%% -------------------------------------------------------- +%% \section{Initialize and Parse Table Outer Specifications} +%%% -------------------------------------------------------- + +%% #1: theme names; #2: template and style commands +\NewDocumentCommand \NewTblrTheme { m +m } + { + \tl_set:cn { g__tblr_theme_ #1 _code_tl } {#2} + \ignorespaces + } + +\cs_new_protected:Npn \__tblr_use_theme:n #1 + { + \ignorespaces + \tl_use:c { g__tblr_theme_ #1 _code_tl } + } + +\cs_new_protected:Npn \__tblr_init_table_outer_spec: + { + \keys_set:nv { tblr-outer } { l__tblr_default_ \l__tblr_env_name_tl _outer_tl } + } + +\cs_new_protected:Npn \__tblr_parse_table_option:n #1 + { + \keys_set:nn { tblr-outer } {#1} + } + +\keys_define:nn { tblr-outer } + { + long .code:n = \__tblr_outer_gput_spec:nn { long } { true }, + tall .code:n = \__tblr_outer_gput_spec:nn { tall } { true }, + halign .code:n = \__tblr_outer_gput_spec:nn { halign } {#1}, + valign .code:n = \__tblr_outer_gput_spec:nn { valign } {#1}, + l .meta:n = { halign = l }, + c .meta:n = { halign = c }, + r .meta:n = { halign = r }, + t .meta:n = { valign = t }, + m .meta:n = { valign = m }, + b .meta:n = { valign = b }, + expand .code:n = \__tblr_outer_gput_spec:nn { expand } {#1}, + headsep .code:n = \__tblr_outer_gput_spec:nn { headsep } {#1}, + footsep .code:n = \__tblr_outer_gput_spec:nn { footsep } {#1}, + presep .code:n = \__tblr_outer_gput_spec:nn { presep } {#1}, + postsep .code:n = \__tblr_outer_gput_spec:nn { postsep } {#1}, + theme .code:n = \__tblr_use_theme:n {#1}, + caption .code:n = \__tblr_outer_gput_spec:nn { caption } {#1}, + entry .code:n = \__tblr_outer_gput_spec:nn { entry } {#1}, + label .code:n = \__tblr_outer_gput_spec:nn { label } {#1}, + unknown .code:n = \__tblr_table_option_key:Vn \l_keys_key_str {#1}, + } + +\cs_new_protected:Npn \__tblr_outer_gput_spec:nn #1 #2 + { + \__tblr_spec_gput:nen { outer } {#1} {#2} + } + +\regex_const:Nn \c__tblr_option_key_name_regex { ^ [A-Za-z\-] + $ } + +\msg_new:nnn { tabularray } { unknown-outer-key } + { Unknown ~ outer ~ key ~ name ~ #1! } + +\cs_new_protected:Npn \__tblr_table_option_key:nn #1 #2 + { + \regex_match:NnTF \c__tblr_option_key_name_regex {#1} + { \msg_error:nnn { tabularray } { unknown-outer-key } {#1} } + { + \regex_extract_once:NnNT \c__tblr_split_key_name_regex {#1} \l_tmpa_seq + { + \tl_set:Nx \l__tblr_a_tl { \seq_item:Nn \l_tmpa_seq {2} } + \tl_set_rescan:Nnx \l__tblr_b_tl {} { \seq_item:Nn \l_tmpa_seq {3} } + \tl_set:Nx \l__tblr_c_tl { \tl_head:N \l__tblr_b_tl } + \use:c { __tblr_outer_gput_ \l__tblr_a_tl :Vn } \l__tblr_c_tl {#2} + } + } + } +\cs_generate_variant:Nn \__tblr_table_option_key:nn { Vn } + +\cs_new_protected:Npn \__tblr_outer_gput_note:nn #1 #2 + { + \__tblr_prop_gput:nnn { note } {#1} {#2} + } +\cs_generate_variant:Nn \__tblr_outer_gput_note:nn { Vn } + +\cs_new_protected:Npn \__tblr_outer_gput_remark:nn #1 #2 + { + \__tblr_prop_gput:nnn { remark } {#1} {#2} + } +\cs_generate_variant:Nn \__tblr_outer_gput_remark:nn { Vn } + +\cs_new_protected:Npn \__tblr_outer_gput_more:nn #1 #2 + { + \__tblr_prop_gput:nnn { more } {#1} {#2} + } +\cs_generate_variant:Nn \__tblr_outer_gput_more:nn { Vn } + %%% -------------------------------------------------------- %% \section{Typeset and Calculate Sizes} %%% -------------------------------------------------------- @@ -2687,7 +3124,7 @@ \cs_new_protected:Npn \__tblr_make_strut_box: { - \tl_set:Nx \l__tblr_s_tl { \__tblr_prop_item:ne { table } { stretch } } + \tl_set:Nx \l__tblr_s_tl { \__tblr_prop_item:ne { inner } { stretch } } \hbox_set:Nn \l__tblr_strut_ht_box { \vrule height \l__tblr_s_tl \box_ht:N \strutbox width ~ 0pt } \hbox_set:Nn \l__tblr_strut_dp_box @@ -2725,11 +3162,11 @@ { \dim_zero:N \l__tblr_w_dim \tl_set:Nx \l__tblr_n_tl - { \__tblr_text_item:ne { vline } { [#2] / @vline-count } } + { \__tblr_spec_item:ne { vline } { [#2] / @vline-count } } \int_compare:nNnT { \l__tblr_n_tl } > {0} { \tl_set:Nx \l__tblr_s_tl - { \__tblr_prop_item:ne { table } { rulesep } } + { \__tblr_prop_item:ne { inner } { rulesep } } \int_step_inline:nn { \l__tblr_n_tl } { \vbox_set_to_ht:Nnn \l__tblr_b_box {1pt} @@ -2738,14 +3175,14 @@ {#1} {#2} {##1} {1pt} {1pt} } \tl_set:Nx \l__tblr_w_tl { \dim_eval:n { \box_wd:N \l__tblr_b_box } } - \__tblr_text_gput_if_larger:nee { vline } + \__tblr_spec_gput_if_larger:nee { vline } { [#2](##1) / @vline-width } { \l__tblr_w_tl } \dim_add:Nn \l__tblr_w_dim { \l__tblr_w_tl } \dim_add:Nn \l__tblr_w_dim { \l__tblr_s_tl } } \dim_add:Nn \l__tblr_w_dim { - \l__tblr_s_tl } } - \__tblr_text_gput_if_larger:nee { vline } + \__tblr_spec_gput_if_larger:nee { vline } { [#2]/ @vline-width } { \dim_use:N \l__tblr_w_dim } } @@ -2756,10 +3193,10 @@ { \group_begin: \tl_set:Nx \l__tblr_w_tl - { \__tblr_text_item:ne { vline } { [#1][#2](#3) / wd } } + { \__tblr_spec_item:ne { vline } { [#1][#2](#3) / wd } } \tl_if_empty:NF \l__tblr_w_tl { \dim_set:Nn \rulewidth { \l__tblr_w_tl } } \tl_set:Nx \l__tblr_d_tl - { \__tblr_text_item:ne { vline } { [#1][#2](#3) / @dash } } + { \__tblr_spec_item:ne { vline } { [#1][#2](#3) / @dash } } \tl_set:Nx \l__tblr_a_tl { \tl_head:N \l__tblr_d_tl } \tl_set:Nx \l__tblr_b_tl { \tl_tail:N \l__tblr_d_tl } \exp_args:NV \tl_if_eq:NNTF \l__tblr_a_tl \@tblr@dash @@ -2768,10 +3205,13 @@ \xleaders \l__tblr_b_tl \vfil } { + %% When using text as vline, we need to omit abovepos and belowpos. + \unskip \hbox_set:Nn \l__tblr_d_box { \l__tblr_b_tl } \box_set_ht:Nn \l__tblr_d_box {#4} \box_set_dp:Nn \l__tblr_d_box {#5} \box_use:N \l__tblr_d_box + \vss } \group_end: } @@ -2783,11 +3223,11 @@ { \dim_zero:N \l__tblr_h_dim \tl_set:Nx \l__tblr_n_tl - { \__tblr_text_item:ne { hline } { [#1] / @hline-count } } + { \__tblr_spec_item:ne { hline } { [#1] / @hline-count } } \int_compare:nNnT { \l__tblr_n_tl } > {0} { \tl_set:Nx \l__tblr_s_tl - { \__tblr_prop_item:ne { table } { rulesep } } + { \__tblr_prop_item:ne { inner } { rulesep } } \int_step_inline:nn { \l__tblr_n_tl } { \hbox_set_to_wd:Nnn \l__tblr_b_box {1pt} @@ -2797,14 +3237,14 @@ \dim_eval:n { \box_ht:N \l__tblr_b_box + \box_dp:N \l__tblr_b_box } } - \__tblr_text_gput_if_larger:nee { hline } + \__tblr_spec_gput_if_larger:nee { hline } { [#1](##1) / @hline-height } { \l__tblr_h_tl } \dim_add:Nn \l__tblr_h_dim { \l__tblr_h_tl } \dim_add:Nn \l__tblr_h_dim { \l__tblr_s_tl } } \dim_add:Nn \l__tblr_h_dim { - \l__tblr_s_tl } } - \__tblr_text_gput_if_larger:nee { hline } + \__tblr_spec_gput_if_larger:nee { hline } { [#1] / @hline-height } { \dim_use:N \l__tblr_h_dim } } @@ -2814,10 +3254,10 @@ { \group_begin: \tl_set:Nx \l__tblr_w_tl - { \__tblr_text_item:ne { hline } { [#1][#2](#3) / wd } } + { \__tblr_spec_item:ne { hline } { [#1][#2](#3) / wd } } \tl_if_empty:NF \l__tblr_w_tl { \dim_set:Nn \rulewidth { \l__tblr_w_tl } } \tl_set:Nx \l__tblr_d_tl - { \__tblr_text_item:ne { hline } { [#1][#2](#3) / @dash } } + { \__tblr_spec_item:ne { hline } { [#1][#2](#3) / @dash } } \tl_set:Nx \l__tblr_a_tl { \tl_head:N \l__tblr_d_tl } \tl_set:Nx \l__tblr_b_tl { \tl_tail:N \l__tblr_d_tl } \exp_args:NV \tl_if_eq:NNTF \l__tblr_a_tl \@tblr@dash @@ -2893,9 +3333,11 @@ { \int_incr:N \c@rownum \int_zero:N \c@colnum + \__tblr_update_rowsep_registers: \tl_set:Nx \l__tblr_h_tl - { \__tblr_data_item:nen { row } { \int_use:N \c@rownum } { height } } - \tl_if_empty:NF \l__tblr_h_tl + { \__tblr_data_item:nen { row } { \int_use:N \c@rownum } { height } } + %% We didn't initialize row heights with -1pt + \dim_compare:nNnF { \l__tblr_h_tl } = { 0pt } { \__tblr_data_gput:nenV { row } { \int_use:N \c@rownum } { @row-height } \l__tblr_h_tl @@ -2903,6 +3345,7 @@ \int_step_inline:nn { \c@colcount } { \int_incr:N \c@colnum + \__tblr_update_colsep_registers: \__tblr_measure_cell_update_sizes:nnNNNN { \int_use:N \c@rownum } { \int_use:N \c@colnum } @@ -2912,6 +3355,31 @@ \g__tblr_cell_foot_dim } } + \int_step_inline:nn { \c@colcount } + { + \tl_set:Nx \l__tblr_w_tl + { \__tblr_data_item:nen { column } {##1} { width } } + \dim_compare:nNnF { \l__tblr_w_tl } < { 0pt } + { + \__tblr_data_gput:nenV { column } {##1} { @col-width } \l__tblr_w_tl + } + } + } + +\cs_new_protected:Npn \__tblr_update_rowsep_registers: + { + \dim_set:Nn \abovesep + { \__tblr_data_item:nen { row } { \int_use:N \c@rownum } { abovesep } } + \dim_set:Nn \belowsep + { \__tblr_data_item:nen { row } { \int_use:N \c@rownum } { belowsep } } + } + +\cs_new_protected:Npn \__tblr_update_colsep_registers: + { + \dim_set:Nn \leftsep + { \__tblr_data_item:nen { column } { \int_use:N \c@colnum } { leftsep } } + \dim_set:Nn \rightsep + { \__tblr_data_item:nen { column } { \int_use:N \c@colnum } { rightsep } } } %% Measure and update natural dimensions of the row/column/cell @@ -2920,7 +3388,9 @@ \cs_new_protected:Npn \__tblr_measure_cell_update_sizes:nnNNNN #1 #2 #3 #4 #5 #6 { \__tblr_get_cell_alignments:nn {#1} {#2} + \__tblr_save_counters:n { trial } \hbox_set:Nn \l_tmpa_box { \__tblr_get_cell_text:nn {#1} {#2} } + \__tblr_restore_counters:n { trial } \__tblr_update_cell_size:nnNNNN {#1} {#2} #3 #4 #5 #6 \__tblr_update_row_size:nnNNN {#1} {#2} #4 #5 #6 \__tblr_update_col_size:nN {#2} #3 @@ -2939,13 +3409,46 @@ { \__tblr_get_cell_text_real:nn { #1 } { #2 } } } +\tl_new:N \l__tblr_cell_fg_tl +\tl_new:N \l__tblr_cell_cmd_tl +\tl_new:N \l__tblr_cell_mode_tl +\bool_new:N \l__tblr_cell_math_mode_bool +\tl_const:Nn \l__tblr_cell_math_style_tl { \relax } +\tl_const:Nn \l__tblr_cell_imath_style_tl { \textstyle } +\tl_const:Nn \l__tblr_cell_dmath_style_tl { \displaystyle } + %% Get cell text, #1: row number, #2: column number %% If the width of the cell is not set, split it with \\ and compute the width %% Therefore we always get a vbox for any cell \cs_new_protected:Npn \__tblr_get_cell_text_real:nn #1 #2 { \group_begin: - \tl_set:Nx \l__tblr_c_tl { \__tblr_text_item:ne { text } {[#1][#2]} } + \tl_set:Nx \l__tblr_cell_cmd_tl + { \__tblr_data_item:neen { cell } {#1} {#2} { cmd } } + \tl_if_empty:NTF \l__tblr_cell_cmd_tl + { \tl_set:Nx \l__tblr_c_tl { \__tblr_spec_item:ne { text } {[#1][#2]} } } + { + \tl_set:Nx \l__tblr_c_tl { { \__tblr_spec_item:ne { text } {[#1][#2]} } } + \tl_put_left:NV \l__tblr_c_tl \l__tblr_cell_cmd_tl + } + \tl_set:Nx \l__tblr_cell_mode_tl + { \__tblr_data_item:neen { cell } {#1} {#2} { mode } } + \tl_if_empty:NT \l__tblr_cell_mode_tl + { + \bool_if:NTF \l__tblr_math_mode_bool + { \tl_set:Nn \l__tblr_cell_mode_tl { math } } + { \tl_set:Nn \l__tblr_cell_mode_tl { text } } + } + \tl_if_eq:NnTF \l__tblr_cell_mode_tl { text } + { \bool_set_false:N \l__tblr_cell_math_mode_bool } + { + \bool_set_true:N \l__tblr_cell_math_mode_bool + \tl_put_left:Nv \l__tblr_c_tl + { l__tblr_cell_ \l__tblr_cell_mode_tl _style_tl } + \tl_put_left:Nn \l__tblr_c_tl { $ } + \tl_put_right:Nn \l__tblr_c_tl { $ } + } + \tl_set:Nx \l__tblr_f_tl { \__tblr_data_item:neen { cell } {#1} {#2} { font } } \tl_set:Nx \l__tblr_w_tl { \__tblr_data_item:neen { cell } {#1} {#2} { width } } \dim_compare:nNnT { \l__tblr_w_tl } < { 0pt } % cell width unset @@ -2959,35 +3462,80 @@ } \dim_compare:nNnT { \l__tblr_w_tl } < { 0pt } % column width unset { - \bool_if:NTF \l__tblr_math_mode_bool + \bool_if:NTF \l__tblr_cell_math_mode_bool { - \hbox_set:Nn \l_tmpa_box { $\l__tblr_c_tl$ } + \hbox_set:Nn \l_tmpa_box { \l__tblr_c_tl } \tl_set:Nx \l__tblr_w_tl { \box_wd:N \l_tmpa_box } } { - \tl_set_eq:NN \l_tmpb_tl \l__tblr_c_tl - \__tblr_insert_braces:N \l_tmpb_tl - \seq_set_split:NnV \l_tmpa_seq { \\ } \l_tmpb_tl - \tl_set:Nn \l__tblr_w_tl { 0pt } - \seq_map_variable:NNn \l_tmpa_seq \l_tmpa_tl - { - \__tblr_remove_braces:N \l_tmpa_tl - \hbox_set:Nn \l_tmpa_box { \l_tmpa_tl } - \tl_set:Nx \l__tblr_w_tl - { \dim_max:nn { \l__tblr_w_tl } { \box_wd:N \l_tmpa_box } } - } + \__tblr_get_cell_size_with_box: } } + \tl_set:Nx \l__tblr_cell_fg_tl + { \__tblr_data_item:neen { cell } {#1} {#2} { foreground } } + \tl_put_left:NV \l__tblr_c_tl \l__tblr_f_tl \__tblr_get_vcell_and_sizes:NN \l__tblr_c_tl \l__tblr_w_tl \group_end: } +\cs_new_protected:Npn \__tblr_get_cell_size_with_box: + { + \__tblr_save_counters:n { cell } + \tl_if_eq:NnTF \l__tblr_inner_spec_measure_tl { vbox } + { \__tblr_get_cell_size_with_vbox: } + { \__tblr_get_cell_size_with_hbox: } + \__tblr_restore_counters:n { cell } + } + +%% Varwidth won't work as expected when \color command occurs in it, +%% and we can not fix this problem with \leavevmode command. +%% See https://tex.stackexchange.com/q/460489. +%% But we need to use \color command for fg option, +%% or users may use it in the middle of the cell text, +%% so we have redefine \color command and disable it before measuring cell. + +\NewDocumentCommand \__tblr_fake_color_command:w { o m } { } + +\cs_new_protected:Npn \__tblr_get_cell_size_with_vbox: + { + \hbox_set:Nn \l_tmpa_box + { + \cs_set_eq:NN \color \__tblr_fake_color_command:w + \begin{varwidth}{\paperwidth} + \l__tblr_f_tl + \__tblr_rescan_cell_tokens:N \l__tblr_c_tl + \end{varwidth} + } + \tl_set:Nx \l__tblr_w_tl { \box_wd:N \l_tmpa_box } + } + +\cs_new_protected:Npn \__tblr_get_cell_size_with_hbox: + { + \tl_set_eq:NN \l_tmpb_tl \l__tblr_c_tl + \__tblr_insert_braces:N \l_tmpb_tl + \seq_set_split:NnV \l_tmpa_seq { \\ } \l_tmpb_tl + \tl_set:Nn \l__tblr_w_tl { 0pt } + \seq_map_variable:NNn \l_tmpa_seq \l_tmpa_tl + { + \__tblr_remove_braces:N \l_tmpa_tl + \hbox_set:Nn \l_tmpa_box + { + \l__tblr_f_tl + \__tblr_rescan_cell_tokens:N \l_tmpa_tl + } + \tl_set:Nx \l__tblr_w_tl + { \dim_max:nn { \l__tblr_w_tl } { \box_wd:N \l_tmpa_box } } + } + } + %% #1: cell text; #2: box width \cs_new_protected:Npn \__tblr_get_vcell_and_sizes:NN #1 #2 { \group_begin: - \vbox_set_top:Nn \l_tmpa_box { \__tblr_make_vcell_text:nN #1 #2 } - \vbox_set:Nn \l_tmpb_box { \__tblr_make_vcell_text:nN #1 #2 } + \__tblr_save_counters:n { cell } + \vbox_set_top:Nn \l_tmpa_box { \__tblr_make_vcell_text:NN #1 #2 } + \__tblr_restore_counters:n { cell } + \vbox_set:Nn \l_tmpb_box { \__tblr_make_vcell_text:NN #1 #2 } \dim_gset:Nn \g__tblr_cell_wd_dim { \box_wd:N \l_tmpb_box } \dim_gset:Nn \g__tblr_cell_ht_dim { \box_ht:N \l_tmpb_box + \box_dp:N \l_tmpb_box } @@ -3029,22 +3577,40 @@ \group_end: } -\cs_new_eq:NN \__tlbr_halign_l: \raggedright -\cs_new_eq:NN \__tlbr_halign_c: \centering -\cs_new_eq:NN \__tlbr_halign_r: \raggedleft - %% #1: cell text; #2: box width -\cs_new_protected:Npn \__tblr_make_vcell_text:nN #1 #2 +%% All halign commands are defined at the beginning of the file +\cs_new_protected:Npn \__tblr_make_vcell_text:NN #1 #2 { \dim_set:Nn \tex_hsize:D { #2 } \@arrayparboxrestore - \cs:w __tlbr_halign_ \g__tblr_cell_halign_tl : \cs_end: + \cs:w __tblr_halign_command_ \g__tblr_cell_halign_tl : \cs_end: \mode_leave_vertical: \box_use:N \l__tblr_strut_ht_box - \bool_if:NTF \l__tblr_math_mode_bool { $#1$ } { #1 } + \tl_if_empty:NF \l__tblr_cell_fg_tl { \exp_args:NV \color \l__tblr_cell_fg_tl } + \bool_if:NTF \l__tblr_cell_math_mode_bool + { #1 } + { \__tblr_rescan_cell_tokens:N #1 } \box_use:N \l__tblr_strut_dp_box } +%% When using verb option, there is an end-of-line character at the end. +%% This character causes extra horizontal space at the end when "measure=hbox", +%% or causes extra vertical space at the end with "measure=vbox". +%% Therefore we have to use an \empty to remove it. +%% See https://tex.stackexchange.com/q/213659 +\cs_new_protected:Npn \__tblr_rescan_cell_tokens:N #1 + { + \tl_if_empty:NTF \l__tblr_inner_spec_verb_tl + { #1 } + { + %% insert space characters after some control sequences first (issue #112) + \regex_replace_all:nnN { (\c{[A-Za-z]*}) ([A-Za-z]) } { \1 \ \2 } #1 + \regex_replace_all:nnN { . } { \c{string} \0 } #1 + \tl_set:Nx #1 { #1 \noexpand \empty } + \exp_args:NV \tex_scantokens:D #1 + } + } + %% #1: total height dimension; #2: head dimension; #3: foot dimension; %% #4: tl for resulting upper size; #5: tl for resulting lower size @@ -3238,7 +3804,7 @@ \cs_new_protected:Npn \__tblr_collect_extendable_column_width: { - \tl_set:Nx \l_tmpa_tl { \__tblr_prop_item:nn {table} {width} } + \tl_set:Nx \l_tmpa_tl { \__tblr_prop_item:nn { inner } { width } } \tl_if_empty:NTF \l_tmpa_tl { \dim_set_eq:NN \l__column_target_dim \linewidth } { \dim_set:Nn \l__column_target_dim { \l_tmpa_tl } } @@ -3271,7 +3837,7 @@ } { \dim_sub:Nn \l__column_target_dim { \l__tblr_a_tl } } \tl_set:Nx \l__tblr_a_tl - { \__tblr_text_item:ne { vline } { [\l__tblr_j_tl] / @vline-width } } + { \__tblr_spec_item:ne { vline } { [\l__tblr_j_tl] / @vline-width } } \tl_set:Nx \l__tblr_b_tl { \__tblr_data_item:nen { column } { \l__tblr_j_tl } { leftsep } } \tl_set:Nx \l__tblr_c_tl @@ -3281,7 +3847,7 @@ } \tl_set:Nx \l__tblr_a_tl { - \__tblr_text_item:ne { vline } + \__tblr_spec_item:ne { vline } { [\int_eval:n {\c@colcount + 1}] / @vline-width } } \tl_if_empty:NF \l__tblr_a_tl @@ -3290,7 +3856,8 @@ } %% If all columns have negative coefficients and small natural widths, -%% \l__column_coefficient_prop will be empty after one or more rounds +%% \l__column_coefficient_prop will be empty after one or more rounds. +%% We reset @row-height, etc for \linewidth graphics in X columns (issue #80) \cs_new_protected:Npn \__tblr_adjust_extendable_column_width: { \bool_while_do:nn @@ -3305,6 +3872,14 @@ \__tblr_data_gput:nnne { column } {##1} { width } {##2} \__tblr_data_gput:nnnn { column } {##1} { @col-width } { 0pt } } + \int_step_inline:nn { \c@rowcount } + { + \__tblr_data_gput:nnnn { row } {##1} { @row-height } { 0pt } + \__tblr_data_gput:nnnn { row } {##1} { @row-head } { 0pt } + \__tblr_data_gput:nnnn { row } {##1} { @row-foot } { 0pt } + \__tblr_data_gput:nnnn { row } {##1} { @row-upper } { 0pt } + \__tblr_data_gput:nnnn { row } {##1} { @row-lower } { 0pt } + } \__tblr_calculate_cell_sizes: } @@ -3378,11 +3953,11 @@ \cs_new_protected:Npn \__tblr_adjust_sizes_for_span_cells: { - \__tblr_prop_if_in:nnT {table} {colspan} + \__tblr_prop_if_in:nnT { inner } { colspan } { \__tblr_collect_column_widths_skips: \str_if_eq:xnTF - { \__tblr_prop_item:ne {table} {hspan} } {minimal} + { \__tblr_prop_item:ne { inner } { hspan } } { minimal } { \__tblr_set_span_widths_from_column_widths: } @@ -3393,12 +3968,12 @@ \LogTblrTracing { column } \__tblr_calculate_cell_sizes: } - \__tblr_prop_if_in:nnT {table} {rowspan} + \__tblr_prop_if_in:nnT { inner } { rowspan } { \__tblr_collect_row_heights_skips: \__tblr_collect_span_heights: \__tblr_set_row_heights_from_span_heights: - \LogTblrTracing {row} + \LogTblrTracing { row } } } @@ -3421,7 +3996,7 @@ \__tblr_data_item:nen { column } { \int_eval:n { \l__tblr_j_tl - 1 } } { rightsep } + - \__tblr_text_item:ne { vline } + \__tblr_spec_item:ne { vline } { [\l__tblr_j_tl] / @vline-width } + \__tblr_data_item:nen { column } { \l__tblr_j_tl } { leftsep } @@ -3453,7 +4028,7 @@ \__tblr_data_item:nen { row } { \int_eval:n {\l__tblr_i_tl - 1} } { belowsep } + - \__tblr_text_item:ne { hline } + \__tblr_spec_item:ne { hline } { [\l__tblr_i_tl] / @hline-height } + \__tblr_data_item:nen { row } { \l__tblr_i_tl } { abovesep } @@ -3585,27 +4160,49 @@ %% Compute and set column widths from span widths \cs_new_protected:Npn \__tblr_set_column_widths_from_span_widths: { - \__tblr_calc_item_sizes_from_span_sizes:xNN - { \int_use:N \c@colcount } - \l__tblr_col_item_skip_size_prop - \l__tblr_col_span_size_prop + \str_if_eq:xnTF + { \__tblr_prop_item:ne { inner } { hspan } } + { even } + { + \__tblr_distribute_span_sizes_even:xNN + { \int_use:N \c@colcount } + \l__tblr_col_item_skip_size_prop + \l__tblr_col_span_size_prop + } + { + \__tblr_distribute_span_sizes_default:xNN + { \int_use:N \c@colcount } + \l__tblr_col_item_skip_size_prop + \l__tblr_col_span_size_prop + } \__tblr_set_all_column_widths: } %% Compute and set row heights from span heights \cs_new_protected:Npn \__tblr_set_row_heights_from_span_heights: { - \__tblr_calc_item_sizes_from_span_sizes:xNN - { \int_use:N \c@rowcount } - \l__tblr_row_item_skip_size_prop - \l__tblr_row_span_size_prop + \str_if_eq:xnTF + { \__tblr_prop_item:ne { inner } { vspan } } + { even } + { + \__tblr_distribute_span_sizes_even:nNN + { \int_use:N \c@rowcount } + \l__tblr_row_item_skip_size_prop + \l__tblr_row_span_size_prop + } + { + \__tblr_distribute_span_sizes_default:xNN + { \int_use:N \c@rowcount } + \l__tblr_row_item_skip_size_prop + \l__tblr_row_span_size_prop + } \__tblr_set_all_row_heights: } %% See page 245 in Chapter 22 of TeXbook %% #1: total number of items %% #2: prop list with item sizes and skip sizes; #3: prop list with span sizes -\cs_new_protected:Npn \__tblr_calc_item_sizes_from_span_sizes:nNN #1 #2 #3 +\cs_new_protected:Npn \__tblr_distribute_span_sizes_default:nNN #1 #2 #3 { \int_step_variable:nNn { #1 } \l__tblr_j_tl { @@ -3656,19 +4253,65 @@ } \__tblr_do_if_tracing:nn { cellspan } { \prop_log:N #2 } } -\cs_generate_variant:Nn \__tblr_calc_item_sizes_from_span_sizes:nNN { x } +\cs_generate_variant:Nn \__tblr_distribute_span_sizes_default:nNN { x } -\cs_new_protected:Npn \__tblr_set_all_column_widths: +%% #1: total number of items +%% #2: prop list with item sizes and skip sizes; #3: prop list with span sizes +\cs_new_protected:Npn \__tblr_distribute_span_sizes_even:nNN #1 #2 #3 { - \int_step_variable:nNn { \c@colcount } \l__tblr_j_tl + \prop_clear:N \l_tmpa_prop + \prop_map_inline:Nn #3 { - \__tblr_data_gput:nene { column } - { \l__tblr_j_tl } { @col-width } - { \prop_item:Ne \l__tblr_col_item_skip_size_prop { item[\l__tblr_j_tl] } } - } - } - -\cs_new_protected:Npn \__tblr_set_all_row_heights: + \__tblr_get_span_from_to:w ##1 + \dim_set:Nn \l_tmpa_dim {##2} + \dim_sub:Nn \l_tmpa_dim { \prop_item:Ne #2 { item[\l__tblr_a_tl] } } + \int_step_inline:nnn { \l__tblr_a_tl + 1 } { \l__tblr_b_tl } + { + \dim_sub:Nn \l_tmpa_dim + { + \prop_item:Ne #2 { skip[####1] } + \prop_item:Nn #2 { item[####1] } + } + } + \__tblr_do_if_tracing:nn { cellspan } + { + \tl_log:x { \l__tblr_a_tl -> \l__tblr_b_tl : ~ \dim_use:N \l_tmpa_dim } + } + \dim_compare:nNnT {\l_tmpa_dim} > {0pt} + { + \tl_set:Nx \l_tmpa_tl + { \dim_eval:n { \l_tmpa_dim / (\l__tblr_b_tl - \l__tblr_a_tl + 1) } } + \int_step_inline:nnn { \l__tblr_a_tl } { \l__tblr_b_tl } + { + \__tblr_put_if_larger:NnV \l_tmpa_prop {####1} \l_tmpa_tl + } + } + } + \__tblr_do_if_tracing:nn { cellspan } { \prop_log:N \l_tmpa_prop } + \prop_map_inline:Nn \l_tmpa_prop + { + \__tblr_add_dimen_value:Nnn #2 {item[##1]} {##2} + } + \__tblr_do_if_tracing:nn { cellspan } { \prop_log:N #2 } + } +\cs_generate_variant:Nn \__tblr_distribute_span_sizes_even:nNN { x } + +\cs_new_protected:Npn \__tblr_get_span_from_to:w (#1-#2) + { + \tl_set:Nn \l__tblr_a_tl {#1} + \tl_set:Nn \l__tblr_b_tl {#2} + } + +\cs_new_protected:Npn \__tblr_set_all_column_widths: + { + \int_step_variable:nNn { \c@colcount } \l__tblr_j_tl + { + \__tblr_data_gput:nene { column } + { \l__tblr_j_tl } { width } + { \prop_item:Ne \l__tblr_col_item_skip_size_prop { item[\l__tblr_j_tl] } } + } + } + +\cs_new_protected:Npn \__tblr_set_all_row_heights: { \int_step_variable:nNn { \c@rowcount } \l__tblr_i_tl { @@ -3690,123 +4333,1118 @@ } } -\cs_new_protected:Npn \__tblr_get_span_key_row_col:w [#1][#2] +%% Compute and set span widths from column widths +\cs_new_protected:Npn \__tblr_set_span_widths_from_column_widths: + { + \int_step_variable:nNn { \c@colcount } \l__tblr_j_tl + { + \int_step_variable:nNn { \c@rowcount } \l__tblr_i_tl + { + \tl_set:Nx \l__tblr_a_tl + { + \__tblr_data_item:neen { cell } + { \l__tblr_i_tl } { \l__tblr_j_tl } { colspan } + } + \int_compare:nNnT { \l__tblr_a_tl } > {1} + { + \__tblr_calc_span_widths:xxN + { \l__tblr_j_tl } + { \int_eval:n { \l__tblr_j_tl + \l__tblr_a_tl - 1 } } + \l__tblr_w_dim + \__tblr_data_gput:neene { cell } + { \l__tblr_i_tl } { \l__tblr_j_tl } { width } + { \dim_use:N \l__tblr_w_dim } + } + } + } + } + +%% Cell is spanned from col #1 to col #2, #3 is the return dim +\cs_new_protected:Npn \__tblr_calc_span_widths:nnN #1 #2 #3 + { + \dim_set:Nn #3 { \prop_item:Ne \l__tblr_col_item_skip_size_prop { item[#1] } } + \int_step_inline:nnn { #1 + 1 } { #2 } + { + \tl_set:Nx \l_tmpa_tl + { \prop_item:Ne \l__tblr_col_item_skip_size_prop { skip[##1] } } + \tl_set:Nx \l_tmpb_tl + { \prop_item:Ne \l__tblr_col_item_skip_size_prop { item[##1] } } + \dim_add:Nn #3 { \dim_eval:n { \l_tmpa_tl + \l_tmpb_tl } } + } + } +\cs_generate_variant:Nn \__tblr_calc_span_widths:nnN { xxN } + +%%% -------------------------------------------------------- +%%> \section{Header and Footer Styles} +%%% -------------------------------------------------------- + +\prop_new:N \l__tblr_element_styles_prop + +\cs_new_protected:Npn \__tblr_style_put:nn #1 #2 + { + \prop_put:Nnn \l__tblr_element_styles_prop {#1} {#2} + } +\cs_generate_variant:Nn \__tblr_style_put:nn { nV, ne, en } + +\cs_new:Npn \__tblr_style_item:n #1 + { + \prop_item:Nn \l__tblr_element_styles_prop {#1} + } + +\cs_new_protected:Npn \__tblr_style_log: + { + \prop_log:N \l__tblr_element_styles_prop + } + +\tl_new:N \l__tblr_element_name_tl +\tl_new:N \l__tblr_element_styles_tl + +%% #1: list of element names; #2: element styles +\NewDocumentCommand \SetTblrStyle { m +m } + { + \tl_set:Nn \l__tblr_element_styles_tl {#2} + \keys_set:nn { tblr-element } {#1} + \ignorespaces + } + +\keys_define:nn { tblr-element } + { + head .meta:n = { firsthead, middlehead, lasthead }, + foot .meta:n = { firstfoot, middlefoot, lastfoot }, + unknown .code:n = \__tblr_set_element_styles:V \l_keys_key_str, + } + +\cs_new_protected:Npn \__tblr_set_element_styles:n #1 + { + \tl_set:Nn \l__tblr_element_name_tl {#1} + \keys_set:nV { tblr-style } \l__tblr_element_styles_tl + } +\cs_generate_variant:Nn \__tblr_set_element_styles:n { V } + +\keys_define:nn { tblr-style } + { + halign .code:n = \__tblr_element_gput_style:nn { halign } {#1}, + l .meta:n = { halign = l }, + c .meta:n = { halign = c }, + r .meta:n = { halign = r }, + fg .code:n = \__tblr_element_gput_style:nn { fg } {#1}, + font .code:n = \__tblr_element_gput_style:nn { font } {#1}, + hang .code:n = \__tblr_element_gput_style:nn { hang } {#1}, + indent .code:n = \__tblr_element_gput_style:nn { indent } {#1}, + unknown .code:n = \__tblr_element_unknown_key:Vn \l_keys_key_str {#1}, + } + +\cs_new_protected:Npn \__tblr_element_gput_style:nn #1 #2 + { + \__tblr_style_put:en { \l__tblr_element_name_tl / #1 } {#2} + } + +\cs_new_protected:Npn \__tblr_element_unknown_key:nn #1 #2 + { + \regex_match:NnTF \c__tblr_is_color_key_regex {#1} + { \__tblr_style_put:en { \l__tblr_element_name_tl / fg } {#1} } + { + %% unknown key name has been changed to string in \l_keys_key_str + \tl_set_rescan:Nnn \l__tblr_f_tl {} {#1} + \tl_if_head_eq_catcode:VNTF \l__tblr_f_tl \scan_stop: + { + \__tblr_style_put:en { \l__tblr_element_name_tl / font } \l__tblr_f_tl + } + { + \__tblr_style_put:en { \l__tblr_element_name_tl / #1 } {#2} + } + } + } +\cs_generate_variant:Nn \__tblr_element_unknown_key:nn { Vn } + +%%% -------------------------------------------------------- +%%> \section{Helper Functions for Templates} +%%% -------------------------------------------------------- + +\tl_new:N \l__tblr_template_name_tl +\tl_new:N \l__tblr_template_code_tl + +\keys_define:nn { tblr-def-template } + { + unknown .code:n = \__tblr_def_template:V \l_keys_key_str, + } + +%% #1: head/foot element; #2: template name; #3: template code +%% If the template name = default, we enable the template at once +%% Otherwise, we may enable the template by using \SetTblrTemplate command +\NewDocumentCommand \DefTblrTemplate { m m +m } + { + \tl_set:Nn \l__tblr_template_name_tl {#2} + \tl_set:Nn \l__tblr_template_code_tl {#3} + \keys_set:nn { tblr-def-template } {#1} + \ignorespaces + } + +\cs_new_protected:Npn \__tblr_def_template:n #1 + { + \tl_set_eq:cN { l__tblr_template_ #1 _ \l__tblr_template_name_tl _tl } + \l__tblr_template_code_tl + } +\cs_generate_variant:Nn \__tblr_def_template:n { V } + +\keys_define:nn { tblr-set-template } + { + unknown .code:n = \__tblr_set_template:V \l_keys_key_str, + } + +%% #1: head/foot element; #2: template name +\NewDocumentCommand \SetTblrTemplate { m m } + { + \tl_set:Nn \l__tblr_template_name_tl {#2} + \keys_set:nn { tblr-set-template } {#1} + \ignorespaces + } + +\cs_new_protected:Npn \__tblr_set_template:n #1 + { + \tl_set_eq:cc { l__tblr_template_ #1 _default_tl } + { l__tblr_template_ #1 _ \l__tblr_template_name_tl _tl } + } +\cs_generate_variant:Nn \__tblr_set_template:n { V } + +\NewExpandableDocumentCommand \GetTblrStyle { m m } + { + \__tblr_style_item:n { #1 / #2 } + } + +\NewDocumentCommand \UseTblrFont { m } + { + \GetTblrStyle {#1} { font } \selectfont + } + +\tl_new:N \l__tblr_use_color_tl + +\NewDocumentCommand \UseTblrColor { m } + { + \tl_set:Nx \l__tblr_use_color_tl { \GetTblrStyle {#1} { fg } } + \tl_if_empty:NF \l__tblr_use_color_tl { \color { \l__tblr_use_color_tl } } + } + +%% All halign commands are defined at the beginning of the file +\NewDocumentCommand \UseTblrAlign { m } + { + \use:c { __tblr_halign_command_ \GetTblrStyle {#1} { halign } : } + } + +\tl_new:N \l__tblr_use_hang_tl + +\NewDocumentCommand \UseTblrHang { m } + { + \tl_set:Nx \l__tblr_use_hang_tl { \GetTblrStyle {#1} { hang } } + \tl_if_empty:NF \l__tblr_use_hang_tl + { + \tl_put_left:Nn \l__tblr_use_hang_tl + { \hangafter = 1 \relax \hangindent = } + \tl_put_right:Nn \l__tblr_use_hang_tl { \relax } + \exp_args:NV \everypar \l__tblr_use_hang_tl + } + } + +\tl_new:N \l__tblr_use_indent_tl + +\NewDocumentCommand \UseTblrIndent { m } + { + \tl_set:Nx \l__tblr_use_indent_tl { \GetTblrStyle {#1} { indent } } + \tl_if_empty:NF \l__tblr_use_indent_tl + { \exp_args:NNV \setlength \parindent \l__tblr_use_indent_tl } + } + +\AtBeginDocument + { + \@ifpackageloaded{xcolor}{}{\RenewDocumentCommand \UseTblrColor {m} {}} + } + +%% #1: head/foot element; #2: template name +\NewExpandableDocumentCommand \ExpTblrTemplate { m m } + { + \tl_use:c { l__tblr_template_ #1 _ #2 _tl } + } + +%% #1: head/foot element; #2: template name +\NewDocumentCommand \UseTblrTemplate { m m } + { + \group_begin: + \UseTblrFont {#1} + \UseTblrColor {#1} + \tl_use:c { l__tblr_template_ #1 _ #2 _tl } + \group_end: + } + +\NewDocumentCommand \MapTblrNotes { +m } + { + \__tblr_prop_map_inline:nn { note } + { + \tl_set_rescan:Nnn \InsertTblrNoteTag {} {##1} + \tl_set:Nn \InsertTblrNoteText {##2} + #1 + } + } + +\NewDocumentCommand \MapTblrRemarks { +m } + { + \__tblr_prop_map_inline:nn { remark } + { + \tl_set_rescan:Nnn \InsertTblrRemarkTag {} {##1} + \tl_set:Nn \InsertTblrRemarkText {##2} + #1 + } + } + +\NewExpandableDocumentCommand \InsertTblrText { m } + { + \__tblr_spec_item:nn { outer } {#1} + } + +\NewExpandableDocumentCommand \InsertTblrMore { m } + { + \__tblr_prop_item:nn { more } {#1} + } + +%%% -------------------------------------------------------- +%%> \section{Table Continuation Templates} +%%% -------------------------------------------------------- + +\DefTblrTemplate { contfoot-text } { normal } { Continued ~ on ~ next ~ page } +\SetTblrTemplate { contfoot-text } { normal } + +\DefTblrTemplate { contfoot } { empty } { } +\DefTblrTemplate { contfoot } { plain } + { + \noindent + \raggedleft + \UseTblrTemplate { contfoot-text } { default } + \par + } +\DefTblrTemplate { contfoot } { normal } + { + %% need to set parindent after alignment + \raggedleft + \UseTblrAlign { contfoot } + \UseTblrIndent { contfoot } + \UseTblrHang { contfoot } + \leavevmode + \UseTblrTemplate { contfoot-text } { default } + \par + } +\SetTblrTemplate { contfoot } { normal } + +\DefTblrTemplate { conthead-text } { normal } { ( Continued ) } +\SetTblrTemplate { conthead-text } { normal } + +\DefTblrTemplate { conthead } { empty } { } +\DefTblrTemplate { conthead } { plain } + { + \noindent + \raggedright + \UseTblrTemplate { conthead-text } { default } + \par + } +\DefTblrTemplate { conthead } { normal } + { + %% need to set parindent after alignment + \raggedright + \UseTblrAlign { conthead } + \UseTblrIndent { conthead } + \UseTblrHang { conthead } + \leavevmode + \UseTblrTemplate { conthead-text } { default } + \par + } +\SetTblrTemplate { conthead } { normal } + +%%% -------------------------------------------------------- +%%> \section{Table Caption Templates} +%%% -------------------------------------------------------- + +\tl_new:N \l__tblr_caption_short_tl + +\DefTblrTemplate { caption-lot } { empty } { } +\DefTblrTemplate { caption-lot } { normal } + { + \tl_set:Nx \l__tblr_caption_short_tl { \InsertTblrText { entry } } + \tl_if_empty:NT \l__tblr_caption_short_tl + { \tl_set:Nx \l__tblr_caption_short_tl { \InsertTblrText { caption } } } + \addcontentsline { lot } { table } + { \protect\numberline { \thetable } { \l__tblr_caption_short_tl } } + } +\SetTblrTemplate { caption-lot } { normal } + +%% We need to use \hspace and \enskip, but not ~ or \space, +%% since we want a correct hangindent caption paragraph. + +\DefTblrTemplate { caption-tag } { empty } { } +\DefTblrTemplate { caption-tag } { normal } { \tablename\hspace{0.25em}\thetable } +\SetTblrTemplate { caption-tag } { normal } + +\DefTblrTemplate { caption-sep } { empty } { } +\DefTblrTemplate { caption-sep } { normal } { : \enskip } +\SetTblrTemplate { caption-sep } { normal } + +\DefTblrTemplate { caption-text } { empty } { } +\DefTblrTemplate { caption-text } { normal } { \InsertTblrText { caption } } +\SetTblrTemplate { caption-text } { normal } + +\box_new:N \l__tblr_caption_box +\box_new:N \l__tblr_caption_left_box + +\DefTblrTemplate { caption } { empty } { } +\DefTblrTemplate { caption } { plain } + { + \hbox_set:Nn \l__tblr_caption_box + { + \UseTblrTemplate { caption-tag } { default } + \UseTblrTemplate { caption-sep } { default } + \UseTblrTemplate { caption-text } { default } + } + \dim_compare:nNnTF { \box_wd:N \l__tblr_caption_box } > { \hsize } + { + \noindent + \hbox_unpack:N \l__tblr_caption_box + \par + } + { + \centering + \makebox [\hsize] [c] { \box_use:N \l__tblr_caption_box } + \par + } + } +\DefTblrTemplate { caption } { normal } + { + \hbox_set:Nn \l__tblr_caption_box + { + \UseTblrTemplate { caption-tag } { default } + \UseTblrTemplate { caption-sep } { default } + \UseTblrTemplate { caption-text } { default } + } + \dim_compare:nNnTF { \box_wd:N \l__tblr_caption_box } > { \hsize } + { + \UseTblrAlign { caption } + \UseTblrIndent { caption } + \hbox_set:Nn \l__tblr_caption_left_box + { + \UseTblrTemplate { caption-tag } { default } + \UseTblrTemplate { caption-sep } { default } + } + \hangindent = \box_wd:N \l__tblr_caption_left_box + \hangafter = 1 + \UseTblrHang { caption } + \leavevmode + \hbox_unpack:N \l__tblr_caption_box + \par + } + { + \centering + \makebox [\hsize] [c] { \box_use:N \l__tblr_caption_box } + \par + } + } +\DefTblrTemplate { caption } { simple } + { + \UseTblrAlign { caption } + \UseTblrIndent { caption } + \UseTblrHang { caption } + \leavevmode + \UseTblrTemplate { caption-tag } { default } + \UseTblrTemplate { caption-sep } { default } + \UseTblrTemplate { caption-text } { default } + \par + } +\SetTblrTemplate { caption } { normal } + +\DefTblrTemplate { capcont } { empty } { } +\DefTblrTemplate { capcont } { plain } + { + \hbox_set:Nn \l__tblr_caption_box + { + \UseTblrTemplate { caption-tag } { default } + \UseTblrTemplate { caption-sep } { default } + \UseTblrTemplate { caption-text } { default } + \space + \UseTblrTemplate { conthead-text } { default } + } + \dim_compare:nNnTF { \box_wd:N \l__tblr_caption_box } > { \hsize } + { + \noindent + \hbox_unpack:N \l__tblr_caption_box + \par + } + { + \centering + \makebox [\hsize] [c] { \box_use:N \l__tblr_caption_box } + \par + } + } +\DefTblrTemplate { capcont } { normal } + { + \hbox_set:Nn \l__tblr_caption_box + { + \UseTblrTemplate { caption-tag } { default } + \UseTblrTemplate { caption-sep } { default } + \UseTblrTemplate { caption-text } { default } + \space + \UseTblrTemplate { conthead-text } { default } + } + \dim_compare:nNnTF { \box_wd:N \l__tblr_caption_box } > { \hsize } + { + \UseTblrAlign { capcont } + \UseTblrIndent { capcont } + \hbox_set:Nn \l__tblr_caption_left_box + { + \UseTblrTemplate { caption-tag } { default } + \UseTblrTemplate { caption-sep } { default } + } + \hangindent = \box_wd:N \l__tblr_caption_left_box + \hangafter = 1 + \UseTblrHang { capcont } + \leavevmode + \hbox_unpack:N \l__tblr_caption_box + \par + } + { + \centering + \makebox [\hsize] [c] { \box_use:N \l__tblr_caption_box } + \par + } + } +\DefTblrTemplate { capcont } { simple } + { + \UseTblrAlign { caption } + \UseTblrIndent { caption } + \UseTblrHang { caption } + \leavevmode + \UseTblrTemplate { caption-tag } { default } + \UseTblrTemplate { caption-sep } { default } + \UseTblrTemplate { caption-text } { default } + \space + \UseTblrTemplate { conthead-text } { default } + \par + } +\SetTblrTemplate { capcont} { normal } + +%%% -------------------------------------------------------- +%%> \section{Table Notes Templates} +%%% -------------------------------------------------------- + +%% By default the targets generated by \hypertarget are too low +%% Therefore we need to use \Hy@raisedlink command to fix this problem +%% See https://tex.stackexchange.com/questions/17057 +%% We also use \use:c in case the private command \Hy@raisedlink is removed +\cs_new_protected:Npn \__tblr_hyper_target:n #1 + { + \cs_if_exist:NT \hypertarget + { + \use:c { Hy@raisedlink } + { + \hypertarget + { tblr / \int_use:N \g__tblr_table_count_int / \tl_to_str:n {#1} } + { } + } + } + } +\cs_generate_variant:Nn \__tblr_hyper_target:n { V } + +\cs_new_protected:Npn \__tblr_hyper_link:nn #1 #2 + { + \cs_if_exist:NTF \hyperlink + { + \hyperlink + { tblr / \int_use:N \g__tblr_table_count_int / \tl_to_str:n {#1} } + { #2 } + } + { #2 } + } + +\DefTblrTemplate { note-border } { empty } + { + \hypersetup { pdfborder = { 0 ~ 0 ~ 0 } } + } +\DefTblrTemplate { note-border } { normal } + { + \hypersetup { pdfborder = { 0 ~ 0 ~ 1 } } + } +\SetTblrTemplate { note-border } { empty } + +\NewDocumentCommand \TblrNote { m } + { + \cs_if_exist:NT \hypersetup { \ExpTblrTemplate { note-border }{ default } } + \__tblr_hyper_link:nn {#1} + { \textsuperscript { \sffamily \UseTblrFont { note-tag } #1 } } + } + +\DefTblrTemplate { note-tag } { empty } { } +\DefTblrTemplate { note-tag } { normal } + { + \textsuperscript { \sffamily \UseTblrFont { note-tag } \InsertTblrNoteTag } + } +\SetTblrTemplate { note-tag } { normal } + +\DefTblrTemplate { note-target } { normal } + { + \__tblr_hyper_target:V \InsertTblrNoteTag + } +\SetTblrTemplate { note-target } { normal } + +\DefTblrTemplate { note-sep } { empty } { } +\DefTblrTemplate { note-sep } { normal } { \space } +\SetTblrTemplate { note-sep } { normal } + +\DefTblrTemplate { note-text } { empty } { } +\DefTblrTemplate { note-text } { normal } { \InsertTblrNoteText } +\SetTblrTemplate { note-text } { normal } + +\DefTblrTemplate { note } { empty } { } +\DefTblrTemplate { note } { plain } + { + \MapTblrNotes + { + \noindent + \UseTblrTemplate { note-tag } { default } + \UseTblrTemplate { note-target } { default } + \UseTblrTemplate { note-sep } { default } + \UseTblrTemplate { note-text } { default } + \par + } + } +\DefTblrTemplate { note } { normal } + { + \UseTblrAlign { note } + \UseTblrIndent { note } + \MapTblrNotes + { + \hangindent = 0.7em + \hangafter = 1 + \UseTblrHang { note } + \leavevmode + \hbox_to_wd:nn { \the\hangindent } + { + \UseTblrTemplate { note-tag } { default } + \UseTblrTemplate { note-target } { default } + \hfil + } + \UseTblrTemplate { note-text } { default } + \par + } + } +\DefTblrTemplate { note } { inline } + { + \UseTblrAlign { note } + \UseTblrIndent { note } + \UseTblrHang { note } + \leavevmode + \MapTblrNotes + { + \UseTblrTemplate { note-tag } { default } + \UseTblrTemplate { note-target } { default } + \UseTblrTemplate { note-sep } { default } + \UseTblrTemplate { note-text } { default } + \quad + } + \par + } +\SetTblrTemplate { note } { normal } + +%%% -------------------------------------------------------- +%%> \section{Table Remarks Templates} +%%% -------------------------------------------------------- + +\DefTblrTemplate { remark-tag } { empty } { } +\DefTblrTemplate { remark-tag } { normal } + { + \itshape \UseTblrFont { remark-tag } \InsertTblrRemarkTag + } +\SetTblrTemplate { remark-tag } { normal } + +\DefTblrTemplate { remark-sep } { empty } { } +\DefTblrTemplate { remark-sep } { normal } { : \space } +\SetTblrTemplate { remark-sep } { normal } + +\DefTblrTemplate { remark-text } { empty } { } +\DefTblrTemplate { remark-text } { normal } { \InsertTblrRemarkText } +\SetTblrTemplate { remark-text } { normal } + +\DefTblrTemplate { remark } { empty } { } +\DefTblrTemplate { remark } { plain } + { + \MapTblrRemarks + { + \noindent + \UseTblrTemplate { remark-tag } { default } + \UseTblrTemplate { remark-sep } { default } + \UseTblrTemplate { remark-text } { default } + \par + } + } +\DefTblrTemplate { remark } { normal } + { + \UseTblrAlign { remark } + \UseTblrIndent { remark } + \MapTblrRemarks + { + \hangindent = 0.7em + \hangafter = 1 + \UseTblrHang { remark } + \leavevmode + \UseTblrTemplate { remark-tag } { default } + \UseTblrTemplate { remark-sep } { default } + \UseTblrTemplate { remark-text } { default } + \par + } + } +\DefTblrTemplate { remark } { inline } + { + \UseTblrAlign { remark } + \UseTblrIndent { remark } + \UseTblrHang { remark } + \leavevmode + \MapTblrRemarks + { + \UseTblrTemplate { remark-tag } { default } + \UseTblrTemplate { remark-sep } { default } + \UseTblrTemplate { remark-text } { default } + \quad + } + \par + } +\SetTblrTemplate { remark } { normal } + +%%% -------------------------------------------------------- +%%> \section{Header and Footer Templates} +%%% -------------------------------------------------------- + +\tl_new:N \g__tblr_template_firsthead_default_tl +\tl_new:N \g__tblr_template_middlehead_default_tl +\tl_new:N \g__tblr_template_lasthead_default_tl +\tl_new:N \g__tblr_template_firstfoot_default_tl +\tl_new:N \g__tblr_template_middlefoot_default_tl +\tl_new:N \g__tblr_template_lastfoot_default_tl + +\keys_define:nn { tblr-def-template } + { + head .meta:n = { firsthead, middlehead, lasthead }, + foot .meta:n = { firstfoot, middlefoot, lastfoot }, + } + +\keys_define:nn { tblr-set-template } + { + head .meta:n = { firsthead, middlehead, lasthead }, + foot .meta:n = { firstfoot, middlefoot, lastfoot }, + } + +\DefTblrTemplate { head } { empty } { } +\DefTblrTemplate { foot } { empty } { } + +\DefTblrTemplate { firsthead } { normal } + { + \UseTblrTemplate { caption } { default } + } + +\DefTblrTemplate { middlehead, lasthead } { normal } + { + \UseTblrTemplate { capcont } { default } + } + +\DefTblrTemplate { firstfoot, middlefoot } { normal } + { + \UseTblrTemplate { contfoot } { default } + } + +\DefTblrTemplate { lastfoot } { normal } + { + \UseTblrTemplate { note } { default } + \UseTblrTemplate { remark } { default } + } + +\SetTblrTemplate { head } { normal } +\SetTblrTemplate { foot } { normal } + +%%% -------------------------------------------------------- +%%> \section{Build the Whole Table} +%%% -------------------------------------------------------- + +\cs_new:Npn \__tblr_box_height:N #1 + { + \dim_eval:n { \box_ht:N #1 + \box_dp:N #1 } + } + +\cs_new_protected:Npn \__tblr_build_head_foot: + { + \__tblr_build_row_head_foot: + \__tblr_build_table_head_foot: + } + +\tl_new:N \l__tblr_row_head_tl +\tl_new:N \l__tblr_row_foot_tl +\box_new:N \l__tblr_row_head_box +\box_new:N \l__tblr_row_foot_box +\dim_new:N \l__tblr_row_head_foot_dim + +\cs_new_protected:Npn \__tblr_build_row_head_foot: + { + %% \l__tblr_row_head_tl and \l__tblr_row_foot_tl may be empty + \tl_set:Nx \l__tblr_row_head_tl { \__tblr_prop_item:ne { inner } { rowhead } } + \int_compare:nNnTF { \l__tblr_row_head_tl + 0 } > { 0 } + { \__tblr_build_one_table:nn {1} { \l__tblr_row_head_tl } } + { \__tblr_build_one_hline:n {1} } + \box_set_eq:NN \l__tblr_row_head_box \l__tblr_table_box + \tl_set:Nx \l__tblr_row_foot_tl { \__tblr_prop_item:ne { inner } { rowfoot } } + \int_compare:nNnTF { \l__tblr_row_foot_tl + 0 } > { 0 } + { + \__tblr_build_one_table:nn + { \c@rowcount - \l__tblr_row_foot_tl + 1 } { \c@rowcount } + } + { \__tblr_build_one_hline:n { \int_eval:n { \c@rowcount + 1 } } } + \box_set_eq:NN \l__tblr_row_foot_box \l__tblr_table_box + \dim_set:Nn \l__tblr_row_head_foot_dim + { + \__tblr_box_height:N \l__tblr_row_head_box + + \__tblr_box_height:N \l__tblr_row_foot_box + } + } + +\dim_new:N \tablewidth + +\cs_new_protected:Npn \__tblr_get_table_width: + { + \dim_zero:N \tablewidth + \int_step_inline:nn { \c@colcount } + { + \dim_add:Nn \tablewidth + { + \__tblr_spec_item:nn { vline } { [##1] / @vline-width } + + + \__tblr_data_item:nnn { column } {##1} { leftsep } + + + \__tblr_data_item:nnn { column } {##1} { @col-width } + + + \__tblr_data_item:nnn { column } {##1} { rightsep } + } + } + \dim_add:Nn \tablewidth + { + \__tblr_spec_item:ne { vline } + { [\int_eval:n { \c@colcount + 1 }] / @vline-width } + } + } + +\box_new:N \l__tblr_table_firsthead_box +\box_new:N \l__tblr_table_middlehead_box +\box_new:N \l__tblr_table_lasthead_box +\box_new:N \l__tblr_table_firstfoot_box +\box_new:N \l__tblr_table_middlefoot_box +\box_new:N \l__tblr_table_lastfoot_box + +\cs_new_protected:Npn \__tblr_build_table_head_foot: { - \tl_set:Nn \l__tblr_i_tl {#1} - \tl_set:Nn \l__tblr_j_tl {#2} + \__tblr_get_table_width: + \__tblr_build_table_head_aux:Nn \l__tblr_table_firsthead_box + { + \__tblr_build_table_label_entry: + \UseTblrTemplate { firsthead } { default } + } + \__tblr_build_table_head_aux:Nn + \l__tblr_table_middlehead_box { \UseTblrTemplate { middlehead } { default } } + \__tblr_build_table_head_aux:Nn + \l__tblr_table_lasthead_box { \UseTblrTemplate { lasthead } { default } } + \__tblr_build_table_foot_aux:Nn + \l__tblr_table_firstfoot_box { \UseTblrTemplate { firstfoot } { default } } + \__tblr_build_table_foot_aux:Nn + \l__tblr_table_middlefoot_box { \UseTblrTemplate { middlefoot } { default } } + \__tblr_build_table_foot_aux:Nn + \l__tblr_table_lastfoot_box { \UseTblrTemplate { lastfoot } { default } } + } + +\cs_new_protected:Npn \__tblr_build_tall_table_head_foot: + { + \__tblr_get_table_width: + \__tblr_build_table_head_aux:Nn \l__tblr_table_firsthead_box + { + \__tblr_build_table_label_entry: + \UseTblrTemplate { firsthead } { default } + } + \__tblr_build_table_foot_aux:Nn + \l__tblr_table_lastfoot_box { \UseTblrTemplate { lastfoot } { default } } + } + +\cs_new_protected:Npn \__tblr_build_table_label_entry: + { + \tl_set:Nx \l_tmpa_tl { \InsertTblrText { label } } + \tl_if_eq:NnTF \l_tmpa_tl { none } + { + \SetTblrTemplate { caption-tag }{ empty } + \SetTblrTemplate { caption-sep }{ empty } + } + { + \refstepcounter { table } + \tl_if_empty:NF \l_tmpa_tl { \exp_args:NV \label \l_tmpa_tl } + } + \tl_set:Nx \l_tmpb_tl { \InsertTblrText { entry } } + \tl_if_eq:NnF \l_tmpb_tl { none } + { \UseTblrTemplate { caption-lot } { default } } + } + +\cs_new_protected:Npn \__tblr_build_table_head_aux:Nn #1 #2 + { + \vbox_set:Nn #1 + { + \hsize = \tablewidth + \parindent = 0pt \relax + \vbox:n {#2} + \skip_vertical:n { \__tblr_spec_item:nn { outer } { headsep } } + } + } + +\cs_new_protected:Npn \__tblr_build_table_foot_aux:Nn #1 #2 + { + \vbox_set:Nn #1 + { + \hsize = \tablewidth + \skip_vertical:n { \__tblr_spec_item:nn { outer } { footsep } } + \parindent = 0pt \relax + \vbox:n {#2} + } + } + +\cs_new_protected:Npn \__tblr_build_whole: + { + \tl_if_eq:enTF { \__tblr_spec_item:nn { outer } { long } } { true } + { \__tblr_build_long_table:e { \__tblr_spec_item:nn { outer } { halign } } } + { + \tl_if_eq:enTF { \__tblr_spec_item:nn { outer } { tall } } { true } + { + \__tblr_build_tall_table:e + { \__tblr_spec_item:nn { outer } { valign } } + } + { + \__tblr_build_short_table:e + { \__tblr_spec_item:nn { outer } { valign } } + } + } } -%% Compute and set span widths from column widths -\cs_new_protected:Npn \__tblr_set_span_widths_from_column_widths: +\dim_new:N \l__tblr_remain_height_dim +\int_new:N \l__tblr_long_from_int +\int_new:N \l__tblr_long_to_int +\int_new:N \l__tblr_curr_i_int +\int_new:N \l__tblr_prev_i_int +\int_new:N \l__tblr_table_page_int +\bool_new:N \l__tblr_page_break_curr_bool +\bool_new:N \l__tblr_page_break_prev_bool + +%% #1: table alignment +%% For long table, we need to leave hmode first to get correct \pagetotal +%% Also remove topskip and presep if we are at the beginning of the page +\cs_new_protected:Npn \__tblr_build_long_table:n #1 { - \int_step_variable:nNn { \c@colcount } \l__tblr_j_tl - { - \int_step_variable:nNn { \c@rowcount } \l__tblr_i_tl + \LogTblrTracing { page } + \par + \LogTblrTracing { page } + \dim_compare:nNnTF { \pagegoal } = { \maxdimen } + { \hbox{}\kern-\topskip\nobreak } + { \skip_vertical:n { \__tblr_spec_item:nn { outer } { presep } } } + \LogTblrTracing { page } + \nointerlineskip + \mode_leave_vertical: % enter horizontal mode to update \pagetotal + \LogTblrTracing { page } + \hrule height ~ 0pt + \nobreak % prevent page break after \hrule (see issue #42) + \LogTblrTracing { page } + \int_set:Nn \l__tblr_table_page_int {1} + \__tblr_build_head_foot: + \dim_set:Nn \l__tblr_remain_height_dim + { \pagegoal - \pagetotal - \l__tblr_row_head_foot_dim } + \int_set:Nn \l__tblr_long_from_int { \l__tblr_row_head_tl + 1 } + \int_set:Nn \l__tblr_long_to_int { \c@rowcount - ( \l__tblr_row_foot_tl + 0 ) } + \int_set:Nn \l__tblr_curr_i_int { \l__tblr_long_from_int - 1 } + \int_do_while:nNnn { \l__tblr_curr_i_int } < { \l__tblr_long_to_int } + { + \int_set_eq:NN \l__tblr_prev_i_int \l__tblr_curr_i_int + \__tblr_get_next_table_rows:NNNN + \l__tblr_long_to_int \l__tblr_curr_i_int + \l_tmpa_dim \l__tblr_page_break_curr_bool + \__tblr_check_table_page_break:NNN + \l__tblr_remain_height_dim \l_tmpa_dim \l__tblr_page_break_prev_bool + \__tblr_do_if_tracing:nn { page } { \int_log:N \l__tblr_curr_i_int } + \bool_if:NTF \l__tblr_page_break_prev_bool { - \tl_set:Nx \l__tblr_a_tl + \int_compare:nNnTF + { \l__tblr_long_from_int } > { \l__tblr_prev_i_int } { - \__tblr_data_item:neen { cell } - { \l__tblr_i_tl } { \l__tblr_j_tl } { colspan } + % See issue #42: if longtblr starts at the bottom of a page, + % \pagetotal maybe exceed \pagegoal after adding presep, + % or after adding rowhead or rowfoot of the table. + % In these cases, we will not typeset table in this page, + % but rather do some negative \vskip and execute \newpage. + \skip_vertical:n { \pagegoal - \pagetotal } } - \int_compare:nNnT { \l__tblr_a_tl } > {1} { - \__tblr_calc_span_widths:xxN - { \l__tblr_j_tl } - { \int_eval:n { \l__tblr_j_tl + \l__tblr_a_tl - 1 } } - \l__tblr_w_dim - \__tblr_data_gput:neene { cell } - { \l__tblr_i_tl } { \l__tblr_j_tl } { width } - { \dim_use:N \l__tblr_w_dim } + \__tblr_build_page_table:nnx {#1} + { \int_use:N \l__tblr_long_from_int } + { \int_use:N \l__tblr_prev_i_int } + \int_incr:N \l__tblr_table_page_int + \int_set:Nn \l__tblr_long_from_int { \l__tblr_prev_i_int + 1 } + } + \newpage + \hbox{}\kern-\topskip\nobreak + \noindent + \LogTblrTracing { page } + \dim_set:Nn \l__tblr_remain_height_dim + { \pagegoal - \pagetotal - \l__tblr_row_head_foot_dim - \l_tmpa_dim } + } + { + \bool_if:NTF \l__tblr_page_break_curr_bool + { + \__tblr_build_page_table:nnx {#1} + { \int_use:N \l__tblr_long_from_int } + { \int_use:N \l__tblr_curr_i_int } + \int_incr:N \l__tblr_table_page_int + \newpage + \hbox{}\kern-\topskip\nobreak + \noindent + \LogTblrTracing { page } + \dim_set:Nn \l__tblr_remain_height_dim + { \pagegoal - \pagetotal - \l__tblr_row_head_foot_dim } + \int_set:Nn \l__tblr_long_from_int { \l__tblr_curr_i_int + 1 } } + { \dim_add:Nn \l__tblr_remain_height_dim { -\l_tmpa_dim } } } } + \int_compare:nNnTF { \l__tblr_table_page_int } = {1} + { + \box_set_eq:NN \l__tblr_table_head_box \l__tblr_table_firsthead_box + \box_set_eq:NN \l__tblr_table_foot_box \l__tblr_table_lastfoot_box + } + { + \box_set_eq:NN \l__tblr_table_head_box \l__tblr_table_lasthead_box + \box_set_eq:NN \l__tblr_table_foot_box \l__tblr_table_lastfoot_box + } + \__tblr_build_page_table:nnn {#1} + { \int_use:N \l__tblr_long_from_int } { \int_use:N \l__tblr_long_to_int } + \skip_vertical:n { \__tblr_spec_item:nn { outer } { postsep } } + % In the past we used "\hrule height ~ 0pt" to get strict postsep, + % but the postsep was not discarded when page breaks, see issue #39. + % Therefore we use \nointerlineskip here. + \nointerlineskip } +\cs_generate_variant:Nn \__tblr_build_long_table:n { e } -%% Cell is spanned from col #1 to col #2, #3 is the return dim -\cs_new_protected:Npn \__tblr_calc_span_widths:nnN #1 #2 #3 +%% #1: int with index of the last row; #2: int with index of current row; +%% #3: row dimension; #4: break page or not. +\cs_new_protected:Npn \__tblr_get_next_table_rows:NNNN #1 #2 #3 #4 { + \bool_set_true:N \l_tmpa_bool \dim_zero:N #3 - \int_step_inline:nnn { #1 } { #2 } + \bool_set_false:N #4 + \bool_while_do:Nn \l_tmpa_bool { - \tl_set:Nx \l_tmpa_tl - { \prop_item:Ne \l__tblr_col_item_skip_size_prop { skip[##1] } } - \tl_set:Nx \l_tmpb_tl - { \prop_item:Ne \l__tblr_col_item_skip_size_prop { item[##1] } } - \dim_add:Nn #3 { \dim_eval:n { \l_tmpa_tl + \l_tmpb_tl } } + \int_incr:N #2 + \dim_add:Nn #3 + { + \__tblr_data_item:nen { row } { \int_use:N #2 } { abovesep } + + + \__tblr_data_item:nen { row } { \int_use:N #2 } { @row-height } + + + \__tblr_data_item:nen { row } { \int_use:N #2 } { belowsep } + + + \__tblr_spec_item:ne { hline } + { [ \int_eval:n { #2 + 1 } ] / @hline-height } + } + \int_compare:nNnTF {#2} < {#1} + { + \tl_set:Nx \l__tblr_b_tl + { \__tblr_data_item:nen { row } { \int_eval:n { #2 + 1 } } { break } } + \int_compare:nNnTF { \l__tblr_b_tl } < { 0 } + { \bool_set_true:N \l_tmpa_bool } + { + \bool_set_false:N \l_tmpa_bool + \int_compare:nNnT { \l__tblr_b_tl } > { 0 } { \bool_set_true:N #4 } + } + } + { \bool_set_false:N \l_tmpa_bool } } } -\cs_generate_variant:Nn \__tblr_calc_span_widths:nnN { xxN } - -%%% -------------------------------------------------------- -%% \section{Build the Whole Table} -%%% -------------------------------------------------------- - -\tl_new:N \__tlbr_vbox_align_tl -\tl_const:Nn \__tlbr_vbox_t_tl {t} -\tl_const:Nn \__tlbr_vbox_m_tl {m} -\tl_const:Nn \__tlbr_vbox_c_tl {c} -\tl_const:Nn \__tlbr_vbox_b_tl {b} - -\box_new:N \l__tblr_table_box - -%% #1: table alignment -\cs_new_protected:Npn \__tblr_build_whole:n #1 - { - \bool_if:NTF \l__tblr_long_table_bool - { \__tblr_build_long_table:n {#1} } - { \__tblr_build_short_table:n {#1} } - } -\dim_new:N \l__tblr_remain_height_dim -\tl_new:N \l__tblr_long_from_tl +\box_new:N \l__tblr_table_head_box +\box_new:N \l__tblr_table_foot_box +\dim_new:N \l__tblr_table_head_foot_dim +\dim_new:N \l__tblr_table_head_body_foot_dim -\cs_new_protected:Npn \__tblr_build_long_table:n #1 +%% #1: remain dimension; #2: row dimension; #3: break page or not +\cs_new_protected:Npn \__tblr_check_table_page_break:NNN #1 #2 #3 { - %\dim_log:N \pagegoal - %\dim_log:N \pagetotal - \dim_set:Nn \l__tblr_remain_height_dim { \pagegoal - \pagetotal } - \tl_set:Nn \l__tblr_long_from_tl {1} - \int_step_variable:nNn { \c@rowcount } \l__tblr_i_tl + \int_compare:nNnTF { \l__tblr_table_page_int } = {1} { - \dim_set:Nn \l_tmpa_dim + \dim_set:Nn \l__tblr_table_head_body_foot_dim { - \__tblr_text_item:ne { hline } { [\l__tblr_i_tl] / @hline-height } - + - \__tblr_data_item:nen { row } { \l__tblr_i_tl } { abovesep } - + - \__tblr_data_item:nen { row } { \l__tblr_i_tl } { @row-height } - + - \__tblr_data_item:nen { row } { \l__tblr_i_tl } { belowsep } + \__tblr_box_height:N \l__tblr_table_firsthead_box + + #2 + \__tblr_box_height:N \l__tblr_table_firstfoot_box } + \box_set_eq:NN \l__tblr_table_head_box \l__tblr_table_firsthead_box \dim_compare:nNnTF - { \l_tmpa_dim } > { \l__tblr_remain_height_dim } + { \l__tblr_table_head_body_foot_dim } > {#1} { - \tl_log:N \l__tblr_i_tl - \__tblr_build_page_table:nnx {#1} - { \l__tblr_long_from_tl } { \int_eval:n { \l__tblr_i_tl - 1 } } - \newpage - \hbox{}\kern-\topskip\nobreak - \leavevmode - %\dim_log:N \pagegoal - %\dim_log:N \pagetotal - \dim_set:Nn \l__tblr_remain_height_dim - { \pagegoal - \pagetotal - \l_tmpa_dim } - \tl_set_eq:NN \l__tblr_long_from_tl \l__tblr_i_tl + \bool_set_true:N #3 + \box_set_eq:NN \l__tblr_table_foot_box \l__tblr_table_firstfoot_box + } + { \bool_set_false:N #3 } + } + { + \dim_set:Nn \l__tblr_table_head_body_foot_dim + { + \__tblr_box_height:N \l__tblr_table_middlehead_box + + #2 + \__tblr_box_height:N \l__tblr_table_middlefoot_box } + \box_set_eq:NN \l__tblr_table_head_box \l__tblr_table_middlehead_box + \dim_compare:nNnTF + { \l__tblr_table_head_body_foot_dim } > {#1} { - \dim_add:Nn \l__tblr_remain_height_dim { -\l_tmpa_dim } + \bool_set_true:N #3 + \box_set_eq:NN \l__tblr_table_foot_box \l__tblr_table_middlefoot_box } + { \bool_set_false:N #3 } } - \__tblr_build_page_table:nnn {#1} { \l__tblr_long_from_tl } { \c@rowcount } } +\box_new:N \l__tblr_table_box + +%% #1: table alignment; #2: row from; #3: row to \cs_new_protected:Npn \__tblr_build_page_table:nnn #1 #2 #3 { + \bool_set_false:N \l__tblr_build_first_hline_bool + \bool_set_false:N \l__tblr_build_last_hline_bool \__tblr_build_one_table:nn {#2} {#3} + \vbox_set:Nn \l__tblr_table_box + { + \box_use:N \l__tblr_table_head_box + \__tblr_cover_two_vboxes:NN \l__tblr_row_head_box \l__tblr_table_box + \box_use:N \l__tblr_row_foot_box + \hrule height ~ 0pt + \box_use:N \l__tblr_table_foot_box + } \__tblr_halign_whole:Nn \l__tblr_table_box #1 } \cs_generate_variant:Nn \__tblr_build_page_table:nnn { nnx } +%% To solve the problem of missing hlines of long tables in some PDF readers, +%% We need to draw body rows before head rows (see issue #88). +\cs_new_protected:Npn \__tblr_cover_two_vboxes:NN #1 #2 + { + \dim_set:Nn \l_tmpa_dim { \box_ht:N #1 + \box_dp:N #1 } + \dim_set:Nn \l_tmpb_dim { \box_ht:N #2 + \box_dp:N #2 } + \skip_vertical:N \l_tmpa_dim + \hrule height ~ 0pt + \box_use:N #2 + \skip_vertical:n { - \l_tmpa_dim - \l_tmpb_dim } + \hrule height ~ 0pt + \box_use:N #1 + \skip_vertical:N \l_tmpb_dim + \hrule height ~ 0pt + } + \cs_new_protected:Npn \__tblr_halign_whole:Nn #1 #2 { \noindent @@ -3818,42 +5456,129 @@ } } +%% #1: table alignment +%% For tall table, we need to leave vmode first. +%% Since there may be \centering in table environment, +%% We use \raggedright to reset alignement for table head/foot. +\cs_new_protected:Npn \__tblr_build_tall_table:n #1 + { + \mode_leave_vertical: + \raggedright + \__tblr_build_tall_table_head_foot: + \__tblr_build_one_table:nn {1} {\c@rowcount} + \vbox_set:Nn \l__tblr_table_box + { + \box_use:N \l__tblr_table_firsthead_box + \hrule height ~ 0pt + \box_use:N \l__tblr_table_box + \hrule height ~ 0pt + \box_use:N \l__tblr_table_lastfoot_box + } + \__tblr_valign_whole:Nn \l__tblr_table_box #1 + } +\cs_generate_variant:Nn \__tblr_build_tall_table:n { e } + +%% #1: table alignment +%% For short table, we need to leave vmode first \cs_new_protected:Npn \__tblr_build_short_table:n #1 { + \mode_leave_vertical: \__tblr_build_one_table:nn {1} {\c@rowcount} \__tblr_valign_whole:Nn \l__tblr_table_box #1 } +\cs_generate_variant:Nn \__tblr_build_short_table:n { e } + +\bool_new:N \l__tblr_build_first_hline_bool +\bool_new:N \l__tblr_build_last_hline_bool +\bool_set_true:N \l__tblr_build_first_hline_bool +\bool_set_true:N \l__tblr_build_last_hline_bool +\box_new:N \l__tblr_table_hlines_box +\box_new:N \l__tblr_hline_box +\box_new:N \l__tblr_row_box %% #1: row from; #2: row to +%% To fix disappeared hlines with colorful tables in Adobe Reader (see #76), +%% we collect all hlines and draw them at the end of the table. \cs_new_protected:Npn \__tblr_build_one_table:nn #1 #2 { + \box_clear:N \l__tblr_table_hlines_box \vbox_set:Nn \l__tblr_table_box { \int_step_variable:nnNn {#1} {#2} \l__tblr_i_tl { - \hbox:n { \__tblr_build_hline:V \l__tblr_i_tl } + \bool_lazy_or:nnT + { \int_compare_p:nNn { \l__tblr_i_tl } > {#1} } + { \bool_if_p:N \l__tblr_build_first_hline_bool } + { \__tblr_put_one_hline:n { \__tblr_build_hline:V \l__tblr_i_tl } } \hrule height ~ 0pt % remove lineskip between hlines and rows - \hbox:n { \__tblr_build_row:N \l__tblr_i_tl } + \__tblr_put_one_row:n { \__tblr_build_row:N \l__tblr_i_tl } \hrule height ~ 0pt } - \hbox:n { \__tblr_build_hline:n { \int_eval:n {#2 + 1} } } + \bool_if:NT \l__tblr_build_last_hline_bool + { + \__tblr_put_one_hline:n + { \__tblr_build_hline:n { \int_eval:n {#2 + 1} } } + } + \skip_vertical:n + { + - \box_ht:N \l__tblr_table_hlines_box + - \box_dp:N \l__tblr_table_hlines_box + } + \box_use:N \l__tblr_table_hlines_box + } + \bool_set_true:N \l__tblr_build_first_hline_bool + \bool_set_true:N \l__tblr_build_last_hline_bool + } + +\cs_new_protected:Npn \__tblr_put_one_hline:n #1 + { + \hbox_set:Nn \l__tblr_hline_box {#1} + \skip_vertical:n { \box_ht:N \l__tblr_hline_box + \box_dp:N \l__tblr_hline_box } + \vbox_set:Nn \l__tblr_table_hlines_box + { + \vbox_unpack:N \l__tblr_table_hlines_box + \box_use:N \l__tblr_hline_box } } +\cs_new_protected:Npn \__tblr_put_one_row:n #1 + { + \hbox_set:Nn \l__tblr_row_box {#1} + \vbox_set:Nn \l__tblr_table_hlines_box + { + \vbox_unpack:N \l__tblr_table_hlines_box + \skip_vertical:n + { \box_ht:N \l__tblr_row_box + \box_dp:N \l__tblr_row_box } + } + \box_use:N \l__tblr_row_box + } + +%% #1: hline number +\cs_new_protected:Npn \__tblr_build_one_hline:n #1 + { + \vbox_set:Nn \l__tblr_table_box { \hbox:n { \__tblr_build_hline:n { #1 } } } + } + +\tl_new:N \__tblr_vbox_align_tl +\tl_const:Nn \__tblr_vbox_t_tl {t} +\tl_const:Nn \__tblr_vbox_m_tl {m} +\tl_const:Nn \__tblr_vbox_c_tl {c} +\tl_const:Nn \__tblr_vbox_b_tl {b} + \cs_new_protected:Npn \__tblr_valign_whole:Nn #1 #2 { \group_begin: - \tl_set:Nn \__tlbr_vbox_align_tl {#2} + \tl_set:Nn \__tblr_vbox_align_tl {#2} \dim_set:Nn \l__tblr_t_dim { \box_ht:N #1 + \box_dp:N #1 } - \tl_case:NnF \__tlbr_vbox_align_tl + \tl_case:NnF \__tblr_vbox_align_tl { - \__tlbr_vbox_m_tl + \__tblr_vbox_m_tl { \__tblr_valign_whole_middle:N #1 } - \__tlbr_vbox_c_tl + \__tblr_vbox_c_tl { \__tblr_valign_whole_middle:N #1 } - \__tlbr_vbox_t_tl + \__tblr_vbox_t_tl { \__tblr_valign_whole_top:N #1 } - \__tlbr_vbox_b_tl + \__tblr_vbox_b_tl { \__tblr_valign_whole_bottom:N #1 } } { \__tblr_valign_whole_middle:N #1 } @@ -3868,10 +5593,10 @@ \cs_new_protected:Npn \__tblr_valign_whole_top:N #1 { \tl_set:Nx \l__tblr_a_tl - { \__tblr_text_item:ne { hline } { [1] / @hline-height } } + { \__tblr_spec_item:ne { hline } { [1] / @hline-height } } %% Note that \l__tblr_b_tl may be empty \tl_set:Nx \l__tblr_b_tl - { \__tblr_prop_item:ne { table } { baseline } } + { \__tblr_prop_item:ne { inner } { baseline } } \bool_lazy_or:nnTF { \dim_compare_p:nNn { \l__tblr_a_tl } = { 0pt } } { \int_compare_p:nNn { \l__tblr_b_tl + 0 } = { 1 } } @@ -3902,12 +5627,12 @@ { \tl_set:Nx \l__tblr_a_tl { - \__tblr_text_item:ne { hline } + \__tblr_spec_item:ne { hline } { [\int_eval:n {\c@rowcount + 1}] / @hline-height } } %% Note that \l__tblr_b_tl may be empty \tl_set:Nx \l__tblr_b_tl - { \__tblr_prop_item:ne { table } { baseline } } + { \__tblr_prop_item:ne { inner } { baseline } } \bool_lazy_or:nnTF { \dim_compare_p:nNn { \l__tblr_a_tl } = { 0pt } } { \int_compare_p:nNn { \l__tblr_b_tl + 0 } = { \c@rowcount } } @@ -3937,6 +5662,10 @@ \box_use_drop:N #1 } +%%% -------------------------------------------------------- +%%> \section{Build Table Components} +%%% -------------------------------------------------------- + \dim_new:N \l__tblr_col_o_wd_dim \dim_new:N \l__tblr_col_b_wd_dim @@ -3952,9 +5681,9 @@ \cs_new_protected:Npn \__tblr_build_hline_segment:nn #1 #2 { \tl_set:Nx \l__tblr_n_tl - { \__tblr_text_item:ne { hline } { [#1] / @hline-count } } + { \__tblr_spec_item:ne { hline } { [#1] / @hline-count } } \tl_set:Nx \l__tblr_o_tl - { \__tblr_text_item:ne { hline } { [#1][#2] / omit } } + { \__tblr_spec_item:ne { hline } { [#1][#2] / omit } } \__tblr_get_col_outer_width_border_width:nNN {#2} \l__tblr_col_o_wd_dim \l__tblr_col_b_wd_dim \tl_if_empty:NTF \l__tblr_o_tl @@ -3975,7 +5704,7 @@ \cs_new_protected:Npn \__tblr_build_hline_segment_real:nn #1 #2 { \tl_set:Nx \l__tblr_s_tl - { \__tblr_prop_item:ne { table } { rulesep } } + { \__tblr_prop_item:ne { inner } { rulesep } } \vbox_set:Nn \l__tblr_c_box { %% add an empty hbox to support vbox width @@ -3983,14 +5712,17 @@ \int_step_inline:nn { \l__tblr_n_tl } { \tl_set:Nx \l__tblr_h_tl - { \__tblr_text_item:ne { hline } { [#1](##1) / @hline-height } } + { \__tblr_spec_item:ne { hline } { [#1](##1) / @hline-height } } \hrule height ~ 0pt % remove lineskip \hbox_set_to_wd:Nnn \l__tblr_b_box { \l__tblr_col_o_wd_dim } { + \__tblr_get_hline_left_right_skips:nnn {#1} {#2} {##1} + \skip_horizontal:N \l__tblr_hline_leftskip_dim \tl_set:Nx \l__tblr_f_tl - { \__tblr_text_item:ne { hline } { [#1][#2](##1) / fg } } + { \__tblr_spec_item:ne { hline } { [#1][#2](##1) / fg } } \tl_if_empty:NF \l__tblr_f_tl { \color{\l__tblr_f_tl} } \__tblr_get_hline_segment_child:nnn {#1} {#2} {##1} + \skip_horizontal:N \l__tblr_hline_rightskip_dim } \box_set_ht:Nn \l__tblr_b_box { \l__tblr_h_tl } \box_set_dp:Nn \l__tblr_b_box { 0pt } @@ -4009,10 +5741,10 @@ \cs_new_protected:Npn \__tblr_get_col_outer_width_border_width:nNN #1 #2 #3 { \dim_set:Nn #3 - { \__tblr_text_item:ne { vline } { [\int_eval:n {#1 + 1}] / @vline-width } } + { \__tblr_spec_item:ne { vline } { [\int_eval:n {#1 + 1}] / @vline-width } } \dim_set:Nn #2 { - \__tblr_text_item:ne { vline } { [#1] / @vline-width } + \__tblr_spec_item:ne { vline } { [#1] / @vline-width } + \__tblr_data_item:nen { column } {#1} { leftsep } + @@ -4024,24 +5756,92 @@ } } +\dim_new:N \l__tblr_hline_leftskip_dim +\dim_new:N \l__tblr_hline_rightskip_dim + +%% Calculate left and right skips from leftpos and rightpos specifications +%% #1: row number; #2: column number; #3: hline index; +\cs_new_protected:Npn \__tblr_get_hline_left_right_skips:nnn #1 #2 #3 + { + \tl_set:Nx \l__tblr_hline_leftpos_tl + { \__tblr_spec_item:ne { hline } { [#1][#2](#3) / leftpos } } + \tl_if_empty:NT \l__tblr_hline_leftpos_tl + { \tl_set:Nn \l__tblr_hline_leftpos_tl {1} } % default position + \tl_set:Nx \l__tblr_hline_rightpos_tl + { \__tblr_spec_item:ne { hline } { [#1][#2](#3) / rightpos } } + \tl_if_empty:NT \l__tblr_hline_rightpos_tl + { \tl_set:Nn \l__tblr_hline_rightpos_tl {1} } % default position + \fp_compare:nNnT { \l__tblr_hline_leftpos_tl } < {1} + { + \dim_set:Nn \l_tmpa_dim + { \__tblr_spec_item:ne { vline } { [#2] / @vline-width } } + \dim_set:Nn \l_tmpb_dim + { \__tblr_data_item:nen { column } {#2} { leftsep } } + \fp_compare:nNnTF { \l__tblr_hline_leftpos_tl } < {0} + { + \dim_set:Nn \l__tblr_hline_leftskip_dim + { \l_tmpa_dim - \l__tblr_hline_leftpos_tl \l_tmpb_dim } + } + { + \dim_set:Nn \l__tblr_hline_leftskip_dim + { \l_tmpa_dim - \l__tblr_hline_leftpos_tl \l_tmpa_dim } + } + } + \fp_compare:nNnT { \l__tblr_hline_rightpos_tl } < {1} + { + \dim_set:Nn \l_tmpa_dim + { + \__tblr_spec_item:ne { vline } + { [\int_eval:n { #2 + 1 }] / @vline-width } + } + \dim_set:Nn \l_tmpb_dim + { \__tblr_data_item:nen { column } {#2} { rightsep } } + \fp_compare:nNnTF { \l__tblr_hline_rightpos_tl } < {0} + { + \dim_set:Nn \l__tblr_hline_rightskip_dim + { \l_tmpa_dim - \l__tblr_hline_rightpos_tl \l_tmpb_dim } + } + { + \dim_set:Nn \l__tblr_hline_rightskip_dim + { \l_tmpa_dim - \l__tblr_hline_rightpos_tl \l_tmpa_dim } + } + } + } + \dim_new:N \l__tblr_row_ht_dim \dim_new:N \l__tblr_row_dp_dim \dim_new:N \l__tblr_row_abovesep_dim \dim_new:N \l__tblr_row_belowsep_dim +\box_new:N \l__tblr_row_vlines_box +\box_new:N \l__tblr_vline_box +\box_new:N \l__tblr_cell_box %% Build current row, #1: row number +%% To fix disappeared vlines with colorful tables in Adobe Reader (see #76), +%% we collect all vlines and draw them at the end of the row. \cs_new_protected:Npn \__tblr_build_row:N #1 { + \int_set:Nn \c@rownum {#1} + \__tblr_update_rowsep_registers: \__tblr_get_row_inner_height_depth:VNNNN #1 \l__tblr_row_ht_dim \l__tblr_row_dp_dim \l__tblr_row_abovesep_dim \l__tblr_row_belowsep_dim \vrule width ~ 0pt ~ height ~ \l__tblr_row_ht_dim ~ depth ~ \l__tblr_row_dp_dim + \hbox_set:Nn \l__tblr_row_vlines_box + { + \vrule width ~ 0pt ~ height ~ \l__tblr_row_ht_dim + ~ depth ~ \l__tblr_row_dp_dim + } \int_step_variable:nNn { \c@colcount } \l__tblr_j_tl { - \__tblr_build_vline_segment:nn {#1} { \l__tblr_j_tl } - \__tblr_build_cell:NN #1 \l__tblr_j_tl + \__tblr_put_one_vline:n + { \__tblr_build_vline_segment:nn {#1} { \l__tblr_j_tl } } + \__tblr_put_one_cell:n { \__tblr_build_cell:NN #1 \l__tblr_j_tl } } - \__tblr_build_vline_segment:nn {#1} { \int_eval:n {\c@colcount + 1} } + \__tblr_put_one_vline:n + { \__tblr_build_vline_segment:nn {#1} { \int_eval:n {\c@colcount + 1} } } + \skip_horizontal:n { - \box_wd:N \l__tblr_row_vlines_box } + \box_use:N \l__tblr_row_vlines_box } %% Read from table specifications and calculate inner height/depth of the row @@ -4074,13 +5874,35 @@ } \cs_generate_variant:Nn \__tblr_get_row_inner_height_depth:nNNNN { V } +\cs_new_protected:Npn \__tblr_put_one_vline:n #1 + { + \hbox_set:Nn \l__tblr_vline_box {#1} + \skip_horizontal:n { \box_wd:N \l__tblr_vline_box } + \hbox_set:Nn \l__tblr_row_vlines_box + { + \hbox_unpack:N \l__tblr_row_vlines_box + \box_use:N \l__tblr_vline_box + } + } + +\cs_new_protected:Npn \__tblr_put_one_cell:n #1 + { + \hbox_set:Nn \l__tblr_cell_box {#1} + \hbox_set:Nn \l__tblr_row_vlines_box + { + \hbox_unpack:N \l__tblr_row_vlines_box + \skip_horizontal:n { \box_wd:N \l__tblr_cell_box } + } + \box_use:N \l__tblr_cell_box + } + %% #1: row number, #2: column number \cs_new_protected:Npn \__tblr_build_vline_segment:nn #1 #2 { \tl_set:Nx \l__tblr_n_tl - { \__tblr_text_item:ne { vline } { [#2] / @vline-count } } + { \__tblr_spec_item:ne { vline } { [#2] / @vline-count } } \tl_set:Nx \l__tblr_o_tl - { \__tblr_text_item:ne { vline } { [#1][#2] / omit } } + { \__tblr_spec_item:ne { vline } { [#1][#2] / omit } } \tl_if_empty:NTF \l__tblr_o_tl { \int_compare:nNnT { \l__tblr_n_tl } > {0} @@ -4093,7 +5915,7 @@ \cs_new_protected:Npn \__tblr_build_vline_segment_omit:nn #1 #2 { \tl_set:Nx \l__tblr_w_tl - { \__tblr_text_item:ne { vline } { [#2] / @vline-width } } + { \__tblr_spec_item:ne { vline } { [#2] / @vline-width } } \skip_horizontal:N \l__tblr_w_tl } @@ -4103,29 +5925,25 @@ \cs_new_protected:Npn \__tblr_build_vline_segment_real:nn #1 #2 { \tl_set:Nx \l__tblr_s_tl - { \__tblr_prop_item:ne { table } { rulesep } } - \tl_set:Nx \l__tblr_b_tl - { - \__tblr_text_item:ne { hline } - { [\int_eval:n{#1 + 1}](1) / @hline-height } - } - \tl_if_empty:NT \l__tblr_b_tl { \tl_set:Nn \l__tblr_b_tl { 0pt } } + { \__tblr_prop_item:ne { inner } { rulesep } } \hbox_set:Nn \l__tblr_a_box { \int_step_inline:nn { \l__tblr_n_tl } { \tl_set:Nx \l__tblr_w_tl - { \__tblr_text_item:ne { vline } { [#2](##1) / @vline-width } } + { \__tblr_spec_item:ne { vline } { [#2](##1) / @vline-width } } \vbox_set_to_ht:Nnn \l__tblr_b_box { \dim_eval:n { \l__tblr_row_ht_dim + \l__tblr_row_dp_dim } } { \tl_set:Nx \l__tblr_f_tl - { \__tblr_text_item:ne { vline } { [#1][#2](##1) / fg } } + { \__tblr_spec_item:ne { vline } { [#1][#2](##1) / fg } } \tl_if_empty:NF \l__tblr_f_tl { \color{\l__tblr_f_tl} } + \__tblr_get_vline_above_below_skips:nnn {#1} {#2} {##1} + \skip_vertical:N \l__tblr_vline_aboveskip_dim \__tblr_get_vline_segment_child:nnnxx {#1} {#2} {##1} { \dim_eval:n { \l__tblr_row_ht_dim } } - { \dim_eval:n { \l__tblr_row_dp_dim + \l__tblr_b_tl } } - \skip_vertical:n { - \l__tblr_b_tl } + { \dim_eval:n { \l__tblr_row_dp_dim } } + \skip_vertical:N \l__tblr_vline_belowskip_dim } \box_set_wd:Nn \l__tblr_b_box { \l__tblr_w_tl } \box_use:N \l__tblr_b_box @@ -4139,6 +5957,68 @@ \box_use:N \l__tblr_c_box } +\dim_new:N \l__tblr_vline_aboveskip_dim +\dim_new:N \l__tblr_vline_belowskip_dim + +%% Calculate above and below skips from abovepos and belowpos specifications +%% #1: row number; #2: column number; #3: vline index; +\cs_new_protected:Npn \__tblr_get_vline_above_below_skips:nnn #1 #2 #3 + { + \tl_set:Nx \l__tblr_vline_abovepos_tl + { \__tblr_spec_item:ne { vline } { [#1][#2](#3) / abovepos } } + \tl_if_empty:NT \l__tblr_vline_abovepos_tl + { + \tl_set:Nn \l__tblr_vline_abovepos_tl {0} % default position + } + \tl_set:Nx \l__tblr_vline_belowpos_tl + { \__tblr_spec_item:ne { vline } { [#1][#2](#3) / belowpos } } + \tl_if_empty:NT \l__tblr_vline_belowpos_tl + { + \tl_set:Nn \l__tblr_vline_belowpos_tl {0} % default position + } + \fp_compare:nNnF { \l__tblr_vline_abovepos_tl } = {0} + { + \dim_set:Nn \l_tmpa_dim + { \__tblr_spec_item:ne { hline } { [#1] / @hline-height } } + \fp_compare:nNnTF { \l__tblr_vline_abovepos_tl } < {0} + { + \dim_set:Nn \l__tblr_vline_aboveskip_dim + { - \l__tblr_vline_abovepos_tl \l__tblr_row_abovesep_dim } + } + { + \dim_set:Nn \l__tblr_vline_aboveskip_dim + { - \l__tblr_vline_abovepos_tl \l_tmpa_dim } + } + } + %% To join two vline segment above and below a cline, + %% we choose to extend every vline downwards a little (#55). + \fp_compare:nNnTF { \l__tblr_vline_belowpos_tl } = {0} + { + \dim_set:Nn \l__tblr_vline_belowskip_dim + { + - \__tblr_spec_item:ne { hline } + { [\int_eval:n { #1 + 1 }](1) / @hline-height } + + 0pt + } + } + { + \dim_set:Nn \l_tmpa_dim + { + \__tblr_spec_item:ne { hline } + { [\int_eval:n { #1 + 1 }] / @hline-height } + } + \fp_compare:nNnTF { \l__tblr_vline_belowpos_tl } < {0} + { + \dim_set:Nn \l__tblr_vline_belowskip_dim + { - \l__tblr_vline_belowpos_tl \l__tblr_row_belowsep_dim } + } + { + \dim_set:Nn \l__tblr_vline_belowskip_dim + { - \l__tblr_vline_belowpos_tl \l_tmpa_dim } + } + } + } + \tl_new:N \l__tblr_cell_rowspan_tl \tl_new:N \l__tblr_cell_colspan_tl \dim_new:N \l__tblr_cell_wd_dim @@ -4146,8 +6026,8 @@ \cs_new_protected:Npn \__tblr_build_cell:NN #1 #2 { - \int_set:Nn \c@rownum {#1} \int_set:Nn \c@colnum {#2} + \__tblr_update_colsep_registers: \group_begin: \tl_set:Nx \l__tblr_w_tl { \__tblr_data_item:nen { column } {#2} { @col-width } } @@ -4183,9 +6063,13 @@ { \hbox_set_to_wd:Nnn \l__tblr_a_box { \l__tblr_cell_wd_dim } { - \tl_if_eq:NnF \g__tblr_cell_halign_tl {l} { \hfil } - \__tblr_get_cell_text:nn {#1} {#2} - \tl_if_eq:NnF \g__tblr_cell_halign_tl {r} { \hfil } + \tl_if_eq:NnTF \g__tblr_cell_halign_tl {j} + { \__tblr_get_cell_text:nn {#1} {#2} } + { + \tl_if_eq:NnF \g__tblr_cell_halign_tl {l} { \hfil } + \__tblr_get_cell_text:nn {#1} {#2} + \tl_if_eq:NnF \g__tblr_cell_halign_tl {r} { \hfil } + } } \vbox_set_to_ht:Nnn \l__tblr_b_box { \l__tblr_cell_ht_dim } { @@ -4305,20 +6189,23 @@ %% #1: row number; #2: column number; #3: dimen register for rowsep above. %% #4: dimen register for total height; #5: dimen register for rowsep below. %% We can use \l__tblr_row_item_skip_size_prop which was made before +%% But when vspan=even, there are no itemskip in the prop list. +%% Therefore we need to calculate them from the sizes of items and skips \cs_new_protected:Npn \__tblr_get_span_vertical_sizes:NNNNN #1 #2 #3 #4 #5 { \dim_set:Nn #3 { \__tblr_data_item:nen { row } {#1} { abovesep } } \dim_zero:N #4 - \int_step_inline:nnn { #1 } { #1 + \l__tblr_cell_rowspan_tl - 2 } - { - \dim_add:Nn #4 - { \prop_item:Ne \l__tblr_row_item_skip_size_prop { itemskip[##1] } } - } \dim_add:Nn #4 + { \prop_item:Ne \l__tblr_row_item_skip_size_prop { item[#1] } } + \int_step_inline:nnn { #1 + 1 } { #1 + \l__tblr_cell_rowspan_tl - 1 } { - \prop_item:Ne \l__tblr_row_item_skip_size_prop - { item[\int_eval:n { #1 + \l__tblr_cell_rowspan_tl - 1 }] } + \dim_add:Nn #4 + { + \prop_item:Ne \l__tblr_row_item_skip_size_prop { skip[##1] } + + + \prop_item:Ne \l__tblr_row_item_skip_size_prop { item[##1] } + } } \dim_set:Nn #5 { @@ -4331,28 +6218,24 @@ %% #1: row number; #2: column number; #3: dimen register for colsep left. %% #4: dimen register for total width; #5: dimen register for colsep right. %% We can use \l__tblr_col_item_skip_size_prop which was made before -%% But when hspan=minimal, there are no itemskip in the prop list. +%% But when hspan=even or hspan=minimal, there are no itemskip in the prop list. %% Therefore we need to calculate them from the sizes of items and skips \cs_new_protected:Npn \__tblr_get_span_horizontal_sizes:NNNNN #1 #2 #3 #4 #5 { \dim_set:Nn #3 { \__tblr_data_item:nen { column } {#2} { leftsep } } \dim_zero:N #4 - \int_step_inline:nnn { #2 } { #2 + \l__tblr_cell_colspan_tl - 2 } + \dim_add:Nn #4 + { \prop_item:Ne \l__tblr_col_item_skip_size_prop { item[#2] } } + \int_step_inline:nnn { #2 + 1 } { #2 + \l__tblr_cell_colspan_tl - 1 } { - \dim_add:Nn #4 - { \prop_item:Ne \l__tblr_col_item_skip_size_prop { item[##1] } } \dim_add:Nn #4 { - \prop_item:Ne \l__tblr_col_item_skip_size_prop - { skip[\int_eval:n { ##1 + 1 }] } + \prop_item:Ne \l__tblr_col_item_skip_size_prop { skip[##1] } + + + \prop_item:Ne \l__tblr_col_item_skip_size_prop { item[##1] } } } - \dim_add:Nn #4 - { - \prop_item:Ne \l__tblr_col_item_skip_size_prop - { item[\int_eval:n { #2 + \l__tblr_cell_colspan_tl - 1 }] } - } \dim_set:Nn #5 { \__tblr_data_item:nen { column } @@ -4373,7 +6256,10 @@ \bool_new:N \g__tblr_tracing_text_bool \bool_new:N \g__tblr_tracing_command_bool -\bool_new:N \g__tblr_tracing_table_bool +\bool_new:N \g__tblr_tracing_option_bool +\bool_new:N \g__tblr_tracing_theme_bool +\bool_new:N \g__tblr_tracing_outer_bool +\bool_new:N \g__tblr_tracing_inner_bool \bool_new:N \g__tblr_tracing_column_bool \bool_new:N \g__tblr_tracing_row_bool \bool_new:N \g__tblr_tracing_cell_bool @@ -4384,6 +6270,10 @@ \bool_new:N \g__tblr_tracing_target_bool \bool_new:N \g__tblr_tracing_cellspan_bool \bool_new:N \g__tblr_tracing_intarray_bool +\bool_new:N \g__tblr_tracing_page_bool +\bool_new:N \g__tblr_tracing_step_bool + +\bool_gset_true:N \g__tblr_tracing_step_bool \keys_define:nn { tblr-set-tracing } { @@ -4391,8 +6281,14 @@ -text .code:n = \bool_gset_false:N \g__tblr_tracing_text_bool, +command .code:n = \bool_gset_true:N \g__tblr_tracing_command_bool, -command .code:n = \bool_gset_false:N \g__tblr_tracing_command_bool, - +table .code:n = \bool_gset_true:N \g__tblr_tracing_table_bool, - -table .code:n = \bool_gset_false:N \g__tblr_tracing_table_bool, + +option .code:n = \bool_gset_true:N \g__tblr_tracing_option_bool, + -option .code:n = \bool_gset_false:N \g__tblr_tracing_option_bool, + +theme .code:n = \bool_gset_true:N \g__tblr_tracing_theme_bool, + -theme .code:n = \bool_gset_false:N \g__tblr_tracing_theme_bool, + +outer .code:n = \bool_gset_true:N \g__tblr_tracing_outer_bool, + -outer .code:n = \bool_gset_false:N \g__tblr_tracing_outer_bool, + +inner .code:n = \bool_gset_true:N \g__tblr_tracing_inner_bool, + -inner .code:n = \bool_gset_false:N \g__tblr_tracing_inner_bool, +column .code:n = \bool_gset_true:N \g__tblr_tracing_column_bool, -column .code:n = \bool_gset_false:N \g__tblr_tracing_column_bool, +row .code:n = \bool_gset_true:N \g__tblr_tracing_row_bool, @@ -4413,6 +6309,10 @@ -cellspan .code:n = \bool_gset_false:N \g__tblr_tracing_cellspan_bool, +intarray .code:n = \bool_gset_true:N \g__tblr_tracing_intarray_bool, -intarray .code:n = \bool_gset_false:N \g__tblr_tracing_intarray_bool, + +page .code:n = \bool_gset_true:N \g__tblr_tracing_page_bool, + -page .code:n = \bool_gset_false:N \g__tblr_tracing_page_bool, + +step .code:n = \bool_gset_true:N \g__tblr_tracing_step_bool, + -step .code:n = \bool_gset_false:N \g__tblr_tracing_step_bool, all .code:n = \__tblr_enable_all_tracings:, none .code:n = \__tblr_disable_all_tracings:, } @@ -4421,7 +6321,10 @@ { \bool_gset_true:N \g__tblr_tracing_text_bool \bool_gset_true:N \g__tblr_tracing_command_bool - \bool_gset_true:N \g__tblr_tracing_table_bool + \bool_gset_true:N \g__tblr_tracing_option_bool + \bool_gset_true:N \g__tblr_tracing_theme_bool + \bool_gset_true:N \g__tblr_tracing_outer_bool + \bool_gset_true:N \g__tblr_tracing_inner_bool \bool_gset_true:N \g__tblr_tracing_column_bool \bool_gset_true:N \g__tblr_tracing_row_bool \bool_gset_true:N \g__tblr_tracing_cell_bool @@ -4432,13 +6335,18 @@ \bool_gset_true:N \g__tblr_tracing_target_bool \bool_gset_true:N \g__tblr_tracing_cellspan_bool \bool_gset_true:N \g__tblr_tracing_intarray_bool + \bool_gset_true:N \g__tblr_tracing_page_bool + \bool_gset_true:N \g__tblr_tracing_step_bool } \cs_new_protected_nopar:Npn \__tblr_disable_all_tracings: { \bool_gset_false:N \g__tblr_tracing_text_bool \bool_gset_false:N \g__tblr_tracing_command_bool - \bool_gset_false:N \g__tblr_tracing_table_bool + \bool_gset_false:N \g__tblr_tracing_option_bool + \bool_gset_false:N \g__tblr_tracing_theme_bool + \bool_gset_false:N \g__tblr_tracing_outer_bool + \bool_gset_false:N \g__tblr_tracing_inner_bool \bool_gset_false:N \g__tblr_tracing_column_bool \bool_gset_false:N \g__tblr_tracing_row_bool \bool_gset_false:N \g__tblr_tracing_cell_bool @@ -4449,6 +6357,8 @@ \bool_gset_false:N \g__tblr_tracing_target_bool \bool_gset_false:N \g__tblr_tracing_cellspan_bool \bool_gset_false:N \g__tblr_tracing_intarray_bool + \bool_gset_false:N \g__tblr_tracing_page_bool + \bool_gset_false:N \g__tblr_tracing_step_bool } \NewDocumentCommand \LogTabularrayTracing { m } @@ -4459,6 +6369,7 @@ \keys_define:nn { tblr-log-tracing } { + step .code:n = \__tblr_log_tracing_step:n {#1}, unknown .code:n = \__tblr_log_tracing:N \l_keys_key_str } @@ -4470,7 +6381,7 @@ \cs_new_protected:Npn \__tblr_log_tracing_text: { - \__tblr_text_log:n { text } + \__tblr_spec_log:n { text } } \cs_new_protected:Npn \__tblr_log_tracing_command: @@ -4478,9 +6389,26 @@ \__tblr_prop_log:n { command } } -\cs_new_protected:Npn \__tblr_log_tracing_table: +\cs_new_protected:Npn \__tblr_log_tracing_option: + { + \__tblr_prop_log:n { note } + \__tblr_prop_log:n { remark } + \__tblr_prop_log:n { more } + } + +\cs_new_protected:Npn \__tblr_log_tracing_theme: + { + \__tblr_style_log: + } + +\cs_new_protected:Npn \__tblr_log_tracing_outer: + { + \__tblr_spec_log:n { outer } + } + +\cs_new_protected:Npn \__tblr_log_tracing_inner: { - \__tblr_prop_log:n { table } + \__tblr_prop_log:n { inner } } \cs_new_protected:Npn \__tblr_log_tracing_column: @@ -4500,12 +6428,12 @@ \cs_new_protected:Npn \__tblr_log_tracing_vline: { - \__tblr_text_log:n { vline } + \__tblr_spec_log:n { vline } } \cs_new_protected:Npn \__tblr_log_tracing_hline: { - \__tblr_text_log:n { hline } + \__tblr_spec_log:n { hline } } \cs_new_protected:Npn \__tblr_log_tracing_colspec: @@ -4537,9 +6465,279 @@ \prop_log:N \l__tblr_row_span_to_row_prop } +\cs_new_protected:Npn \__tblr_log_tracing_page: + { + \dim_log:N \pagegoal + \dim_log:N \pagetotal + } + +\cs_new_protected:Npn \__tblr_log_tracing_step:n #1 + { + \bool_if:NT \g__tblr_tracing_step_bool { \tl_log:x {Step :~ #1} } + } + \cs_new_protected:Npn \__tblr_do_if_tracing:nn #1 #2 { \bool_if:cT { g__tblr_tracing_ #1 _bool } {#2} } -\ExplSyntaxOff +%%% -------------------------------------------------------- +%% \section{Tabularray Libraries} +%%% -------------------------------------------------------- + +%% \NewTblrLibrary and \UseTblrLibrary commands + +\NewDocumentCommand \NewTblrLibrary { m m } + { + \cs_new_protected:cpn { __tblr_use_lib_ #1: } {#2} + } + +\NewDocumentCommand \UseTblrLibrary { m } + { + \clist_map_inline:nn {#1} { \use:c { __tblr_use_lib_ ##1: } } + } + +%% Library amsmath and environments +array, +matrix, +cases, ... + +\NewTblrLibrary { amsmath } + { + \RequirePackage { amsmath, environ } + \NewTblrEnviron { +array } + \SetTblrInner[+array]{colsep = 5pt} + \NewEnviron { +matrix } [1] [] { + \begin{+array}[expand = \BODY]{ + column{1} = {leftsep = 0pt}, column{Z} = {rightsep = 0pt}, + cells = {c}, ##1 + } + \BODY + \end{+array} + } + \NewEnviron { +bmatrix } [1] [] { + \left[\begin{+array}[expand = \BODY]{ + column{1} = {leftsep = 0pt}, column{Z} = {rightsep = 0pt}, + cells = {c}, ##1 + } + \BODY + \end{+array}\right] + \ignorespacesafterend + } + \NewEnviron { +Bmatrix } [1] [] { + \left\lbrace\begin{+array}[expand = \BODY]{ + column{1} = {leftsep = 0pt}, column{Z} = {rightsep = 0pt}, + cells = {c}, ##1 + } + \BODY + \end{+array}\right\rbrace + } + \NewEnviron { +pmatrix } [1] [] { + \left(\begin{+array}[expand = \BODY]{ + column{1} = {leftsep = 0pt}, column{Z} = {rightsep = 0pt}, + cells = {c}, ##1 + } + \BODY + \end{+array}\right) + } + \NewEnviron { +vmatrix } [1] [] { + \left\lvert\begin{+array}[expand = \BODY]{ + column{1} = {leftsep = 0pt}, column{Z} = {rightsep = 0pt}, + cells = {c}, ##1 + } + \BODY + \end{+array}\right\rvert + } + \NewEnviron { +Vmatrix } [1] [] { + \left\lVert\begin{+array}[expand = \BODY]{ + column{1} = {leftsep = 0pt}, column{Z} = {rightsep = 0pt}, + cells = {c}, ##1 + } + \BODY + \end{+array}\right\rVert + } + \NewEnviron { +cases } [1] [] { + \left\lbrace\begin{+array}[expand = \BODY]{ + column{1} = {leftsep = 0pt}, column{Z} = {rightsep = 0pt}, + colspec = {ll}, stretch = 1.2, ##1 + } + \BODY + \end{+array}\right. + } + } + +%% Library booktabs and commands \toprule, \midrule, \bottomrule + +\NewTblrLibrary { booktabs } + { + % We only use dimensions \aboverulesep and \belowrulesep in booktabs package + \RequirePackage { booktabs } + \newcommand \tblr@booktabs@hline [1] [] { \hline [##1] } + \newcommand \tblr@booktabs@oldhline [1] [] { + \hline [abovespace = \aboverulesep, belowspace = \belowrulesep, ##1] + } + \newcommand \tblr@booktabs@cline [2] [] { \cline [##1] {##2} } + \newcommand \tblr@booktabs@oldcline [2] [] { + \cline [abovespace = \aboverulesep, belowspace = \belowrulesep, ##1] {##2} + } + \newcommand \tblr@booktabs@cline@more [2] [] { \SetHline [+] {##2} {##1} } + \newcommand \tblr@booktabs@oldcline@more [2] [] { + \SetHline [+] {##2} { + abovespace = \aboverulesep, belowspace = \belowrulesep, ##1 + } + } + \NewTableCommand \toprule [1] [] { + \tblr@booktabs@hline [wd=\heavyrulewidth, ##1] + } + \NewTableCommand \midrule [1] [] { + \tblr@booktabs@hline [wd=\lightrulewidth, ##1] + } + \NewTableCommand \bottomrule [1] [] { + \tblr@booktabs@hline [wd=\heavyrulewidth, ##1] + } + \NewTableCommand \cmidrule [2] [] { + \tblr@booktabs@cline [wd=\cmidrulewidth, endpos, ##1] {##2} + } + \NewTableCommand \cmidrulemore [2] [] { + \tblr@booktabs@cline@more [wd=\cmidrulewidth, endpos, ##1] {##2} + } + \newcommand \tblr@booktabs@change@more [1] { \cmidrulemore } + \NewTableCommand \morecmidrules { + \peek_meaning:NTF \cmidrule { \tblr@booktabs@change@more } { \relax } + } + \NewTblrEnviron { booktabs } + \SetTblrInner [ booktabs ] { rowsep = 0pt } + \RequirePackage { etoolbox } + \AtBeginEnvironment { booktabs } + { + \let \tblr@booktabs@hline = \tblr@booktabs@oldhline + \let \tblr@booktabs@cline = \tblr@booktabs@oldcline + \let \tblr@booktabs@cline@more = \tblr@booktabs@oldcline@more + } + \NewTableCommand \specialrule [3] + { \hline [##1, abovespace = ##2, belowspace = ##3] } + \NewTableCommand \addrowspace [1] [\defaultaddspace] + { \SetVspace { abovespace+ = (##1) / 2, belowspace+ = (##1) / 2 } } + \NewTableCommand \addlinespace [1] [\defaultaddspace] + { \SetVspace { abovespace+ = (##1) / 2, belowspace+ = (##1) / 2 } } + } + +%% Library counter for resetting all counters + +\tl_new:N \__tblr_saved_trial_counters_tl +\tl_new:N \__tblr_saved_cell_counters_tl + +\cs_new_protected:Npn \__tblr_save_counters:n #1 { } +\cs_new_protected:Npn \__tblr_restore_counters:n #1 { } + +%% We use code from tabularx package for resetting all LaTeX counters, +%% where internal macro \cl@@ckpt looks like the following: +%% \@elt{page} \@elt{equation} \@elt{enumi} \@elt{enumii} \@elt{enumiii} ... + +\NewTblrLibrary { counter } + { + \cs_set_protected:Npn \__tblr_save_counters:n ##1 + { + \def \@elt ####1 { \global\value{####1} = \the\value{####1} \relax } + \tl_set:cx { __tblr_saved_ ##1 _counters_tl } { \cl@@ckpt } + \let \@elt = \relax + } + \cs_set_protected:Npn \__tblr_restore_counters:n ##1 + { + \tl_use:c { __tblr_saved_ ##1 _counters_tl } + } + } + +%% Library diagbox and command \diagbox + +\NewTblrLibrary { diagbox } + { + \RequirePackage{ diagbox } + \cs_set_eq:NN \__tblr_lib_saved_diagbox:w \diagbox + \NewContentCommand \diagbox [3] [] + { + \__tblr_lib_diagbox_fix:n + { + \__tblr_lib_saved_diagbox:w + [ leftsep=\leftsep, rightsep=\rightsep, ##1 ] + { \__tblr_lib_diagbox_math_or_text:n {##2} } + { \__tblr_lib_diagbox_math_or_text:n {##3} } + } + } + \NewContentCommand \diagboxthree [4] [] + { + \__tblr_lib_diagbox_fix:n + { + \__tblr_lib_saved_diagbox:w + [ leftsep=\leftsep, rightsep=\rightsep, ##1 ] + { \__tblr_lib_diagbox_math_or_text:n {##2} } + { \__tblr_lib_diagbox_math_or_text:n {##3} } + { \__tblr_lib_diagbox_math_or_text:n {##4} } + } + } + } + +\cs_new_protected:Npn \__tblr_lib_diagbox_math_or_text:n #1 + { + \bool_if:NTF \l__tblr_cell_math_mode_bool {$#1$} {#1} + } + +\box_new:N \l__tblr_diag_box + +\cs_new_protected:Npn \__tblr_lib_diagbox_fix:n #1 + { + \hbox_set:Nn \l__tblr_diag_box {#1} + \box_set_ht:Nn \l__tblr_diag_box { \box_ht:N \l__tblr_diag_box - \abovesep } + \box_set_dp:Nn \l__tblr_diag_box { \box_dp:N \l__tblr_diag_box - \belowsep } + \box_use:N \l__tblr_diag_box + } + +%% Library siunitx and S columns + +\NewTblrLibrary { siunitx } + { + \RequirePackage { siunitx } + \NewColumnType { S } [1] [] { Q[si = {##1}, c] } + \NewColumnType { s } [1] [] { Q[si = {##1}, c, cmd = \TblrUnit] } + \__tblr_data_new_key:nnn { cell } { si } { str } + \keys_define:nn { tblr-column } + { + si .code:n = \__tblr_siunitx_setcolumn:n {##1} + } + \cs_new_protected:Npn \__tblr_siunitx_setcolumn:n ##1 + { + \__tblr_column_gput_cell:nn { si } {##1} + \__tblr_column_gput_cell:nn { cmd } { \TblrNum } + } + \NewDocumentCommand \TblrNum { m } + { + \__tblr_siunitx_process:Nn \tablenum {##1} + } + \NewDocumentCommand \TblrUnit { m } + { + \__tblr_siunitx_process:Nn \si {##1} + } + \cs_new_protected:Npn \__tblr_siunitx_process:Nn ##1 ##2 + { + \tl_if_head_is_group:nTF {##2} + { ##2 } + { + \group_begin: + \tl_set:Nx \l_tmpa_tl + { + \__tblr_data_item:neen { cell } + { \int_use:N \c@rownum } { \int_use:N \c@colnum } { si } + } + \exp_args:NV \sisetup \l_tmpa_tl + ##1 {##2} + \group_end: + } + } + } + +%% Library varwidth and measure option + +\NewTblrLibrary { varwidth } + { + \RequirePackage { varwidth } + \clist_gput_left:Nn \g__tblr_table_known_keys_clist { measure } + \keys_define:nn { tblr } { measure .tl_set:N = \l__tblr_inner_spec_measure_tl } + } + diff --git a/Master/texmf-dist/tex/latex/tabularray/tabularray.sty b/Master/texmf-dist/tex/latex/tabularray/tabularray.sty index f5ad547d716..5ec77339f3b 100644 --- a/Master/texmf-dist/tex/latex/tabularray/tabularray.sty +++ b/Master/texmf-dist/tex/latex/tabularray/tabularray.sty @@ -1,49 +1,65 @@ %%% % -*- coding: utf-8 -*- %%% ---------------------------------------------------------------------------- %%% Tabularray: Typeset tabulars and arrays with LaTeX3 -%%% Author : Jianrui Lyu +%%% Copyright : 2021-2022 (c) Jianrui Lyu %%% Repository: https://github.com/lvjr/tabularray %%% License : The LaTeX Project Public License 1.3 %%% ---------------------------------------------------------------------------- %%% -------------------------------------------------------- -%% \section{Scratch Variables and Function Variants} +%%> \section{Scratch Variables and Function Variants} %%% -------------------------------------------------------- -\NeedsTeXFormat{LaTeX2e} +%% \DeclareRelease and \DeclareCurrentRelease are added in LaTeX 2018-04-01 +\NeedsTeXFormat{LaTeX2e}[2018-04-01] +\DeclareRelease{v2021}{}{tabularray-2021.sty} +\DeclareCurrentRelease{}{2022-01-01} + \RequirePackage{expl3} -\ProvidesExplPackage{tabularray}{2021-12-01}{2021Q} +\ProvidesExplPackage{tabularray}{2022-03-01}{2022A} {Typeset tabulars and arrays with LaTeX3} -\RequirePackage{xparse} - -\AtBeginDocument{\@ifpackageloaded{xcolor}{\RequirePackage{ninecolors}}{}} - -%% Backport \tl_if_eq:NnTF for old texlive 2020 -\cs_if_exist:NF \tl_if_eq:NnTF +%% \IfFormatAtLeastTF, xparse and lthooks are added in LaTeX 2020-10-01 +%% Note that \@ifl@t@r or \@ifpackagelater means 'this date or later' +\msg_new:nnn { tabularray } { latex-too-old } { - \tl_new:N \l__tblr_backport_b_tl - \prg_new_protected_conditional:Npnn \tl_if_eq:Nn #1 #2 { T, F, TF } - { - \group_begin: - \tl_set:Nn \l__tblr_backport_b_tl {#2} - \exp_after:wN - \group_end: - \if_meaning:w #1 \l__tblr_backport_b_tl - \prg_return_true: - \else: - \prg_return_false: - \fi: - } - \prg_generate_conditional_variant:Nnn \tl_if_eq:Nn { c } { TF, T, F } + Your ~ LaTeX ~ release ~ is ~ too ~ old. \\ + Please ~ update ~ to ~ 2020-10-01 ~ first. + } +\@ifl@t@r\fmtversion{2020-10-01}{}{ + %% Support TeX Live 2020 on Overleaf + \msg_warning:nn { tabularray } { latex-too-old } + \usepackage{xparse} +} + +\AtBeginDocument{ + \@ifpackageloaded{xcolor}{\RequirePackage{ninecolors}}{} + \@ifpackageloaded{hyperref}{ + \newenvironment{tblrNoHyper}{\NoHyper}{\endNoHyper} + }{ + \newenvironment{tblrNoHyper}{}{} } +} -%% Compatible with texlive 2020 -\cs_if_exist:NF \seq_map_indexed_function:NN +\NewDocumentCommand \TblrParboxRestore { } { \@parboxrestore } + +\NewDocumentCommand \TblrAlignBoth { } { - \cs_set_eq:NN \seq_map_indexed_function:NN \seq_indexed_map_function:NN + \let \\ = \@normalcr + \leftskip = \z@skip + \@rightskip = \z@skip + \rightskip = \@rightskip + \parfillskip = \@flushglue } +\NewDocumentCommand \TblrAlignLeft { } { \raggedright } + +\NewDocumentCommand \TblrAlignCenter { } { \centering } + +\NewDocumentCommand \TblrAlignRight { } { \raggedleft } + +\cs_set_eq:NN \TblrNewPage \newpage + \cs_generate_variant:Nn \msg_error:nnnn { nnVn } \cs_generate_variant:Nn \prop_item:Nn { Ne, NV } \cs_generate_variant:Nn \prop_put:Nnn { Nxn, Nxx, NxV } @@ -55,6 +71,7 @@ \cs_generate_variant:Nn \tl_put_left:Nn { Nv } \prg_generate_conditional_variant:Nnn \clist_if_in:Nn { Nx } { TF } \prg_generate_conditional_variant:Nnn \prop_if_in:Nn { c } { T } +\prg_generate_conditional_variant:Nnn \regex_match:Nn { NV } { TF } \prg_generate_conditional_variant:Nnn \str_if_eq:nn { xn } { TF } \prg_generate_conditional_variant:Nnn \tl_if_eq:nn { en } { T, TF } \prg_generate_conditional_variant:Nnn \tl_if_head_eq_catcode:nN { VN } { TF } @@ -102,9 +119,10 @@ \int_new:N \g__tblr_table_count_int %% Some commands for horizontal alignment -\cs_new_eq:NN \__tblr_halign_command_l: \raggedright -\cs_new_eq:NN \__tblr_halign_command_c: \centering -\cs_new_eq:NN \__tblr_halign_command_r: \raggedleft +\cs_new_eq:NN \__tblr_halign_command_j: \TblrAlignBoth +\cs_new_eq:NN \__tblr_halign_command_l: \TblrAlignLeft +\cs_new_eq:NN \__tblr_halign_command_c: \TblrAlignCenter +\cs_new_eq:NN \__tblr_halign_command_r: \TblrAlignRight %% Some counters for row and column numbering. %% We may need to restore all LaTeX counters in measuring and building cells, @@ -127,7 +145,7 @@ \dim_new:N \rightsep %%% -------------------------------------------------------- -%% \section{Data Structures Based on Property Lists} +%%> \section{Data Structures Based on Property Lists} %%% -------------------------------------------------------- \int_new:N \g_tblr_level_int % store table nesting level @@ -238,7 +256,7 @@ \cs_generate_variant:Nn \__tblr_gadd_dimen_value:Nnn { cnn } %%% -------------------------------------------------------- -%% \section{Data Structures Based on Token Lists} +%%> \section{Data Structures Based on Token Lists} %%% -------------------------------------------------------- \cs_new_protected:Npn \__tblr_clear_spec_lists: @@ -318,7 +336,7 @@ } %%% -------------------------------------------------------- -%% \section{Data Structures Based on Integer Arrays} +%%> \section{Data Structures Based on Integer Arrays} %%% -------------------------------------------------------- \msg_new:nnn { tabularray } { intarray-beyond-bound } @@ -362,7 +380,6 @@ \__tblr_data_new_key:nnn { row } { @row-foot } { dim } \__tblr_data_new_key:nnn { row } { @row-upper } { dim } \__tblr_data_new_key:nnn { row } { @row-lower } { dim } -\__tblr_data_new_key:nnn { row } { break } { int } \int_new:N \g__tblr_data_column_key_count_int \__tblr_data_new_key:nnn { column } { width } { dim } @@ -763,7 +780,7 @@ } %%% -------------------------------------------------------- -%% \section{Child Selectors} +%%> \section{Child Selectors} %%% -------------------------------------------------------- \clist_new:N \g_tblr_used_child_selectors_clist @@ -810,15 +827,42 @@ \clist_new:N \l_tblr_childs_clist \tl_new:N \l_tblr_childs_total_tl -\NewChildSelector { odd } +\NewChildSelector { odd } [1] [] { - \int_step_inline:nnnn {1} {2} { \l_tblr_childs_total_tl } - { \clist_put_right:Nn \l_tblr_childs_clist {##1} } + \tl_if_blank:nTF {#1} + { + \int_step_inline:nnnn {1} {2} { \l_tblr_childs_total_tl } + { \clist_put_right:Nn \l_tblr_childs_clist {##1} } + } + { \__tblr_child_selector_odd_or_even:nn { odd } {#1} } } -\NewChildSelector { even } +\NewChildSelector { even } [1] [] { - \int_step_inline:nnnn {2} {2} { \l_tblr_childs_total_tl } + \tl_if_blank:nTF {#1} + { + \int_step_inline:nnnn {2} {2} { \l_tblr_childs_total_tl } + { \clist_put_right:Nn \l_tblr_childs_clist {##1} } + } + { \__tblr_child_selector_odd_or_even:nn { even } {#1} } + } + +\tl_new:N \l__tblr_child_from_tl +\tl_new:N \l__tblr_child_to_tl + +%% #1: odd or even; #2: selector option +\cs_new_protected:Npn \__tblr_child_selector_odd_or_even:nn #1 #2 + { + \seq_set_split:Nnn \l_tmpa_seq {-} { #2 - Z } + \tl_set:Nx \l__tblr_child_from_tl { \seq_item:Nn \l_tmpa_seq {1} } + \tl_set:Nx \l__tblr_child_to_tl { \seq_item:Nn \l_tmpa_seq {2} } + \tl_use:c { int_if_ #1 :nF } { \l__tblr_child_from_tl } + { + \tl_set:Nx \l__tblr_child_from_tl + { \int_eval:n { \l__tblr_child_from_tl + 1 } } + } + \__tblr_child_name_to_index:VN \l__tblr_child_to_tl \l__tblr_child_to_tl + \int_step_inline:nnnn { \l__tblr_child_from_tl } {2} { \l__tblr_child_to_tl } { \clist_put_right:Nn \l_tblr_childs_clist {##1} } } @@ -842,7 +886,7 @@ __tblr_child_selector_ \seq_item:Nn \l__tblr_childs_regex_seq {2} :w \cs_end: } - \exp_args:Nx \l__tblr_childs_selector_tl + \exp_last_unbraced:Nx \l__tblr_childs_selector_tl { \seq_item:Nn \l__tblr_childs_regex_seq{3} } } { @@ -865,9 +909,6 @@ } } -\tl_new:N \l__tblr_child_from_tl -\tl_new:N \l__tblr_child_to_tl - \cs_new_protected_nopar:Npn \__tblr_get_childs_normal_aux:w #1 - #2 \scan_stop { \__tblr_child_name_to_index:nN {#1} \l__tblr_child_from_tl @@ -888,9 +929,10 @@ } { \tl_set:Nx #2 { #1 } } } +\cs_generate_variant:Nn \__tblr_child_name_to_index:nN { VN } %%% -------------------------------------------------------- -%% \section{New Table Commands} +%%> \section{New Table Commands} %%% -------------------------------------------------------- %% We need some commands to modify table/row/column/cell specifications. @@ -985,7 +1027,7 @@ { \clist_if_in:NnTF \g__tblr_content_commands_clist { #1 } { - \msg_warning:nnn { tabularray } { defined-content-command } { #1 } + \msg_error:nnn { tabularray } { defined-content-command } { #1 } \clist_log:N \g__tblr_content_commands_clist } { @@ -1003,7 +1045,7 @@ } %%% -------------------------------------------------------- -%% \section{New Dash Styles} +%%> \section{New Dash Styles} %%% -------------------------------------------------------- %% \NewDashStyle commands @@ -1073,7 +1115,7 @@ \NewDashStyle {dotted} {on ~ 0.4pt ~ off ~ 1pt} %%% -------------------------------------------------------- -%% \section{Set Hlines and Vlines} +%%> \section{Set Hlines and Vlines} %%% -------------------------------------------------------- \tl_set:Nn \@tblr@dash { dash } @@ -1128,10 +1170,6 @@ \NewTableCommand \hline [1] [] { \SetHline [+] {-} {#1} } -%% Some keys can be set by any hline, such as abovespace and belowspace keys. -%% Using special hline of index 0, you can set these keys without adding any hlines. -\NewTableCommand \SetVspace [1] { \SetHline [0] {-} {#1} } - %% #1: the index of the hline (may be + or =) %% #2: which columns of the hline, separate by commas %% #3: key=value pairs @@ -1145,19 +1183,13 @@ \cs_new_protected:Npn \tblr_set_hline:nnn #1 #2 #3 { \group_begin: - %% We can not use \int_compare:nNnTF here since #1 may be + or = . - %% Also we treat hline of index 0 specially, not adding hline count. - \tl_if_eq:nnTF {#1} {0} - { \keys_set:nn { tblr-hline } {#3} } + \keys_set_groups:nnn { tblr-hline } { text } {#3} + \tl_if_eq:NnF \l__tblr_hline_dash_tl { \exp_not:N \@tblr@text } { - \keys_set_groups:nnn { tblr-hline } { text } {#3} - \tl_if_eq:NnF \l__tblr_hline_dash_tl { \exp_not:N \@tblr@text } - { - \__tblr_set_hline_num:n {#1} - \tl_clear:N \l__tblr_hline_dash_tl - \keys_set:nn { tblr-hline } { dash = solid, #3 } - \__tblr_set_hline_cmd:n {#2} - } + \__tblr_set_hline_num:n {#1} + \tl_clear:N \l__tblr_hline_dash_tl + \keys_set:nn { tblr-hline } { dash = solid, #3 } + \__tblr_set_hline_cmd:n {#2} } \group_end: } @@ -1233,7 +1265,6 @@ text .groups:n = { text }, wd .code:n = \tl_set:Nn \l__tblr_hline_wd_tl { \dim_eval:n {#1} }, fg .code:n = \tl_set:Nn \l__tblr_hline_fg_tl {#1}, - baseline .code:n = \__tblr_hline_set_baseline:n {#1}, leftpos .code:n = \tl_set:Nx \l__tblr_hline_leftpos_tl {#1}, rightpos .code:n = \tl_set:Nx \l__tblr_hline_rightpos_tl {#1}, l .meta:n = { leftpos = #1 }, @@ -1243,12 +1274,6 @@ lr .meta:n = { leftpos = #1, rightpos = #1 }, lr .default:n = { -0.8 }, endpos .bool_set:N = \l__tblr_hline_endpos_bool, - abovespace .code:n = \__tblr_row_gput_above:ne { belowsep } { \dim_eval:n {#1} }, - belowspace .code:n = \__tblr_row_gput:ne { abovesep } { \dim_eval:n {#1} }, - abovespace+ .code:n = \__tblr_row_gadd_dimen_above:ne - { belowsep } { \dim_eval:n {#1} }, - belowspace+ .code:n = \__tblr_row_gadd_dimen:ne - { abovesep } { \dim_eval:n {#1} }, unknown .code:n = \__tblr_hline_unknown_key:V \l_keys_key_str, } @@ -1325,22 +1350,20 @@ { [\int_use:N \c@rownum][#1](\l__tblr_hline_num_tl) / #2 } { #3 } } -\NewTableCommand \firsthline [1] [] { \SetHline [+] {-} { #1, baseline=below } } -\NewTableCommand \lasthline [1] [] { \SetHline [+] {-} { #1, baseline=above } } +\msg_new:nnn { tabularray } { obsolete-firsthline } + { \firsthline ~ is ~ obsolete; ~ use ~ 'baseline=T' ~ instead. } -\cs_new_protected:Npn \__tblr_hline_set_baseline:n #1 +\msg_new:nnn { tabularray } { obsolete-lasthline } + { \lasthline ~ is ~ obsolete; ~ use ~ 'baseline=B' ~ instead. } + +\NewTableCommand \firsthline [1] [] { - \tl_if_eq:nnTF {#1} {above} - { - \__tblr_prop_gput:nnx { inner } - { baseline } { \int_eval:n { \c@rownum - 1 } } - } - { - \tl_if_eq:nnT {#1} {below} - { - \__tblr_prop_gput:nnx { inner } { baseline } { \int_use:N \c@rownum } - } - } + \msg_error:nn { tabularray } { obsolete-firsthline } + } + +\NewTableCommand \lasthline [1] [] + { + \msg_error:nn { tabularray } { obsolete-lasthline } } %% \SetVlines command for setting every vline in the table @@ -1540,7 +1563,107 @@ } %%% -------------------------------------------------------- -%% \section{Set Cells} +%%> \section{Set Hborders and Vborders} +%%% -------------------------------------------------------- + +%% Hborder holds keys not related to a specified hline +\NewTableCommand \hborder [1] { \tblr_set_hborder:n {#1} } + +\cs_new_protected:Npn \tblr_set_hborder:n #1 + { + \keys_set:nn { tblr-hborder } {#1} + } + +\cs_new_protected:Npn \tblr_set_hborder:nn #1 #2 + { + \group_begin: + \__tblr_get_childs:nx {#1} { \int_eval:n { \c@rowcount + 1 } } + \clist_map_inline:Nn \l_tblr_childs_clist + { + \int_set:Nn \c@rownum {##1} + \tblr_set_hborder:n {#2} + } + \group_end: + } + +%% This function is called when parsing table specifications +%% Note that #1 always includes an outer pair of braces +\cs_new_protected:Npn \__tblr_set_hborder_aux:nn #1 #2 + { + \tblr_set_hborder:nn #1 {#2} + } +\cs_generate_variant:Nn \__tblr_set_hborder_aux:nn { Vn } + +\keys_define:nn { tblr-hborder } + { + abovespace .code:n = \__tblr_row_gput_above:ne + { belowsep } { \dim_eval:n {#1} }, + belowspace .code:n = \__tblr_row_gput:ne { abovesep } { \dim_eval:n {#1} }, + abovespace+ .code:n = \__tblr_row_gadd_dimen_above:ne + { belowsep } { \dim_eval:n {#1} }, + belowspace+ .code:n = \__tblr_row_gadd_dimen:ne + { abovesep } { \dim_eval:n {#1} }, + pagebreak .code:n = \__tblr_hborder_gput_pagebreak:n {#1}, + pagebreak .default:n = yes, + baseline .code:n = \__tblr_outer_gput_spec:ne + { baseline } { - \int_use:N \c@rownum }, + } + +\tl_const:Nn \c__tblr_pagebreak_yes_tl { 1 } +\tl_const:Nn \c__tblr_pagebreak_auto_tl { 0 } +\tl_const:Nn \c__tblr_pagebreak_no_tl { -1 } + +\cs_new_protected:Npn \__tblr_hborder_gput_pagebreak:n #1 + { + \tl_if_exist:cT { c__tblr_pagebreak_ #1 _tl } + { + \__tblr_spec_gput:nee { hline } + { [\int_use:N \c@rownum] / @pagebreak } + { \tl_use:c { c__tblr_pagebreak_ #1 _tl } } + } + } + +%% Vborder holds keys not related to a specified vline +\NewTableCommand \vborder [1] { \tblr_set_vborder:n {#1} } + +\cs_new_protected:Npn \tblr_set_vborder:n #1 + { + \keys_set:nn { tblr-vborder } {#1} + } + +\cs_new_protected:Npn \tblr_set_vborder:nn #1 #2 + { + \group_begin: + \__tblr_get_childs:nx {#1} { \int_eval:n { \c@colcount + 1 } } + \clist_map_inline:Nn \l_tblr_childs_clist + { + \int_set:Nn \c@colnum {##1} + \tblr_set_vborder:n {#2} + } + \group_end: + } + +%% This function is called when parsing table specifications +%% Note that #1 always includes an outer pair of braces +\cs_new_protected:Npn \__tblr_set_vborder_aux:nn #1 #2 + { + \tblr_set_vborder:nn #1 {#2} + } +\cs_generate_variant:Nn \__tblr_set_vborder_aux:nn { Vn } + +\keys_define:nn { tblr-vborder } + { + leftspace .code:n = \__tblr_column_gput_left:ne + { rightsep } { \dim_eval:n {#1} }, + rightspace .code:n = \__tblr_column_gput:ne { leftsep } { \dim_eval:n {#1} }, + leftspace+ .code:n = \__tblr_column_gadd_dimen_left:ne + { rightsep } { \dim_eval:n {#1} }, + rightspace+ .code:n = \__tblr_column_gadd_dimen:ne + { leftsep } { \dim_eval:n {#1} }, + } + +%%% -------------------------------------------------------- +%%> \section{Set Cells} %%% -------------------------------------------------------- %% \SetCells command for setting every cell in the table @@ -1767,7 +1890,7 @@ { 1 } } \int_step_variable:nnNn - { \c@rownum } { \int_eval:n { \c@rownum + #1 -1 } } \l__tblr_i_tl + { \c@rownum } { \int_eval:n { \c@rownum + #1 - 2 } } \l__tblr_i_tl { \__tblr_spec_gput:nee { vline } { [\l__tblr_i_tl][\int_use:N \c@colnum](\l__tblr_n_tl) / belowpos } {1} @@ -1777,59 +1900,26 @@ } \cs_generate_variant:Nn \__tblr_set_span_spec:nn { VV } -%% Legacy \multicolumn and \multirow commands -%% Both of them could be replaced with \SetCell command -%% Note that they don't have cell text as the last arguments +%% Obsolete \multicolumn and \multirow commands + +\msg_new:nnn { tabularray } { obsolete-multicolumn } + { \multicolumn ~ is ~ obsolete; ~ use ~ \SetCell ~ instead. } -%% If \multicolumn is followed by \multirow, -%% We need to call \tblr_set_cell together -%% in order to omit all hlines inside the span cell. -\tl_new:N \g__tblr_multicolumn_num_tl -\tl_new:N \g__tblr_multicolumn_spec_tl +\msg_new:nnn { tabularray } { obsolete-multirow } + { \multirow ~ is ~ obsolete; ~ use ~ \SetCell ~ instead. } -%% There maybe p{2em} inside #2 of \multicolumn command \NewTableCommand \multicolumn [2] { - \tl_gclear:N \g__tblr_multicolumn_num_tl - \tl_gclear:N \g__tblr_multicolumn_spec_tl - \tl_map_inline:nn {#2} - { - \bool_lazy_and:nnF - { \tl_if_single_token_p:n {##1} } - { \token_if_eq_charcode_p:NN ##1 | } - { \tl_put_right:Nn \g__tblr_multicolumn_spec_tl {,##1} } - } - \peek_meaning:NTF \multirow - { \tl_gset:Nn \g__tblr_multicolumn_num_tl {#1} } - { \tblr_set_cell:nV { c = #1 } \g__tblr_multicolumn_spec_tl } + \msg_error:nn { tabularray } { obsolete-multicolumn } } \NewTableCommand \multirow [3] [m] { - \tl_if_eq:nnTF {#1} {c} - { \tl_set:Nn \l_tmpa_tl {, m} } - { - \tl_if_eq:nnTF {#1} {t} - { \tl_set:Nn \l_tmpa_tl {, h} } - { \tl_if_eq:nnTF {#1} {b} - { \tl_set:Nn \l_tmpa_tl {, f} } - { \tl_set:Nn \l_tmpa_tl {, #1} } - } - } - \tl_if_eq:nnF {#3} {*} - { \tl_if_eq:nnF {#3} {=} { \tl_put_right:Nn \l_tmpa_tl {, wd=#3} } } - \tl_if_empty:NTF \g__tblr_multicolumn_num_tl - { \tblr_set_cell:nV { r = #2 } \l_tmpa_tl } - { - \tl_put_left:NV \l_tmpa_tl \g__tblr_multicolumn_spec_tl - \exp_args:Nx \tblr_set_cell:nV - { c = \g__tblr_multicolumn_num_tl, r = #2 } \l_tmpa_tl - \tl_gclear:N \g__tblr_multicolumn_num_tl - } + \msg_error:nn { tabularray } { obsolete-multirow } } %%% -------------------------------------------------------- -%% \section{Set Columns and Rows} +%%> \section{Set Columns and Rows} %%% -------------------------------------------------------- %% \SetColumns command for setting every column in the table @@ -1937,6 +2027,12 @@ } \cs_generate_variant:Nn \__tblr_column_gput:nn { ne } +\cs_new_protected:Npn \__tblr_column_gput_left:nn #1 #2 + { + \__tblr_data_gput:nenn { column } { \int_eval:n { \c@colnum - 1 } } {#1} {#2} + } +\cs_generate_variant:Nn \__tblr_column_gput_left:nn { ne } + \cs_new_protected:Npn \__tblr_column_gadd_dimen:nn #1 #2 { \__tblr_data_gadd_dimen_value:nenn { column } @@ -1944,6 +2040,13 @@ } \cs_generate_variant:Nn \__tblr_column_gadd_dimen:nn { ne } +\cs_new_protected:Npn \__tblr_column_gadd_dimen_left:nn #1 #2 + { + \__tblr_data_gadd_dimen_value:nenn { column } + { \int_eval:n { \c@colnum - 1 } } {#1} {#2} + } +\cs_generate_variant:Nn \__tblr_column_gadd_dimen_left:nn { ne } + %% #1: key; #2: value \cs_new_protected:Npn \__tblr_column_gput_cell:nn #1 #2 { @@ -2080,9 +2183,8 @@ abovesep+ .code:n = \__tblr_row_gadd_dimen:ne { abovesep } { \dim_eval:n {#1} }, belowsep+ .code:n = \__tblr_row_gadd_dimen:ne { belowsep } { \dim_eval:n {#1} }, rowsep+ .meta:n = { abovesep+ = #1, belowsep+ = #1}, - break .code:n = \__tblr_row_gput:nn { break } {#1}, - pagebreak .meta:n = { break = 1 }, - nopagebreak .meta:n = { break = -1 }, + baseline .code:n = \__tblr_outer_gput_spec:ne + { baseline } { \int_use:N \c@rownum }, unknown .code:n = \__tblr_row_unknown_key:V \l_keys_key_str, } @@ -2158,16 +2260,16 @@ \NewTableCommand \pagebreak { - \tblr_set_row:nn {} { break = 1 } + \hborder { pagebreak = yes } } \NewTableCommand \nopagebreak { - \tblr_set_row:nn {} { break = -1 } + \hborder { pagebreak = no } } %%% -------------------------------------------------------- -%% \section{Column Types and Row Types} +%%> \section{Column Types and Row Types} %%% -------------------------------------------------------- %% Some primitive column/row types @@ -2344,8 +2446,8 @@ \str_if_in:cnTF { g_tblr_used_ \g__tblr_column_or_row_tl _types_str } {#1} { \tl_if_eq:NnTF \g__tblr_column_or_row_tl { row } - { \msg_warning:nnnn { tabularray } { used-colrow-type } { Row } {#1} } - { \msg_warning:nnnn { tabularray } { used-colrow-type } { Column } {#1} } + { \msg_error:nnnn { tabularray } { used-colrow-type } { Row } {#1} } + { \msg_error:nnnn { tabularray } { used-colrow-type } { Column } {#1} } \str_log:c { g_tblr_used_ \g__tblr_column_or_row_tl _types_str } } { @@ -2457,13 +2559,13 @@ } %%% -------------------------------------------------------- -%% \section{Set Environments and New Environments} +%%> \section{Set Environments and New Environments} %%% -------------------------------------------------------- \tl_new:N \l__tblr_initial_tblr_outer_tl \tl_set:Nn \l__tblr_initial_tblr_outer_tl { - halign = c, valign = m, headsep = 6pt, footsep = 6pt, + halign = c, baseline = m, headsep = 6pt, footsep = 6pt, presep = 1.5\bigskipamount, postsep = 1.5\bigskipamount, } @@ -2485,13 +2587,13 @@ %% #1: env name \NewDocumentCommand \NewTblrEnviron { m } { - \tl_new:c { l__tblr_default_ #1 _outer_tl } - \tl_set_eq:cN { l__tblr_default_ #1 _outer_tl } \l__tblr_initial_tblr_outer_tl - \tl_new:c { l__tblr_default_ #1 _inner_tl } \NewDocumentEnvironment {#1} { O{c} m +b } { \__tblr_environ_code:nnnn {#1} {##1} {##2} {##3} } { } + \tl_new:c { l__tblr_default_ #1 _inner_tl } + \tl_new:c { l__tblr_default_ #1 _outer_tl } + \tl_set_eq:cN { l__tblr_default_ #1 _outer_tl } \l__tblr_initial_tblr_outer_tl \ignorespaces } @@ -2550,7 +2652,7 @@ } %%% -------------------------------------------------------- -%% \section{Split Table Contents} +%%> \section{Split Table Contents} %%% -------------------------------------------------------- %% Insert and remove braces for nesting environments inside cells @@ -2628,7 +2730,7 @@ { \tl_if_head_eq_meaning:nNTF {##1} * { - \tl_set:Nn \l__tblr_b_tl { \SetRow { break = -1 } } + \tl_set:Nn \l__tblr_b_tl { \hborder { pagebreak = no } } \tl_set:Nx \l__tblr_c_tl { \tl_tail:n {##1} } \tl_trim_spaces:N \l__tblr_c_tl %% Ignore spaces between * and [dimen] \tl_if_head_eq_meaning:VNT \l__tblr_c_tl [ @@ -2681,7 +2783,6 @@ \__tblr_extract_table_commands:N \l_tmpa_tl \__tblr_trim_par_space_tokens:N \l_tmpa_tl \__tblr_spec_gput:neV { text } { [#1][\int_use:N \c@colnum] } \l_tmpa_tl - \__tblr_add_multicolumn_empty_cell: } %% Decrease row count by 1 if the last row has only one empty cell text %% We need to do it here since the > or < column type may add text to cells @@ -2711,26 +2812,12 @@ \regex_replace_once:NnN \c__tblr_trim_right_space_par_regex {} #1 } -%% Add empty cells after the \multicolumn span cell -\cs_new_protected:Npn \__tblr_add_multicolumn_empty_cell: - { - \int_step_inline:nn { \l__multicolumn_cell_number_int - 1 } - { - \int_incr:N \c@colnum - \__tblr_spec_gput:nen { text } - { [\int_use:N \c@rownum][\int_use:N \c@colnum] } { } - } - } - %%% -------------------------------------------------------- -%% \section{Extract Table Commands from Cell Text} +%%> \section{Extract Table Commands from Cell Text} %%% -------------------------------------------------------- %% Extract table commands defined with \NewTableCommand from cell text -\clist_gset:Nn \g__tblr_table_commands_unbrace_next_clist {\multirow, \multicolumn} -\bool_new:N \l__tblr_table_command_unbrace_next_bool -\int_new:N \l__multicolumn_cell_number_int \tl_new:N \l__tblr_saved_table_commands_before_cell_text_tl \tl_new:N \l__tblr_saved_cell_text_after_table_commands_tl @@ -2738,7 +2825,6 @@ { \tl_clear:N \l__tblr_saved_table_commands_before_cell_text_tl \tl_clear:N \l__tblr_saved_cell_text_after_table_commands_tl - \int_set:Nn \l__multicolumn_cell_number_int {1} \exp_last_unbraced:NV \__tblr_extract_table_commands_next:n #1 \q_stop \tl_if_empty:NF \l__tblr_saved_table_commands_before_cell_text_tl { @@ -2755,14 +2841,7 @@ \tl_if_single_token:nTF {#1} { \clist_if_in:NnTF \g__tblr_table_commands_clist { #1 } - { - \clist_if_in:NnTF \g__tblr_table_commands_unbrace_next_clist { #1 } - { \bool_set_true:N \l__tblr_table_command_unbrace_next_bool } - { \bool_set_false:N \l__tblr_table_command_unbrace_next_bool } - \token_if_eq_meaning:NNTF #1 \multicolumn - { \__tblr_extract_multicolumn_command:Nn #1 } - { \__tblr_extract_one_table_command:N #1 } - } + { \__tblr_extract_one_table_command:N #1 } { \token_if_eq_meaning:NNF #1 \q_stop { \__tblr_save_real_cell_text:w #1 } @@ -2771,12 +2850,6 @@ { \__tblr_save_real_cell_text:w {#1} } } -\cs_new_protected:Npn \__tblr_extract_multicolumn_command:Nn #1 #2 - { - \int_set:Nn \l__multicolumn_cell_number_int {#2} - \__tblr_extract_one_table_command:N #1 {#2} - } - \cs_new_protected:Npn \__tblr_extract_one_table_command:N #1 { \int_set:Nn \l__tblr_a_int @@ -2811,15 +2884,9 @@ \int_decr:N \l__tblr_a_int \__tblr_extract_table_command_arg_m:n } - { - \bool_if:NTF \l__tblr_table_command_unbrace_next_bool - { \__tblr_last_unbraced:Nn \__tblr_extract_table_commands_next:n } - { \__tblr_extract_table_commands_next:n } - } + { \__tblr_extract_table_commands_next:n } } -\cs_new_protected:Npn \__tblr_last_unbraced:Nn #1 #2 { #1 #2 } - %% The outermost set of braces of cell text #1 will be removed \cs_new_protected:Npn \__tblr_save_real_cell_text:w #1 \q_stop { @@ -2827,7 +2894,7 @@ } %%% -------------------------------------------------------- -%% \section{Initialize Table Inner Specifications} +%%> \section{Initialize Table Inner Specifications} %%% -------------------------------------------------------- \prop_gset_from_keyval:Nn \g__tblr_initial_table_prop @@ -2858,7 +2925,7 @@ \prop_gset_from_keyval:Nn \g__tblr_initial_cells_prop { - halign = l, + halign = j, valign = t, width = -1pt, % cell width unset rowspan = 1, @@ -2937,10 +3004,10 @@ \clist_new:N \g__tblr_table_known_keys_clist \clist_gset:Nn \g__tblr_table_known_keys_clist { - colspec, rowspec, width, hspan, vspan, stretch, verb, - column, row, cell, vline, hline, columns, rows, cells, vlines, hlines, + colspec, rowspec, column, row, cell, hline, vline, hborder, vborder, width, + rowhead, rowfoot, columns, rows, cells, hlines, vlines, % hborders, vborders, leftsep, rightsep, colsep, abovesep, belowsep, rowsep, rulesep, - rowhead, rowfoot, + baseline, hspan, vspan, stretch, verb, } \keys_define:nn { tblr } @@ -2967,6 +3034,7 @@ rulesep .code:n = \__tblr_keys_gput:nn { rulesep } {#1}, rowhead .code:n = \__tblr_keys_gput:nn { rowhead } {#1}, rowfoot .code:n = \__tblr_keys_gput:nn { rowfoot } {#1}, + baseline .code:n = \__tblr_outer_gput_spec:nn { baseline } {#1}, unknown .code:n = \__tblr_table_special_key:Vn \l_keys_key_str {#1}, } @@ -3007,14 +3075,21 @@ \cs_generate_variant:Nn \__tblr_keys_gput:nn { nx } %%% -------------------------------------------------------- -%% \section{Initialize and Parse Table Outer Specifications} +%%> \section{Initialize and Parse Table Outer Specifications} %%% -------------------------------------------------------- +\msg_new:nnn { tabularray } { used-theme-name } + { theme ~ name ~ #1 ~ has ~ been ~ used! } + %% #1: theme names; #2: template and style commands \NewDocumentCommand \NewTblrTheme { m +m } { - \tl_set:cn { g__tblr_theme_ #1 _code_tl } {#2} - \ignorespaces + \tl_if_exist:cTF { g__tblr_theme_ #1 _code_tl } + { \msg_error:nnn { tabularray } { used-theme-name } { #1 } } + { + \tl_set:cn { g__tblr_theme_ #1 _code_tl } {#2} + \ignorespaces + } } \cs_new_protected:Npn \__tblr_use_theme:n #1 @@ -3038,13 +3113,17 @@ long .code:n = \__tblr_outer_gput_spec:nn { long } { true }, tall .code:n = \__tblr_outer_gput_spec:nn { tall } { true }, halign .code:n = \__tblr_outer_gput_spec:nn { halign } {#1}, - valign .code:n = \__tblr_outer_gput_spec:nn { valign } {#1}, + baseline .code:n = \__tblr_outer_gput_spec:nn { baseline } {#1}, l .meta:n = { halign = l }, c .meta:n = { halign = c }, r .meta:n = { halign = r }, - t .meta:n = { valign = t }, - m .meta:n = { valign = m }, - b .meta:n = { valign = b }, + t .meta:n = { baseline = t }, + T .meta:n = { baseline = T }, + m .meta:n = { baseline = m }, + M .meta:n = { baseline = M }, + b .meta:n = { baseline = b }, + B .meta:n = { baseline = B }, + valign .meta:n = { baseline = #1 }, % obsolete, will be removed some day expand .code:n = \__tblr_outer_gput_spec:nn { expand } {#1}, headsep .code:n = \__tblr_outer_gput_spec:nn { headsep } {#1}, footsep .code:n = \__tblr_outer_gput_spec:nn { footsep } {#1}, @@ -3061,6 +3140,7 @@ { \__tblr_spec_gput:nen { outer } {#1} {#2} } +\cs_generate_variant:Nn \__tblr_outer_gput_spec:nn { ne } \regex_const:Nn \c__tblr_option_key_name_regex { ^ [A-Za-z\-] + $ } @@ -3102,7 +3182,7 @@ \cs_generate_variant:Nn \__tblr_outer_gput_more:nn { Vn } %%% -------------------------------------------------------- -%% \section{Typeset and Calculate Sizes} +%%> \section{Typeset and Calculate Sizes} %%% -------------------------------------------------------- %% Calculate the width and height for every cell and border @@ -3125,12 +3205,47 @@ \cs_new_protected:Npn \__tblr_make_strut_box: { \tl_set:Nx \l__tblr_s_tl { \__tblr_prop_item:ne { inner } { stretch } } - \hbox_set:Nn \l__tblr_strut_ht_box - { \vrule height \l__tblr_s_tl \box_ht:N \strutbox width ~ 0pt } - \hbox_set:Nn \l__tblr_strut_dp_box - { \vrule depth \l__tblr_s_tl \box_dp:N \strutbox width ~ 0pt } + \fp_compare:nNnTF { \l__tblr_s_tl } > {0} + { + \hbox_set:Nn \l__tblr_strut_ht_box + { \vrule height \l__tblr_s_tl \box_ht:N \strutbox width ~ 0pt } + \hbox_set:Nn \l__tblr_strut_dp_box + { \vrule depth \l__tblr_s_tl \box_dp:N \strutbox width ~ 0pt } + \cs_set_eq:NN \__tblr_use_strut_ht_box: \__tblr_use_strut_ht_box_real: + \cs_set_eq:NN \__tblr_use_strut_dp_box: \__tblr_use_strut_dp_box_real: + } + { + \fp_compare:nNnTF { \l__tblr_s_tl } < {0} + { + \cs_set_eq:NN \__tblr_use_strut_ht_box: \__tblr_use_strut_ht_box_vmode: + } + { + \cs_set_eq:NN \__tblr_use_strut_ht_box: \__tblr_use_strut_ht_box_hmode: + } + \cs_set_eq:NN \__tblr_use_strut_dp_box: \__tblr_use_strut_dp_box_ignore: + } } +\cs_new_protected:Npn \__tblr_use_strut_ht_box_real: + { + \mode_leave_vertical: + \box_use:N \l__tblr_strut_ht_box + } +\cs_new_protected:Npn \__tblr_use_strut_ht_box_hmode: + { + \mode_leave_vertical: + } +\cs_new_protected:Npn \__tblr_use_strut_ht_box_vmode: + { + \@minipagetrue % for lists (see issue #99) + } + +\cs_new_protected:Npn \__tblr_use_strut_dp_box_real: + { + \box_use:N \l__tblr_strut_dp_box + } +\cs_new_protected:Npn \__tblr_use_strut_dp_box_ignore: { } + %% Calculate the thickness for every hline and vline \cs_new_protected:Npn \__tblr_calculate_line_sizes: { @@ -3207,7 +3322,11 @@ { %% When using text as vline, we need to omit abovepos and belowpos. \unskip - \hbox_set:Nn \l__tblr_d_box { \l__tblr_b_tl } + \hbox_set:Nn \l__tblr_d_box + { + \bool_if:NTF \l__tblr_math_mode_bool + { $ \l__tblr_b_tl $ } { \l__tblr_b_tl } + } \box_set_ht:Nn \l__tblr_d_box {#4} \box_set_dp:Nn \l__tblr_d_box {#5} \box_use:N \l__tblr_d_box @@ -3265,7 +3384,11 @@ \__tblr_get_hline_dash_style:N \l__tblr_b_tl \xleaders \l__tblr_b_tl \hfil } - { \l__tblr_b_tl \hfil } + { + \bool_if:NTF \l__tblr_math_mode_bool + { $ \l__tblr_b_tl $ } { \l__tblr_b_tl } + \hfil + } \group_end: } @@ -3329,6 +3452,7 @@ %% You can use these two counters in cell text \int_zero:N \c@rownum \int_zero:N \c@colnum + \__tblr_save_counters:n { table } \int_step_inline:nn { \c@rowcount } { \int_incr:N \c@rownum @@ -3355,6 +3479,7 @@ \g__tblr_cell_foot_dim } } + \__tblr_restore_counters:n { table } \int_step_inline:nn { \c@colcount } { \tl_set:Nx \l__tblr_w_tl @@ -3388,9 +3513,7 @@ \cs_new_protected:Npn \__tblr_measure_cell_update_sizes:nnNNNN #1 #2 #3 #4 #5 #6 { \__tblr_get_cell_alignments:nn {#1} {#2} - \__tblr_save_counters:n { trial } \hbox_set:Nn \l_tmpa_box { \__tblr_get_cell_text:nn {#1} {#2} } - \__tblr_restore_counters:n { trial } \__tblr_update_cell_size:nnNNNN {#1} {#2} #3 #4 #5 #6 \__tblr_update_row_size:nnNNN {#1} {#2} #4 #5 #6 \__tblr_update_col_size:nN {#2} #3 @@ -3423,13 +3546,21 @@ \cs_new_protected:Npn \__tblr_get_cell_text_real:nn #1 #2 { \group_begin: - \tl_set:Nx \l__tblr_cell_cmd_tl - { \__tblr_data_item:neen { cell } {#1} {#2} { cmd } } - \tl_if_empty:NTF \l__tblr_cell_cmd_tl - { \tl_set:Nx \l__tblr_c_tl { \__tblr_spec_item:ne { text } {[#1][#2]} } } - { - \tl_set:Nx \l__tblr_c_tl { { \__tblr_spec_item:ne { text } {[#1][#2]} } } - \tl_put_left:NV \l__tblr_c_tl \l__tblr_cell_cmd_tl + \tl_set:Nx \l__tblr_c_tl { \__tblr_spec_item:ne { text } {[#1][#2]} } + %% when the cell text is guarded by a pair of curly braces, + %% we unbrace it and ignore cmd option of the cell, see issue #90. + \bool_lazy_and:nnTF + { \tl_if_single_p:N \l__tblr_c_tl } + { \exp_args:NV \tl_if_head_is_group_p:n \l__tblr_c_tl } + { \exp_last_unbraced:NNV \tl_set:Nn \l__tblr_c_tl \l__tblr_c_tl } + { + \tl_set:Nx \l__tblr_cell_cmd_tl + { \__tblr_data_item:neen { cell } {#1} {#2} { cmd } } + \tl_if_empty:NF \l__tblr_cell_cmd_tl + { + \tl_set:Nx \l__tblr_c_tl + { \exp_not:V \l__tblr_cell_cmd_tl { \exp_not:V \l__tblr_c_tl } } + } } \tl_set:Nx \l__tblr_cell_mode_tl { \__tblr_data_item:neen { cell } {#1} {#2} { mode } } @@ -3462,14 +3593,17 @@ } \dim_compare:nNnT { \l__tblr_w_tl } < { 0pt } % column width unset { + \__tblr_save_counters:n { cell } \bool_if:NTF \l__tblr_cell_math_mode_bool { - \hbox_set:Nn \l_tmpa_box { \l__tblr_c_tl } + %% Note that font = \boldmath will increase cell width (issue #137) + \hbox_set:Nn \l_tmpa_box { \l__tblr_f_tl \l__tblr_c_tl } \tl_set:Nx \l__tblr_w_tl { \box_wd:N \l_tmpa_box } } { \__tblr_get_cell_size_with_box: } + \__tblr_restore_counters:n { cell } } \tl_set:Nx \l__tblr_cell_fg_tl { \__tblr_data_item:neen { cell } {#1} {#2} { foreground } } @@ -3480,11 +3614,9 @@ \cs_new_protected:Npn \__tblr_get_cell_size_with_box: { - \__tblr_save_counters:n { cell } \tl_if_eq:NnTF \l__tblr_inner_spec_measure_tl { vbox } { \__tblr_get_cell_size_with_vbox: } { \__tblr_get_cell_size_with_hbox: } - \__tblr_restore_counters:n { cell } } %% Varwidth won't work as expected when \color command occurs in it, @@ -3494,6 +3626,9 @@ %% or users may use it in the middle of the cell text, %% so we have redefine \color command and disable it before measuring cell. +%% In order to correctly measure an enumerate environment, +%% we need to enclose varwidth with NoHyper environment (see issue #196). + \NewDocumentCommand \__tblr_fake_color_command:w { o m } { } \cs_new_protected:Npn \__tblr_get_cell_size_with_vbox: @@ -3501,10 +3636,12 @@ \hbox_set:Nn \l_tmpa_box { \cs_set_eq:NN \color \__tblr_fake_color_command:w + \begin{tblrNoHyper} \begin{varwidth}{\paperwidth} \l__tblr_f_tl \__tblr_rescan_cell_tokens:N \l__tblr_c_tl \end{varwidth} + \end{tblrNoHyper} } \tl_set:Nx \l__tblr_w_tl { \box_wd:N \l_tmpa_box } } @@ -3582,15 +3719,15 @@ \cs_new_protected:Npn \__tblr_make_vcell_text:NN #1 #2 { \dim_set:Nn \tex_hsize:D { #2 } - \@arrayparboxrestore + \TblrParboxRestore \cs:w __tblr_halign_command_ \g__tblr_cell_halign_tl : \cs_end: - \mode_leave_vertical: - \box_use:N \l__tblr_strut_ht_box + %% \mode_leave_vertical: has been moved into \__tblr_use_strut_ht_box: + \__tblr_use_strut_ht_box: \tl_if_empty:NF \l__tblr_cell_fg_tl { \exp_args:NV \color \l__tblr_cell_fg_tl } \bool_if:NTF \l__tblr_cell_math_mode_bool { #1 } { \__tblr_rescan_cell_tokens:N #1 } - \box_use:N \l__tblr_strut_dp_box + \__tblr_use_strut_dp_box: } %% When using verb option, there is an end-of-line character at the end. @@ -3775,7 +3912,7 @@ } %%% -------------------------------------------------------- -%% \section{Calculate and Adjust Extendable Columns} +%%> \section{Calculate and Adjust Extendable Columns} %%% -------------------------------------------------------- %% Compute column widths when there are some extendable columns @@ -3943,7 +4080,7 @@ } %%% -------------------------------------------------------- -%% \section{Calculate and Adjust Multispan Cells} +%%> \section{Calculate and Adjust Multispan Cells} %%% -------------------------------------------------------- %% Compute and adjust widths when there are some span cells. @@ -4479,6 +4616,7 @@ \keys_set:nn { tblr-def-template } {#1} \ignorespaces } +\cs_new_eq:NN \DeclareTblrTemplate \DefTblrTemplate \cs_new_protected:Npn \__tblr_def_template:n #1 { @@ -4869,11 +5007,16 @@ } \SetTblrTemplate { note-border } { empty } +\cs_set_eq:NN \TblrOverlap \rlap + \NewDocumentCommand \TblrNote { m } { \cs_if_exist:NT \hypersetup { \ExpTblrTemplate { note-border }{ default } } - \__tblr_hyper_link:nn {#1} - { \textsuperscript { \sffamily \UseTblrFont { note-tag } #1 } } + \TblrOverlap + { + \__tblr_hyper_link:nn {#1} + { \textsuperscript { \sffamily \UseTblrFont { note-tag } #1 } } + } } \DefTblrTemplate { note-tag } { empty } { } @@ -5146,16 +5289,26 @@ \__tblr_build_table_label_entry: \UseTblrTemplate { firsthead } { default } } - \__tblr_build_table_head_aux:Nn - \l__tblr_table_middlehead_box { \UseTblrTemplate { middlehead } { default } } - \__tblr_build_table_head_aux:Nn - \l__tblr_table_lasthead_box { \UseTblrTemplate { lasthead } { default } } - \__tblr_build_table_foot_aux:Nn - \l__tblr_table_firstfoot_box { \UseTblrTemplate { firstfoot } { default } } - \__tblr_build_table_foot_aux:Nn - \l__tblr_table_middlefoot_box { \UseTblrTemplate { middlefoot } { default } } - \__tblr_build_table_foot_aux:Nn - \l__tblr_table_lastfoot_box { \UseTblrTemplate { lastfoot } { default } } + \__tblr_build_table_head_aux:Nn \l__tblr_table_middlehead_box + { + \UseTblrTemplate { middlehead } { default } + } + \__tblr_build_table_head_aux:Nn \l__tblr_table_lasthead_box + { + \UseTblrTemplate { lasthead } { default } + } + \__tblr_build_table_foot_aux:Nn \l__tblr_table_firstfoot_box + { + \UseTblrTemplate { firstfoot } { default } + } + \__tblr_build_table_foot_aux:Nn \l__tblr_table_middlefoot_box + { + \UseTblrTemplate { middlefoot } { default } + } + \__tblr_build_table_foot_aux:Nn \l__tblr_table_lastfoot_box + { + \UseTblrTemplate { lastfoot } { default } + } } \cs_new_protected:Npn \__tblr_build_tall_table_head_foot: @@ -5192,9 +5345,12 @@ \vbox_set:Nn #1 { \hsize = \tablewidth - \parindent = 0pt \relax - \vbox:n {#2} - \skip_vertical:n { \__tblr_spec_item:nn { outer } { headsep } } + \TblrParboxRestore % it will set \linewidth = \hsize + \vbox_set:Nn \l_tmpa_box {#2} + \box_use:N \l_tmpa_box + \dim_compare:nNnT + { \box_ht:N \l_tmpa_box + \box_dp:N \l_tmpa_box } > { 0pt } + { \skip_vertical:n { \__tblr_spec_item:nn { outer } { headsep } } } } } @@ -5203,9 +5359,12 @@ \vbox_set:Nn #1 { \hsize = \tablewidth - \skip_vertical:n { \__tblr_spec_item:nn { outer } { footsep } } - \parindent = 0pt \relax - \vbox:n {#2} + \TblrParboxRestore % it will set \linewidth = \hsize + \vbox_set:Nn \l_tmpb_box {#2} + \dim_compare:nNnT + { \box_ht:N \l_tmpb_box + \box_dp:N \l_tmpb_box } > { 0pt } + { \skip_vertical:n { \__tblr_spec_item:nn { outer } { footsep } } } + \box_use:N \l_tmpb_box } } @@ -5217,11 +5376,11 @@ \tl_if_eq:enTF { \__tblr_spec_item:nn { outer } { tall } } { true } { \__tblr_build_tall_table:e - { \__tblr_spec_item:nn { outer } { valign } } + { \__tblr_spec_item:nn { outer } { baseline } } } { \__tblr_build_short_table:e - { \__tblr_spec_item:nn { outer } { valign } } + { \__tblr_spec_item:nn { outer } { baseline } } } } } @@ -5288,7 +5447,7 @@ \int_incr:N \l__tblr_table_page_int \int_set:Nn \l__tblr_long_from_int { \l__tblr_prev_i_int + 1 } } - \newpage + \TblrNewPage \hbox{}\kern-\topskip\nobreak \noindent \LogTblrTracing { page } @@ -5302,7 +5461,7 @@ { \int_use:N \l__tblr_long_from_int } { \int_use:N \l__tblr_curr_i_int } \int_incr:N \l__tblr_table_page_int - \newpage + \TblrNewPage \hbox{}\kern-\topskip\nobreak \noindent \LogTblrTracing { page } @@ -5356,12 +5515,17 @@ \int_compare:nNnTF {#2} < {#1} { \tl_set:Nx \l__tblr_b_tl - { \__tblr_data_item:nen { row } { \int_eval:n { #2 + 1 } } { break } } - \int_compare:nNnTF { \l__tblr_b_tl } < { 0 } + { + \__tblr_spec_item:ne { hline } + { [ \int_eval:n { #2 + 1 } ] / @pagebreak } + } + % Note that \l__tblr_b_tl may be empty + \int_compare:nNnTF { \l__tblr_b_tl + 0 } < { 0 } { \bool_set_true:N \l_tmpa_bool } { \bool_set_false:N \l_tmpa_bool - \int_compare:nNnT { \l__tblr_b_tl } > { 0 } { \bool_set_true:N #4 } + \int_compare:nNnT { \l__tblr_b_tl + 0 } > { 0 } + { \bool_set_true:N #4 } } } { \bool_set_false:N \l_tmpa_bool } @@ -5425,7 +5589,7 @@ \hrule height ~ 0pt \box_use:N \l__tblr_table_foot_box } - \__tblr_halign_whole:Nn \l__tblr_table_box #1 + \__tblr_halign_whole:Nn \l__tblr_table_box {#1} } \cs_generate_variant:Nn \__tblr_build_page_table:nnn { nnx } @@ -5463,7 +5627,6 @@ \cs_new_protected:Npn \__tblr_build_tall_table:n #1 { \mode_leave_vertical: - \raggedright \__tblr_build_tall_table_head_foot: \__tblr_build_one_table:nn {1} {\c@rowcount} \vbox_set:Nn \l__tblr_table_box @@ -5474,7 +5637,7 @@ \hrule height ~ 0pt \box_use:N \l__tblr_table_lastfoot_box } - \__tblr_valign_whole:Nn \l__tblr_table_box #1 + \__tblr_valign_whole:Nn \l__tblr_table_box {#1} } \cs_generate_variant:Nn \__tblr_build_tall_table:n { e } @@ -5484,7 +5647,7 @@ { \mode_leave_vertical: \__tblr_build_one_table:nn {1} {\c@rowcount} - \__tblr_valign_whole:Nn \l__tblr_table_box #1 + \__tblr_valign_whole:Nn \l__tblr_table_box {#1} } \cs_generate_variant:Nn \__tblr_build_short_table:n { e } @@ -5561,9 +5724,15 @@ \tl_new:N \__tblr_vbox_align_tl \tl_const:Nn \__tblr_vbox_t_tl {t} +\tl_const:Nn \__tblr_vbox_T_tl {T} \tl_const:Nn \__tblr_vbox_m_tl {m} +\tl_const:Nn \__tblr_vbox_M_tl {M} \tl_const:Nn \__tblr_vbox_c_tl {c} \tl_const:Nn \__tblr_vbox_b_tl {b} +\tl_const:Nn \__tblr_vbox_B_tl {B} + +\regex_const:Nn \c__tblr_is_positive_integer_regex { ^ \d+ $ } +\regex_const:Nn \c__tblr_is_negative_integer_regex { ^ - \d+ $ } \cs_new_protected:Npn \__tblr_valign_whole:Nn #1 #2 { @@ -5576,12 +5745,34 @@ { \__tblr_valign_whole_middle:N #1 } \__tblr_vbox_c_tl { \__tblr_valign_whole_middle:N #1 } + \__tblr_vbox_M_tl + { \__tblr_valign_whole_middle_row_or_border:N #1 } \__tblr_vbox_t_tl { \__tblr_valign_whole_top:N #1 } + \__tblr_vbox_T_tl + { + \tl_set:Nn \__tblr_vbox_align_tl {1} + \__tblr_valign_whole_at_row_from_above:N #1 + } \__tblr_vbox_b_tl { \__tblr_valign_whole_bottom:N #1 } + \__tblr_vbox_B_tl + { + \tl_set:Nx \__tblr_vbox_align_tl { \int_use:N \c@rowcount } + \__tblr_valign_whole_at_row_from_below:N #1 + } + } + { + \regex_match:NVTF \c__tblr_is_positive_integer_regex \__tblr_vbox_align_tl + { \__tblr_valign_whole_at_row:N #1 } + { + \regex_match:NVTF + \c__tblr_is_negative_integer_regex \__tblr_vbox_align_tl + { \__tblr_valign_whole_at_border:N #1 } + { \__tblr_valign_whole_middle:N #1 } + } } - { \__tblr_valign_whole_middle:N #1 } + \box_use_drop:N #1 \group_end: } @@ -5592,74 +5783,147 @@ \cs_new_protected:Npn \__tblr_valign_whole_top:N #1 { - \tl_set:Nx \l__tblr_a_tl - { \__tblr_spec_item:ne { hline } { [1] / @hline-height } } - %% Note that \l__tblr_b_tl may be empty - \tl_set:Nx \l__tblr_b_tl - { \__tblr_prop_item:ne { inner } { baseline } } - \bool_lazy_or:nnTF - { \dim_compare_p:nNn { \l__tblr_a_tl } = { 0pt } } - { \int_compare_p:nNn { \l__tblr_b_tl + 0 } = { 1 } } + \dim_set:Nn \l__tblr_h_dim { \__tblr_valign_get_hline_total:n {1} } + \dim_compare:nNnT \l__tblr_h_dim = { 0pt } + { \dim_add:Nn \l__tblr_h_dim { \__tblr_valign_get_row_height:n {1} } } + \box_set_ht:Nn #1 { \l__tblr_h_dim } + \box_set_dp:Nn #1 { \l__tblr_t_dim - \l__tblr_h_dim } + } + +\cs_new_protected:Npn \__tblr_valign_whole_bottom:N #1 + { + \dim_set:Nn \l__tblr_d_dim + { \__tblr_valign_get_hline_total:n { \int_eval:n { \c@rowcount + 1 } } } + \dim_compare:nNnTF \l__tblr_d_dim = { 0pt } { - \dim_set:Nn \l__tblr_h_dim - { - \__tblr_data_item:nnn { row } {1} { abovesep } - + - ( \__tblr_data_item:nnn { row } {1} { @row-height } - + - \__tblr_data_item:nnn { row } {1} { @row-upper } - - - \__tblr_data_item:nnn { row } {1} { @row-lower } - ) / 2 - } - \dim_set:Nn \l__tblr_d_dim { \l__tblr_t_dim - \l__tblr_h_dim } + \dim_set:Nn \l__tblr_d_dim + { \__tblr_valign_get_row_depth:n { \int_use:N \c@rowcount } } } + { \dim_zero:N \l__tblr_d_dim } + \box_set_ht:Nn #1 { \l__tblr_t_dim - \l__tblr_d_dim } + \box_set_dp:Nn #1 { \l__tblr_d_dim } + } + +\cs_new_protected:Npn \__tblr_valign_whole_middle_row_or_border:N #1 + { + \int_if_odd:nTF { \c@rowcount } { - \dim_set:Nn \l__tblr_h_dim { 0pt } - \dim_set_eq:NN \l__tblr_d_dim \l__tblr_t_dim + \tl_set:Nx \__tblr_vbox_align_tl { \int_eval:n { (\c@rowcount + 1) / 2 } } + \__tblr_valign_whole_at_row_from_above:N #1 + } + { + \tl_set:Nx \__tblr_vbox_align_tl { \int_eval:n { \c@rowcount / 2 + 1 } } + \__tblr_valign_whole_at_border_from_above:N #1 } - \box_set_ht:Nn #1 { \l__tblr_h_dim } - \box_set_dp:Nn #1 { \l__tblr_d_dim } - \box_use_drop:N #1 } -\cs_new_protected:Npn \__tblr_valign_whole_bottom:N #1 +\cs_new_protected:Npn \__tblr_valign_whole_at_row:N #1 { - \tl_set:Nx \l__tblr_a_tl + \int_compare:nNnTF { 2 * \__tblr_vbox_align_tl } > { \c@rowcount } + { \__tblr_valign_whole_at_row_from_below:N #1 } + { \__tblr_valign_whole_at_row_from_above:N #1 } + } + +\cs_new_protected:Npn \__tblr_valign_whole_at_row_from_above:N #1 + { + \dim_set:Nn \l__tblr_h_dim + { \__tblr_valign_get_hline_total:n { \__tblr_vbox_align_tl } } + \dim_add:Nn \l__tblr_h_dim + { \__tblr_valign_get_row_height:n { \__tblr_vbox_align_tl } } + \int_step_inline:nn { \__tblr_vbox_align_tl - 1 } { - \__tblr_spec_item:ne { hline } - { [\int_eval:n {\c@rowcount + 1}] / @hline-height } + \dim_add:Nn \l__tblr_h_dim { \__tblr_valign_get_hline_total:n {##1} } + \dim_add:Nn \l__tblr_h_dim { \__tblr_valign_get_row_total:n {##1} } } - %% Note that \l__tblr_b_tl may be empty - \tl_set:Nx \l__tblr_b_tl - { \__tblr_prop_item:ne { inner } { baseline } } - \bool_lazy_or:nnTF - { \dim_compare_p:nNn { \l__tblr_a_tl } = { 0pt } } - { \int_compare_p:nNn { \l__tblr_b_tl + 0 } = { \c@rowcount } } + \box_set_ht:Nn #1 { \l__tblr_h_dim } + \box_set_dp:Nn #1 { \l__tblr_t_dim - \l__tblr_h_dim } + } + +\cs_new_protected:Npn \__tblr_valign_whole_at_row_from_below:N #1 + { + \dim_set:Nn \l__tblr_d_dim + { \__tblr_valign_get_hline_total:n { \int_eval:n {\c@rowcount + 1} } } + \dim_add:Nn \l__tblr_d_dim + { \__tblr_valign_get_row_depth:n { \__tblr_vbox_align_tl } } + \int_step_inline:nnn { \__tblr_vbox_align_tl + 1 } { \c@rowcount } { - \dim_set:Nn \l__tblr_d_dim - { - ( \__tblr_data_item:nen { row } - { \int_use:N \c@rowcount } { @row-height } - - - \__tblr_data_item:nen { row } - { \int_use:N \c@rowcount } { @row-upper } - + - \__tblr_data_item:nen { row } - { \int_use:N \c@rowcount } { @row-lower } - ) / 2 - + - \__tblr_data_item:nnn { row } {1} { belowsep } - } - \dim_set:Nn \l__tblr_h_dim { \l__tblr_t_dim - \l__tblr_d_dim } + \dim_add:Nn \l__tblr_d_dim { \__tblr_valign_get_hline_total:n {##1} } + \dim_add:Nn \l__tblr_d_dim { \__tblr_valign_get_row_total:n {##1} } } + \box_set_dp:Nn #1 { \l__tblr_d_dim } + \box_set_ht:Nn #1 { \l__tblr_t_dim - \l__tblr_d_dim } + } + +\cs_new_protected:Npn \__tblr_valign_whole_at_border:N #1 + { + \tl_set:Nx \__tblr_vbox_align_tl { \int_eval:n { - \__tblr_vbox_align_tl } } + \int_compare:nNnTF { 2 * \__tblr_vbox_align_tl - 2 } > { \c@rowcount } + { \__tblr_valign_whole_at_border_from_below:N #1 } + { \__tblr_valign_whole_at_border_from_above:N #1 } + } + +\cs_new_protected:Npn \__tblr_valign_whole_at_border_from_above:N #1 + { + \dim_set:Nn \l__tblr_h_dim + { \__tblr_valign_get_hline_total:n { \__tblr_vbox_align_tl } } + \int_step_inline:nn { \__tblr_vbox_align_tl - 1 } { - \dim_set:Nn \l__tblr_d_dim { 0pt } - \dim_set_eq:NN \l__tblr_h_dim \l__tblr_t_dim + \dim_add:Nn \l__tblr_h_dim { \__tblr_valign_get_hline_total:n {##1} } + \dim_add:Nn \l__tblr_h_dim { \__tblr_valign_get_row_total:n {##1} } } \box_set_ht:Nn #1 { \l__tblr_h_dim } + \box_set_dp:Nn #1 { \l__tblr_t_dim - \l__tblr_h_dim } + } + +\cs_new_protected:Npn \__tblr_valign_whole_at_border_from_below:N #1 + { + \dim_zero:N \l__tblr_d_dim + \int_step_inline:nnn { \__tblr_vbox_align_tl } { \c@rowcount } + { + \dim_add:Nn \l__tblr_d_dim { \__tblr_valign_get_row_total:n {##1} } + \dim_add:Nn \l__tblr_d_dim + { \__tblr_valign_get_hline_total:n { \int_eval:n { ##1 + 1 } } } + } \box_set_dp:Nn #1 { \l__tblr_d_dim } - \box_use_drop:N #1 + \box_set_ht:Nn #1 { \l__tblr_t_dim - \l__tblr_d_dim } + } + +\cs_new_nopar:Npn \__tblr_valign_get_hline_total:n #1 + { + \__tblr_spec_item:ne { hline } { [#1] / @hline-height } + } + +\cs_new_nopar:Npn \__tblr_valign_get_row_total:n #1 + { + \__tblr_data_item:nnn { row } {#1} { abovesep } + + + \__tblr_data_item:nnn { row } {#1} { @row-height } + + + \__tblr_data_item:nnn { row } {#1} { belowsep } + } + +\cs_new_nopar:Npn \__tblr_valign_get_row_height:n #1 + { + \__tblr_data_item:nnn { row } {#1} { abovesep } + + + ( \__tblr_data_item:nnn { row } {#1} { @row-height } + + + \__tblr_data_item:nnn { row } {#1} { @row-upper } + - + \__tblr_data_item:nnn { row } {#1} { @row-lower } + ) / 2 + } + +\cs_new_nopar:Npn \__tblr_valign_get_row_depth:n #1 + { + ( \__tblr_data_item:nen { row } {#1} { @row-height } + - + \__tblr_data_item:nen { row } {#1} { @row-upper } + + + \__tblr_data_item:nen { row } {#1} { @row-lower } + ) / 2 + + + \__tblr_data_item:nnn { row } {#1} { belowsep } } %%% -------------------------------------------------------- @@ -6064,7 +6328,8 @@ \hbox_set_to_wd:Nnn \l__tblr_a_box { \l__tblr_cell_wd_dim } { \tl_if_eq:NnTF \g__tblr_cell_halign_tl {j} - { \__tblr_get_cell_text:nn {#1} {#2} } + % cell width may be less than column width for j cells + { \__tblr_get_cell_text:nn {#1} {#2} \hfil } { \tl_if_eq:NnF \g__tblr_cell_halign_tl {l} { \hfil } \__tblr_get_cell_text:nn {#1} {#2} @@ -6245,14 +6510,13 @@ } %%% -------------------------------------------------------- -%% \section{Tracing Tabularray} +%%> \section{Tracing Tabularray} %%% -------------------------------------------------------- -\NewDocumentCommand \SetTabularrayTracing { m } +\NewDocumentCommand \SetTblrTracing { m } { \keys_set:nn { tblr-set-tracing } {#1} } -\cs_new_eq:NN \SetTblrTracing \SetTabularrayTracing \bool_new:N \g__tblr_tracing_text_bool \bool_new:N \g__tblr_tracing_command_bool @@ -6361,11 +6625,10 @@ \bool_gset_false:N \g__tblr_tracing_step_bool } -\NewDocumentCommand \LogTabularrayTracing { m } +\NewDocumentCommand \LogTblrTracing { m } { \keys_set:nn { tblr-log-tracing } {#1} } -\cs_new_eq:NN \LogTblrTracing \LogTabularrayTracing \keys_define:nn { tblr-log-tracing } { @@ -6482,7 +6745,7 @@ } %%% -------------------------------------------------------- -%% \section{Tabularray Libraries} +%%> \section{Tabularray Libraries} %%% -------------------------------------------------------- %% \NewTblrLibrary and \UseTblrLibrary commands @@ -6571,17 +6834,18 @@ \RequirePackage { booktabs } \newcommand \tblr@booktabs@hline [1] [] { \hline [##1] } \newcommand \tblr@booktabs@oldhline [1] [] { - \hline [abovespace = \aboverulesep, belowspace = \belowrulesep, ##1] + \hline [##1] + \hborder { abovespace = \aboverulesep, belowspace = \belowrulesep } } \newcommand \tblr@booktabs@cline [2] [] { \cline [##1] {##2} } \newcommand \tblr@booktabs@oldcline [2] [] { - \cline [abovespace = \aboverulesep, belowspace = \belowrulesep, ##1] {##2} + \cline [##1] {##2} + \hborder { abovespace = \aboverulesep, belowspace = \belowrulesep } } \newcommand \tblr@booktabs@cline@more [2] [] { \SetHline [+] {##2} {##1} } \newcommand \tblr@booktabs@oldcline@more [2] [] { - \SetHline [+] {##2} { - abovespace = \aboverulesep, belowspace = \belowrulesep, ##1 - } + \SetHline [+] {##2} {##1} + \hborder { abovespace = \aboverulesep, belowspace = \belowrulesep } } \NewTableCommand \toprule [1] [] { \tblr@booktabs@hline [wd=\heavyrulewidth, ##1] @@ -6603,20 +6867,29 @@ \peek_meaning:NTF \cmidrule { \tblr@booktabs@change@more } { \relax } } \NewTblrEnviron { booktabs } + \NewTblrEnviron { longtabs } + \NewTblrEnviron { talltabs } \SetTblrInner [ booktabs ] { rowsep = 0pt } + \SetTblrInner [ longtabs ] { rowsep = 0pt } + \SetTblrInner [ talltabs ] { rowsep = 0pt } + \SetTblrOuter [ longtabs ] { long } + \SetTblrOuter [ talltabs ] { tall } \RequirePackage { etoolbox } - \AtBeginEnvironment { booktabs } + \newcommand \tblr@booktabs@begin@hook { \let \tblr@booktabs@hline = \tblr@booktabs@oldhline \let \tblr@booktabs@cline = \tblr@booktabs@oldcline \let \tblr@booktabs@cline@more = \tblr@booktabs@oldcline@more } + \AtBeginEnvironment { booktabs } { \tblr@booktabs@begin@hook } + \AtBeginEnvironment { longtabs } { \tblr@booktabs@begin@hook } + \AtBeginEnvironment { talltabs } { \tblr@booktabs@begin@hook } \NewTableCommand \specialrule [3] - { \hline [##1, abovespace = ##2, belowspace = ##3] } + { \hline [##1] \hborder { abovespace = ##2, belowspace = ##3 } } \NewTableCommand \addrowspace [1] [\defaultaddspace] - { \SetVspace { abovespace+ = (##1) / 2, belowspace+ = (##1) / 2 } } + { \hborder { abovespace+ = (##1) / 2, belowspace+ = (##1) / 2 } } \NewTableCommand \addlinespace [1] [\defaultaddspace] - { \SetVspace { abovespace+ = (##1) / 2, belowspace+ = (##1) / 2 } } + { \hborder { abovespace+ = (##1) / 2, belowspace+ = (##1) / 2 } } } %% Library counter for resetting all counters -- cgit v1.2.3