texlive[55483] Master/texmf-dist: cellprops (8jun20)

commits+karl at tug.org commits+karl at tug.org
Mon Jun 8 23:18:52 CEST 2020


Revision: 55483
          http://tug.org/svn/texlive?view=revision&revision=55483
Author:   karl
Date:     2020-06-08 23:18:51 +0200 (Mon, 08 Jun 2020)
Log Message:
-----------
cellprops (8jun20)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/latex/cellprops/LICENSE
    trunk/Master/texmf-dist/doc/latex/cellprops/README.md
    trunk/Master/texmf-dist/doc/latex/cellprops/cellprops.pdf
    trunk/Master/texmf-dist/source/latex/cellprops/cellprops.dtx
    trunk/Master/texmf-dist/source/latex/cellprops/cellprops.ins
    trunk/Master/texmf-dist/tex/latex/cellprops/cellprops.sty

Modified: trunk/Master/texmf-dist/doc/latex/cellprops/LICENSE
===================================================================
--- trunk/Master/texmf-dist/doc/latex/cellprops/LICENSE	2020-06-08 21:18:36 UTC (rev 55482)
+++ trunk/Master/texmf-dist/doc/latex/cellprops/LICENSE	2020-06-08 21:18:51 UTC (rev 55483)
@@ -632,7 +632,7 @@
 the "copyright" line and a pointer to where the full notice is found.
 
     cellprops
-    Copyright (C) 2016-2019  Julien "_FrnchFrgg_" RIVAUD
+    Copyright (C) 2016-2020  Julien "_FrnchFrgg_" RIVAUD
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -652,7 +652,7 @@
   If the program does terminal interaction, make it output a short
 notice like this when it starts in an interactive mode:
 
-    cellprops  Copyright (C) 2016-2019  Julien "_FrnchFrgg_" RIVAUD
+    cellprops  Copyright (C) 2016-2020  Julien "_FrnchFrgg_" RIVAUD
     This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
     This is free software, and you are welcome to redistribute it
     under certain conditions; type `show c' for details.

Modified: trunk/Master/texmf-dist/doc/latex/cellprops/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/cellprops/README.md	2020-06-08 21:18:36 UTC (rev 55482)
+++ trunk/Master/texmf-dist/doc/latex/cellprops/README.md	2020-06-08 21:18:51 UTC (rev 55483)
@@ -13,7 +13,7 @@
 
 
 
-Copyright (C) 2016-2019  Julien "_FrnchFrgg_" RIVAUD
+Copyright (C) 2016-2020  Julien "_FrnchFrgg_" RIVAUD
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by

Modified: trunk/Master/texmf-dist/doc/latex/cellprops/cellprops.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/source/latex/cellprops/cellprops.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/cellprops/cellprops.dtx	2020-06-08 21:18:36 UTC (rev 55482)
+++ trunk/Master/texmf-dist/source/latex/cellprops/cellprops.dtx	2020-06-08 21:18:51 UTC (rev 55483)
@@ -1,7 +1,7 @@
 % \iffalse meta-comment
 % vim: tw=80 spl=en
 %
-%% File: cellprops.dtx (C) Copyright 2016-2019 RIVAUD Julien
+%% File: cellprops.dtx (C) Copyright 2016-2020 RIVAUD Julien
 %%
 %% It may be distributed and/or modified under the conditions of the
 %% General Public License (GPL), either version 3 of this
@@ -14,8 +14,8 @@
 \RequirePackage{expl3}[2018/06/19]
 \def\ExplFileName{cellprops}
 \def\ExplFileDescription{CSS-like cell and table properties}
-\def\ExplFileDate{2019/09/29}
-\def\ExplFileVersion{1.6}
+\def\ExplFileDate{2020/06/07}
+\def\ExplFileVersion{1.7a}
 %</driver|package>
 %<*driver>
 \documentclass[full]{l3doc}
@@ -159,6 +159,8 @@
 %
 %\cellprops{
 %   td { border: thin solid black; }
+%   tr:nth-child(-n+3) { background-color: black!10; }
+%   tr:nth-child(n+8) { background-color: blue!10; }
 %   tr:nth-child(4n) td:first-child,
 %   tr:nth-child(4n+1) td:nth-child(2),
 %   tr:nth-child(4n+2) td:nth-child(3),
@@ -200,6 +202,8 @@
 %\begin{verbatim}
 %\cellprops{
 %   td { border: thin solid black; }
+%   tr:nth-child(-n+3) { background-color: black!10; }
+%   tr:nth-child(n+8) { background-color: blue!10; }
 %   tr:nth-child(4n) td:first-child,
 %   tr:nth-child(4n+1) td:nth-child(2),
 %   tr:nth-child(4n+2) td:nth-child(3),
@@ -312,16 +316,13 @@
 %        "td:nth-child()" to select a column. Currently, cells spanning several
 %        columns actually increase the child count by the number of column they
 %        span, so that nth-child can still be used to select columns.
-%        This is not consistent with the CSS specification.
-%    \item Any ":nth-child("$A$"n+"$B$")" or ":nth-child("$A$"n)"
-%       or ":nth-child("$B$")" is supported, with arbitrary $A$~and~$B$. The
-%       performance will slowly degrade the more different~$A$ are active
-%       (but if in a \TeX\ group, they will become inactive again when leaving
-%       the group). \emph{A big difference} with the CSS specification is that
-%       currently $n$ is not enforced non-negative. In particular
-%       ":nth-child(2n+8)" \emph{will} match for the second element. This also
-%       prevents tricks like ":nth-child(-n+3)". I am investigating how to
-%       handle those without slowing down the general case.
+%        This is not consistent with the HTML specification of tables, but acts
+%        as if a cell spanning multiple columns was implicitly creating
+%        "display: none" empty cell siblings following it.
+%    \item Any ":nth-child("$A$"n+"$B$")" or ":nth-child("$A$"n)" or
+%        ":nth-child("$B$")" is supported, with arbitrary $A$~and~$B$, including
+%        nothing for~$A$ (standing for~$A = 1$) or just a minus sign (standing
+%        for~$A = -1$).
 % \end{itemize}
 %
 % \subsection{Compatibility}
@@ -338,8 +339,7 @@
 %
 % Add a test suite with compatibility tests. Improve
 % the documentation, and test more \LaTeX\ table constructs and preamble column
-% types. Enforce $n\ge0$ in ":nth-child" selectors to match the CSS
-% specification.
+% types.
 %
 % \end{documentation}
 %
@@ -452,6 +452,12 @@
 %
 %   \end{macro}
 %
+%   \begin{macro}{\@@_parse_properties:nn}
+%   Now we can parse the block of properties for a given selector. The first
+%   argument is the token list variable which will ultimately hold the expanded
+%   code setting internal variables from the properties. That code will be
+%   called when recalling the computed values in a specific context.
+%
 %    \begin{macrocode}
 \cs_new_protected:Nn \@@_parse_properties:Nn {
     \tl_clear:N #1
@@ -477,7 +483,20 @@
         }
     }
 }
-
+%    \end{macrocode}
+%   \end{macro}
+%
+%   \subsection{Defining new properties}
+%
+%   \subsubsection{Some helpers}
+%
+%   \begin{macro}{\@@_fourval_setter:nnnnnn}
+%   \begin{macro}{\@@_define_fourval_properties:nnnnnn}
+%   We first define helpers to parse and define compound properties like
+%   "padding" where you can give one to four different values and the missing
+%   values are copied from the given ones.
+%
+%    \begin{macrocode}
 \cs_new:Nn \@@_fourval_setter:nnnnnn {
     \@@_fourval_setter_aux:w
         {#1}{#2}{#3}{#4}#6~{\q_no_value}~{\q_no_value}~{\q_no_value}~\q_stop
@@ -510,7 +529,14 @@
         #2
     }
 }
-
+%    \end{macrocode}
+%   \end{macro}
+%   \end{macro}
+%
+%   \begin{macro}{\@@_color_setter:nn}
+%   This macro is used to parse color definitions, either named, rgb, or hsl.
+%
+%    \begin{macrocode}
 \tl_const:Nn \c_@@_inherit_color_tl { \q_nil }
 
 \cs_new_nopar:Nn \@@_color_setter:nn {
@@ -533,6 +559,13 @@
         }
     }
 }
+%    \end{macrocode}
+%   \end{macro}
+%
+%   \begin{macro}{\@@_bgcolor_setter:nn}
+%   For background colors, we support "transparent" as an alias for "inherit".
+%
+%    \begin{macrocode}
 \cs_new_nopar:Nn \@@_bgcolor_setter:nn {
     \str_if_eq:nnTF {#2} {transparent} {
         \@@_color_setter:nn {#1} {inherit}
@@ -540,7 +573,13 @@
         \@@_color_setter:nn {#1} {#2}
     }
 }
-
+%    \end{macrocode}
+%   \end{macro}
+%
+%   \begin{macro}{\@@_linewidth_setter:nn}
+%   A setter for line widths that supports common keywords:
+%
+%    \begin{macrocode}
 \cs_new_nopar:Nn \@@_linewidth_setter:nn {
     \str_case:nnF {#2} {
         {thin}   { \@@_generic_setter:nnn \exp_not:n {#1} { \fboxrule} }
@@ -550,7 +589,16 @@
         \@@_generic_setter:nnn \exp_not:n {#1} {#2}
     }
 }
-
+%    \end{macrocode}
+%   \end{macro}
+%
+%   \begin{macro}{\@@_border_setter:nn }
+%   "border" and "border-"<side> are  compound properties that can define the
+%   width, the style and the color. As per the specification, the "border"
+%   property always sets all four sides at the same time instead of being a
+%   four-valued property.
+%
+%    \begin{macrocode}
 \cs_new_nopar:Nn \@@_border_setter:nn {
     \@@_border_setter_aux:nw
         {#1}#2~{\q_no_value}~{\q_no_value}~\q_stop
@@ -586,6 +634,7 @@
         \@@_delegate_setter:nn {#1-color} {#4}
     }
 }
+
 \cs_new:Npn \@@_border_setter_isstyle:nTF #1 {
     \str_case:nnTF {#1} {
         {none}{} {hidden}{} {dotted}{} {dashed}{} {solid}{}
@@ -592,7 +641,15 @@
         {double}{} {groove}{} {ridge}{} {inset}{} {outset}{}
     }
 }
-
+%    \end{macrocode}
+%   \end{macro}
+%
+%   \subsubsection{Actual definitions of properties}
+%
+%   First some simple-valued properties where we just store the value
+%   unexpanded.
+%
+%    \begin{macrocode}
 \@@_define_properties:nn {
     \@@_generic_setter:nnn \exp_not:n
 }{
@@ -600,12 +657,21 @@
     min-depth,
     min-width,
 }
-
+%    \end{macrocode}
+%
+%   "padding" is a compound property for "padding-"<side> which store their
+%   value unexpanded.
+%
+%    \begin{macrocode}
 \@@_define_fourval_properties:nnnnnn
     { \@@_generic_setter:nnn \exp_not:n }
     {padding}
     {padding-top}{padding-right}{padding-bottom}{padding-left}
-
+%    \end{macrocode}
+%
+%   Simple-valued properties that store a str value.
+%
+%    \begin{macrocode}
 \@@_define_properties:nn {
     \@@_generic_setter:nnn \tl_to_str:n
 }{
@@ -612,7 +678,11 @@
     text-align,
     math-mode,
 }
-
+%    \end{macrocode}
+%
+%   Some simple-valued color properties, using the dedicated parser.
+%
+%    \begin{macrocode}
 \@@_define_properties:nn {
     \@@_color_setter:nn
 }{
@@ -624,31 +694,54 @@
 }{
     background-color,
 }
-
+%    \end{macrocode}
+%
+%   A compound property whose individual sides use the linewidth setter for
+%   keyword recognition.
+%
+%    \begin{macrocode}
 \@@_define_fourval_properties:nnnnnn
     { \@@_linewidth_setter:nn }
     {border-width}
     {border-top-width}{border-right-width}
     {border-bottom-width}{border-left-width}
-
+%    \end{macrocode}
+%
+%   A compound property whose individual sides are str values. They could be
+%   checked against the list of valid values, but any non-existing one will be
+%   ignored anyway due to the way they are implemented.
+%
+%    \begin{macrocode}
 \@@_define_fourval_properties:nnnnnn
     { \@@_generic_setter:nnn \tl_to_str:n }
     {border-style}
     {border-top-style}{border-right-style}
     {border-bottom-style}{border-left-style}
-
+%    \end{macrocode}
+%
+%   A compound property whose individual sides are colors.
+%
+%    \begin{macrocode}
 \@@_define_fourval_properties:nnnnnn
     { \@@_color_setter:nn }
     {border-color}
     {border-top-color}{border-right-color}
     {border-bottom-color}{border-left-color}
-
+%    \end{macrocode}
+%
+%   The five border-specific compound properties are defined here.
+%
+%    \begin{macrocode}
 \@@_define_properties:nn {
     \@@_border_setter:nn
 }{
     border, border-top, border-right, border-bottom, border-left
 }
-
+%    \end{macrocode}
+%
+%   \subsection{Parsing a CSS stylesheet}
+%
+%    \begin{macrocode}
 \NewDocumentCommand \cellprops { m } {
     \@@_parse_css:n {#1}
 }
@@ -656,135 +749,235 @@
 \cs_new_protected:Nn \@@_parse_css:n {
     \@@_parse_css:w #1 \q_mark {\q_nil} \q_stop
 }
-
-\tl_new:N \l_@@_parse_tmp_tl
+%    \end{macrocode}
+%
+%   Grab the content up to the first opening brace. That content will be the
+%   comma-separated selector list, and the braced content is a block of
+%   properties. We can loop until there is no such block remaining.
+%
+%    \begin{macrocode}
+\tl_new:N \l_@@_parse_properties_tl
 \NewDocumentCommand \@@_parse_css:w { lmu{\q_stop} } {
     \quark_if_nil:nF {#2} {
-        \@@_parse_properties:Nn \l_@@_parse_tmp_tl {#2}
+        \@@_parse_properties:Nn \l_@@_parse_properties_tl {#2}
         \clist_map_inline:nn {#1} {
-            \@@_parse_css_addprops:nV {##1} \l_@@_parse_tmp_tl
+            \@@_parse_css_addprops:n {##1}
         }
         \@@_parse_css:w #3 \q_stop
     }
 }
-
-
-\seq_new:N \l_@@_parse_selector_seq
-\tl_new:N \l_@@_parse_desc_tl
-
-\str_const:Nn \c_@@_parse_nthchild_str { :nth-child( }
-\prop_new:N \c_@@_parse_replace_prop
-\prop_put:Nnn \c_@@_parse_replace_prop { :first-child } { :nth-child(1) }
-
-\cs_new_protected:Nn \@@_parse_selector:Nn {
-    \str_set:Nx \l_tmpa_str {#2}
 %    \end{macrocode}
 %
-%   Replace some aliases with their meaning:
+%   Some pseudo-classes generate conditional code for the properties to be
+%   applied. Check if such code exists, and wrap the parsed property setters
+%   in a \cs{bool_if:nT}.
 %
 %    \begin{macrocode}
-    \prop_map_inline:Nn \c_@@_parse_replace_prop {
-        \use:x {
-            \exp_not:n { \tl_replace_all:Nnn \l_tmpa_str }
-            { \tl_to_str:n { ##1 } } { \tl_to_str:n { ##2 } }
+\tl_new:N \l_@@_current_selector_tl
+\tl_new:N \l_@@_current_selector_check_tl
+\cs_new_protected:Nn \@@_parse_css_addprops:n {
+    \@@_parse_selector:n {#1}
+    \tl_set:Nx \l_tmpa_tl { l_@@_property_group_\l_@@_current_selector_tl _tl }
+    \tl_if_exist:cF { \l_tmpa_tl } { \tl_clear:c { \l_tmpa_tl } }
+    \tl_if_empty:NTF \l_@@_current_selector_check_tl {
+        \tl_put_right:cV { \l_tmpa_tl } \l_@@_parse_properties_tl
+    }{
+        \tl_put_right:cx { \l_tmpa_tl } {
+            \exp_not:N \bool_if:nT {
+                \exp_not:V \l_@@_current_selector_check_tl
+            }{
+                \exp_not:V \l_@@_parse_properties_tl
+            }
         }
     }
+}
 %    \end{macrocode}
 %
-%   Replace all spaces by \cs{q_stop} to defeat the space removal feature of
-%   \cs{seq_set_split:Nnn}.
+%   Here we parse a selector. These are naturally space-separated, but we first
+%   need to detect and normalize constructs like ":nth-child(argument)". We
+%   replace them by ":nth-child{argument}" where the braces will procect any
+%   space that can legitimately occur within "argument".
 %
 %    \begin{macrocode}
-    \tl_replace_all:Nnn \l_tmpa_str {~} {\q_stop}
-    \exp_args:NNVV
-        \seq_set_split:Nnn \l_tmpa_seq \c_@@_parse_nthchild_str \l_tmpa_str
-    \seq_pop_left:NN \l_tmpa_seq \l_tmpa_tl
+\cs_new_protected:Nn \@@_parse_selector_sanitize:n {
+    \exp_args:Nx \@@_parse_selector_sanitize_aux:n
+        { \tl_to_str:n{#1} }
+}
+\cs_new_protected:Nn \@@_parse_selector_sanitize_aux:n {
+    \cs_set:Npn \@@_parse_selector_sanitize:w ##1:#1(##2)##3\q_stop
+    {
+        \quark_if_nil:nTF {##3} {
+            ##1
+        }{
+            ##1:#1{##2}\@@_parse_selector_sanitize:w ##3\q_stop
+        }
+    }
+    \tl_set:Nx \l_@@_current_selector_tl {
+        \exp_last_unbraced:NV
+            \@@_parse_selector_sanitize:w
+            \l_@@_current_selector_tl
+        :#1()\q_nil\q_stop
+    }
+}
 %    \end{macrocode}
 %
-%   And replace them back.
+%   Now that we can sanitize pseudo-classes, parsing the selector is safe. The
+%   only construct to protect is currently ":nth-child()".
 %
 %    \begin{macrocode}
-    \tl_replace_all:Nnn \l_tmpa_tl {\q_stop} {~}
-    \seq_clear:N \l_@@_parse_selector_seq
-    \seq_put_right:NV \l_@@_parse_selector_seq \l_tmpa_tl
-    \seq_map_inline:Nn \l_tmpa_seq {
-        \tl_set:Nn \l_tmpa_tl { ##1 }
+\seq_new:N \l_@@_current_selector_seq
+\seq_new:N \l_@@_pseudoclasses_seq
+\tl_new:N \l_@@_current_element_tl
+\cs_new_protected:Nn \@@_parse_selector:n {
+    \tl_set:Nx \l_@@_current_selector_tl { \tl_to_str:n {#1} }
 %    \end{macrocode}
 %
-%   And replace them back again.
+%   The sanitize code is more readable with Expl category colon, so replace it
+%   now, instead of defining the method with expand or lccode tricks.
 %
 %    \begin{macrocode}
-        \tl_replace_all:Nnn \l_tmpa_tl {\q_stop} {~}
+    \exp_args:NNV \tl_replace_all:Nnn
+        \l_@@_current_selector_tl \c_colon_str {:}
+    \@@_parse_selector_sanitize:n {nth-child}
+    \seq_set_split:NnV \l_@@_current_selector_seq {~} \l_@@_current_selector_tl
+    \tl_clear:N \l_@@_current_selector_tl
+    \tl_clear:N \l_@@_current_selector_check_tl
+    \seq_map_inline:Nn \l_@@_current_selector_seq {
 %    \end{macrocode}
 %
-%   Now replace the first closing parenthesis by \cs{q_stop}\cs{prg_do_nothing:}
-%   to use \cs{q_stop} as a delimiter for \cs{seq_set_split:Nnn} and thus split
-%   at most once. Note that here the space trimming feature is desired for the
-%   left part, but not just at the right of the parenthesis, so
-%   \cs{prg_do_nothing:} will act as a guard and will be removed afterwards.
+%   Split the current selector item on ":" to get the base element and the
+%   pseudo-classes.
 %
 %    \begin{macrocode}
-        \tl_replace_once:Nnn \l_tmpa_tl { ) } { \q_stop\prg_do_nothing: }
-        \seq_set_split:NnV \l_tmpa_seq { \q_stop } \l_tmpa_tl
-        \seq_pop_right:NN \l_tmpa_seq \l_@@_parse_desc_tl
-        \tl_replace_once:Nnn \l_@@_parse_desc_tl { \prg_do_nothing: } {}
-        \seq_get_left:NNT \l_tmpa_seq \l_tmpa_tl {
-            \exp_args:NNV \@@_parse_nth:Nn \l_tmpa_tl \l_tmpa_tl
-            \tl_put_left:Nn \l_@@_parse_desc_tl { ) }
-            \tl_put_left:NV \l_@@_parse_desc_tl \l_tmpa_tl
+        \seq_set_split:Nnn \l_@@_pseudoclasses_seq {:} {##1}
+        \seq_pop_left:NN \l_@@_pseudoclasses_seq \l_@@_current_element_tl
+        \tl_put_right:Nn \l_@@_current_selector_tl {~}
+        \tl_put_right:NV \l_@@_current_selector_tl \l_@@_current_element_tl
+        \seq_map_inline:Nn \l_@@_pseudoclasses_seq {
+            \@@_parse_pseudoclass:w ####1{}\q_stop
         }
-        \seq_put_right:NV \l_@@_parse_selector_seq \l_@@_parse_desc_tl
     }
-    \tl_set:Nx #1 {
-        \exp_args:NNV \seq_use:Nn
-            \l_@@_parse_selector_seq \c_@@_parse_nthchild_str
+}
+%    \end{macrocode}
+%
+%   The first argument is the complete pseudo-class up to the opening argument
+%   brace (if any), and the second argument is the braced content (if any).
+%   The third argument gobbles any trailing garbage.
+%
+%    \begin{macrocode}
+\NewDocumentCommand \@@_parse_pseudoclass:w { lmu{\q_stop} } {
+    \exp_args:Nx \str_case:nn { #1 } {
+        {first-child} { \@@_parse_selector_nth:n {1} }
+        {nth-child} { \@@_parse_selector_nth:n {#2} }
     }
 }
 
 \str_const:Nn \c_@@_parse_n_str {n}
-\seq_new:N \l_@@_used_nth_factors_seq
-\cs_new_protected:Nn \@@_parse_nth:Nn {
-    \str_case:nnF {#2} {
+\int_new:N \l_@@_nth_coeff_int
+\int_new:N \l_@@_nth_offset_int
+\cs_new_protected:Nn \@@_parse_selector_nth:n {
+%    \end{macrocode}
+%
+%   Put something in the selector token list, for specificity ordering
+%   of declarations.
+%
+%    \begin{macrocode}
+    \tl_put_right:Nn \l_@@_current_selector_tl { :nth-child }
+%    \end{macrocode}
+%
+%   Now parse the nth-child argument:
+%
+%    \begin{macrocode}
+    \str_case:nnF {#1} {
         {even} { \str_set:Nn \l_tmpa_str {2n} }
         {odd}  { \str_set:Nn \l_tmpa_str {2n+1} }
     }{
-        \str_set:Nn \l_tmpa_str {#2}
+        \str_set:Nn \l_tmpa_str {#1}
     }
-    \exp_args:NNVV
-        \seq_set_split:Nnn \l_tmpa_seq \c_@@_parse_n_str \l_tmpa_str
+    \exp_args:NNV
+        \seq_set_split:NnV \l_tmpa_seq \c_@@_parse_n_str \l_tmpa_str
     \seq_pop_right:NN \l_tmpa_seq \l_tmpa_tl
-    \int_set:Nn \l_tmpb_int { 0\l_tmpa_tl }
-    \seq_get_left:NNTF \l_tmpa_seq \l_tmpa_tl {
-        \int_set:Nn \l_tmpa_int { 0\l_tmpa_tl }
+    \tl_if_empty:NTF \l_tmpa_tl {
+        \int_zero:N \l_@@_nth_offset_int
     }{
-        \int_zero:N \l_tmpa_int
+        \int_set:Nn \l_@@_nth_offset_int { \l_tmpa_tl }
     }
-    \int_compare:nNnTF \l_tmpa_int = { 0 } {
-        \tl_set:Nx #1 { \int_use:N \l_tmpb_int }
+    \seq_get_left:NNTF \l_tmpa_seq \l_tmpa_tl {
+        \tl_if_empty:NTF \l_tmpa_tl {
+            \int_set:Nn \l_@@_nth_coeff_int {1}
+        }{
+            \exp_args:NV \tl_if_eq:nnTF \l_tmpa_tl {-} {
+                \int_set:Nn \l_@@_nth_coeff_int {-1}
+            }{
+                \int_set:Nn \l_@@_nth_coeff_int { \l_tmpa_tl }
+            }
+        }
     }{
-        \int_set:Nn \l_tmpb_int { \int_mod:nn {\l_tmpb_int} {\l_tmpa_int} }
-        \tl_set:Nx #1 {
-            \int_use:N \l_tmpa_int \exp_not:V \c_@@_parse_n_str
-            + \int_use:N \l_tmpb_int }
-        \seq_put_right:Nx
-            \l_@@_used_nth_factors_seq { \int_use:N \l_tmpa_int }
+        \int_zero:N \l_@@_nth_coeff_int
     }
+%    \end{macrocode}
+%
+%   At last, generate the condition code.
+%
+%    \begin{macrocode}
+    \exp_args:NV \str_case:nn \l_@@_current_element_tl {
+        {tr} { \@@_generate_check_nth:n {\g_@@_row_int} }
+        {td} { \@@_generate_check_nth:n {\g_@@_col_int} }
+    }
 }
 
-\cs_new_protected:Npn \@@_parse_css_addprops:nV #1 #2 {
-    \@@_parse_selector:Nn \l_tmpa_tl {#1}
-    \tl_set:Nx \l_tmpa_tl { l_@@_property_group_\l_tmpa_tl _tl }
-    \tl_if_exist:cF { \l_tmpa_tl } { \tl_clear:c { \l_tmpa_tl } }
-    \tl_put_right:cV { \l_tmpa_tl } #2
+\cs_new_protected_nopar:Nn \@@_generate_check_nth:n {
+    \int_compare:nNnTF \l_@@_nth_coeff_int = { 0 } {
+        \tl_set:Nx \l_tmpa_tl {
+            \exp_not:n { \int_compare_p:nNn #1 = }
+            \exp_not:V \l_@@_nth_offset_int
+        }
+    }{
+        \tl_set:Nx \l_tmpb_tl {
+            {
+                \exp_not:n { #1 - }
+                \exp_not:V \l_@@_nth_offset_int
+            }{
+                \exp_not:V \l_@@_nth_coeff_int
+            }
+        }
+        \tl_set:Nx \l_tmpa_tl {
+            \exp_not:N \bool_lazy_and_p:nn {
+                \exp_not:n { \int_compare_p:nNn 0 = }
+                {
+                    \exp_not:N \int_mod:nn
+                    \exp_not:V \l_tmpb_tl
+                }
+            }{
+                \exp_not:n { \int_compare_p:nNn 0 < }
+                {
+                    \exp_not:N \int_div_truncate:nn
+                    \exp_not:V \l_tmpb_tl
+                    \exp_not:n { + 1 }
+                }
+            }
+        }
+    }
+    \tl_if_empty:NTF \l_@@_current_selector_check_tl {
+        \tl_set_eq:NN \l_@@_current_selector_check_tl \l_tmpa_tl
+    }{
+        \tl_set:Nx \l_@@_current_selector_check_tl {
+            \exp_not:N \bool_lazy_and_p:nn {
+                \exp_not:V \l_@@_current_selector_check_tl
+            }{
+                \exp_not:V \l_tmpa_tl
+            }
+        }
+    }
 }
 
 \cs_set_protected:Nn \@@_recall_properties:n {
-    \tl_if_exist:cT { l_@@_property_group_#1_tl } {
-        \tl_use:c { l_@@_property_group_#1_tl }
+    \tl_if_exist:cT { l_@@_property_group_~#1_tl } {
+        \tl_use:c { l_@@_property_group_~#1_tl }
     }
     \clist_map_inline:nn { \@currenvir } {
-        \tl_if_exist:cT { l_@@_property_group_##1~#1_tl } {
-            \tl_use:c { l_@@_property_group_##1~#1_tl }
+        \tl_if_exist:cT { l_@@_property_group_~##1~#1_tl } {
+            \tl_use:c { l_@@_property_group_~##1~#1_tl }
         }
     }
 }
@@ -897,13 +1090,46 @@
     \hlx{s[\l_@@_tablepadding_top_dim]}
 }
 
+\cs_new_protected_nopar:Nn \@@_maybe_startrow: {
+    \bool_if:NF \g_@@_inrow_bool {
+        \bool_gset_true:N \g_@@_inrow_bool
+        \int_gincr:N \g_@@_row_int
+        \int_gset_eq:NN \g_@@_col_int \c_one_int
+        \dim_gzero:N \g_@@_ht_dim
+        \dim_gzero:N \g_@@_dp_dim
+    }
+}
+
+\cs_new_protected_nopar:Nn \@@_maybe_endrow: {
+    \bool_if:NT \g_@@_inrow_bool {
+        \@@_every_cell_end:
+        \bool_gset_false:N \g_@@_inrow_bool
+    }
+}
+
+\cs_new_protected_nopar:Nn \@@_every_cell_end: {
+    \int_gincr:N \g_@@_col_int
+}
+
 \cs_set_protected_nopar:Nn \@@_readpreamble:n {
     \cs_set_eq:NN \tab at readpreamble \@@_orig_tab at readpreamble:n
-    \tl_put_left:Nn \tab at multicol {\@@_startrow:}
-    \tl_put_left:Nn \tab at tabtext {\int_gincr:N \g_@@_col_int}
+%    \end{macrocode}
+%
+%   \cs{tab at multicol} is inserted at the beginning of a each row, and by
+%   \cs{multicolumn} after its \cs{omit}. We use it to ensure that the row is
+%   initialized correctly however it starts (normally or with a
+%   \cs{multicolumn}).
+%
+%   \cs{tab at tabtext} is inserted at the end of every cell but the last one, so
+%   we should ensure that its effect is applied at the end of the row;
+%   \cs{@@_maybe_endrow} will take care of that.
+%
+%    \begin{macrocode}
+    \tl_put_left:Nn \tab at multicol {\@@_maybe_startrow:}
+    \tl_put_left:Nn \tab at tabtext {\@@_every_cell_end:}
     \tab at readpreamble{#1}
     \exp_args:Nx \tab at preamble
-        { \exp_not:N\@@_startrow: \the\tab at preamble \exp_not:N\@@_endrow: }
+        { \the\tab at preamble \exp_not:N\@@_maybe_endrow: }
 }
 %    \end{macrocode}
 %
@@ -976,24 +1202,8 @@
     \@@_end_array:n { \@@_orig_endLT: }
 }
 
-\cs_new_protected_nopar:Nn \@@_startrow: {
-    \bool_if:NF \g_@@_inrow_bool {
-        \bool_gset_true:N \g_@@_inrow_bool
-        \int_gincr:N \g_@@_row_int
-        \int_gset_eq:NN \g_@@_col_int \c_one_int
-        \dim_gzero:N \g_@@_ht_dim
-        \dim_gzero:N \g_@@_dp_dim
-    }
-}
-
-\cs_new_protected_nopar:Nn \@@_endrow: {
-    \bool_if:NT \g_@@_inrow_bool {
-        \bool_gset_false:N \g_@@_inrow_bool
-    }
-}
-
 \cs_new_protected_nopar:Nn \@@_cr:n {
-    \@@_endrow:
+    \@@_maybe_endrow:
     \tl_if_empty:NF \g_@@_borders_tl {
         \cr
         \noalign{\nobreak}
@@ -1016,10 +1226,12 @@
 
 \cs_set_eq:NN \@@_orig_multicolumn:w \multicolumn
 \cs_set:Npn \multicolumn#1#2#3 {
-    \@@_orig_multicolumn:w {#1}{#2}{
-        #3
-        \int_gadd:Nn \g_@@_col_int {#1}
+    \@@_orig_multicolumn:w {#1}{#2}{#3}
+    \int_gadd:Nn \g_@@_col_int {#1}
+    \tl_gput_right:Nx \g_@@_borders_tl {
+        \prg_replicate:nn {#1 - 1} {\span\omit}
     }
+    \ignorespaces
 }
 
 }
@@ -1110,20 +1322,6 @@
 
 
 \colpop
-%    \end{macrocode}
-%
-% Handle various \verb|:nth-child()| forms.
-%
-%    \begin{macrocode}
-\cs_new_protected_nopar:Nn \@@_seq_nthchild:Nn {
-    \seq_clear:N #1
-    \seq_map_inline:Nn \l_@@_used_nth_factors_seq {
-        \seq_put_right:Nx #1 {
-            ##1 n + \int_eval:n{\int_mod:nn{#2}{##1}}
-        }
-    }
-    \seq_put_right:Nx #1 { \int_eval:n{#2} }
-}
 
 \cs_new_protected_nopar:Nn \@@_begincell:n {
     \@@_begin_raw_cell:n {
@@ -1162,25 +1360,13 @@
             \global\@minipagefalse
             \everypar{}
         }
-        \@@_seq_nthchild:Nn \l_tmpa_seq { \g_@@_row_int }
-        \@@_seq_nthchild:Nn \l_tmpb_seq { \g_@@_col_int }
         \@@_recall_properties:n {td~p}
-        \seq_map_inline:Nn \l_tmpa_seq {
-            \@@_recall_properties:n {tr:nth-child(##1)~p}
-        }
-        \seq_map_inline:Nn \l_tmpb_seq {
-            \@@_recall_properties:n {td:nth-child(##1)~p}
-        }
         \@@_recall_properties:n {tr~td~p}
-        \seq_map_inline:Nn \l_tmpa_seq {
-            \@@_recall_properties:n {tr:nth-child(##1)~td~p}
-        }
-        \seq_map_inline:Nn \l_tmpa_seq {
-            \seq_map_inline:Nn \l_tmpb_seq {
-                \@@_recall_properties:n {tr:nth-child(##1)~
-                                         td:nth-child(####1)~p}
-            }
-        }
+        \@@_recall_properties:n {tr:nth-child~p}
+        \@@_recall_properties:n {td:nth-child~p}
+        \@@_recall_properties:n {tr:nth-child~td~p}
+        \@@_recall_properties:n {tr~td:nth-child~p}
+        \@@_recall_properties:n {tr:nth-child~td:nth-child~p}
     }
 }
 \cs_new_protected_nopar:Nn \@@_end_par_cell:n {
@@ -1195,26 +1381,14 @@
 
 \cs_new_protected_nopar:Nn \@@_begin_raw_cell:n {
     \group_begin:
-    \@@_seq_nthchild:Nn \l_tmpa_seq { \g_@@_row_int }
-    \@@_seq_nthchild:Nn \l_tmpb_seq { \g_@@_col_int }
-    \seq_map_inline:Nn \l_tmpa_seq {
-        \@@_recall_properties:n {tr:nth-child(##1)}
-    }
+    \@@_recall_properties:n {tr:nth-child}
     \@@_update_colors:
     \@@_recall_properties:n {td}
     \@@_recall_properties:n {tr~td}
-    \seq_map_inline:Nn \l_tmpb_seq {
-        \@@_recall_properties:n {td:nth-child(##1)}
-    }
-    \seq_map_inline:Nn \l_tmpa_seq {
-        \@@_recall_properties:n {tr:nth-child(##1)~td}
-    }
-    \seq_map_inline:Nn \l_tmpa_seq {
-        \seq_map_inline:Nn \l_tmpb_seq {
-            \@@_recall_properties:n {tr:nth-child(##1)~
-                                     td:nth-child(####1)}
-        }
-    }
+    \@@_recall_properties:n {td:nth-child}
+    \@@_recall_properties:n {tr:nth-child~td}
+    \@@_recall_properties:n {tr~td:nth-child}
+    \@@_recall_properties:n {tr:nth-child~td:nth-child}
     \@@_update_colors:
     % Additional init code
     #1

Modified: trunk/Master/texmf-dist/source/latex/cellprops/cellprops.ins
===================================================================
--- trunk/Master/texmf-dist/source/latex/cellprops/cellprops.ins	2020-06-08 21:18:36 UTC (rev 55482)
+++ trunk/Master/texmf-dist/source/latex/cellprops/cellprops.ins	2020-06-08 21:18:51 UTC (rev 55483)
@@ -1,6 +1,6 @@
 \iffalse meta-comment
 
-File cellprops.ins (C) Copyright 2016-2019 RIVAUD Julien
+File cellprops.ins (C) Copyright 2016-2020 RIVAUD Julien
 
 It may be distributed and/or modified under the conditions of the
 General Public License (GPL), either version 3 of this

Modified: trunk/Master/texmf-dist/tex/latex/cellprops/cellprops.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/cellprops/cellprops.sty	2020-06-08 21:18:36 UTC (rev 55482)
+++ trunk/Master/texmf-dist/tex/latex/cellprops/cellprops.sty	2020-06-08 21:18:51 UTC (rev 55483)
@@ -6,7 +6,7 @@
 %%
 %% cellprops.dtx  (with options: `package')
 %% 
-%% File: cellprops.dtx (C) Copyright 2016-2019 RIVAUD Julien
+%% File: cellprops.dtx (C) Copyright 2016-2020 RIVAUD Julien
 %%
 %% It may be distributed and/or modified under the conditions of the
 %% General Public License (GPL), either version 3 of this
@@ -15,8 +15,8 @@
 \RequirePackage{expl3}[2018/06/19]
 \def\ExplFileName{cellprops}
 \def\ExplFileDescription{CSS-like cell and table properties}
-\def\ExplFileDate{2019/09/29}
-\def\ExplFileVersion{1.6}
+\def\ExplFileDate{2020/06/07}
+\def\ExplFileVersion{1.7a}
 \ProvidesExplPackage
   {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
 
@@ -79,7 +79,6 @@
         }
     }
 }
-
 \cs_new:Nn \__cellprops_fourval_setter:nnnnnn {
     \__cellprops_fourval_setter_aux:w
         {#1}{#2}{#3}{#4}#6~{\q_no_value}~{\q_no_value}~{\q_no_value}~\q_stop
@@ -112,7 +111,6 @@
         #2
     }
 }
-
 \tl_const:Nn \c__cellprops_inherit_color_tl { \q_nil }
 
 \cs_new_nopar:Nn \__cellprops_color_setter:nn {
@@ -142,7 +140,6 @@
         \__cellprops_color_setter:nn {#1} {#2}
     }
 }
-
 \cs_new_nopar:Nn \__cellprops_linewidth_setter:nn {
     \str_case:nnF {#2} {
         {thin}   { \__cellprops_generic_setter:nnn \exp_not:n {#1} { \fboxrule} }
@@ -152,7 +149,6 @@
         \__cellprops_generic_setter:nnn \exp_not:n {#1} {#2}
     }
 }
-
 \cs_new_nopar:Nn \__cellprops_border_setter:nn {
     \__cellprops_border_setter_aux:nw
         {#1}#2~{\q_no_value}~{\q_no_value}~\q_stop
@@ -188,6 +184,7 @@
         \__cellprops_delegate_setter:nn {#1-color} {#4}
     }
 }
+
 \cs_new:Npn \__cellprops_border_setter_isstyle:nTF #1 {
     \str_case:nnTF {#1} {
         {none}{} {hidden}{} {dotted}{} {dashed}{} {solid}{}
@@ -194,7 +191,6 @@
         {double}{} {groove}{} {ridge}{} {inset}{} {outset}{}
     }
 }
-
 \__cellprops_define_properties:nn {
     \__cellprops_generic_setter:nnn \exp_not:n
 }{
@@ -202,12 +198,10 @@
     min-depth,
     min-width,
 }
-
 \__cellprops_define_fourval_properties:nnnnnn
     { \__cellprops_generic_setter:nnn \exp_not:n }
     {padding}
     {padding-top}{padding-right}{padding-bottom}{padding-left}
-
 \__cellprops_define_properties:nn {
     \__cellprops_generic_setter:nnn \tl_to_str:n
 }{
@@ -214,7 +208,6 @@
     text-align,
     math-mode,
 }
-
 \__cellprops_define_properties:nn {
     \__cellprops_color_setter:nn
 }{
@@ -226,31 +219,26 @@
 }{
     background-color,
 }
-
 \__cellprops_define_fourval_properties:nnnnnn
     { \__cellprops_linewidth_setter:nn }
     {border-width}
     {border-top-width}{border-right-width}
     {border-bottom-width}{border-left-width}
-
 \__cellprops_define_fourval_properties:nnnnnn
     { \__cellprops_generic_setter:nnn \tl_to_str:n }
     {border-style}
     {border-top-style}{border-right-style}
     {border-bottom-style}{border-left-style}
-
 \__cellprops_define_fourval_properties:nnnnnn
     { \__cellprops_color_setter:nn }
     {border-color}
     {border-top-color}{border-right-color}
     {border-bottom-color}{border-left-color}
-
 \__cellprops_define_properties:nn {
     \__cellprops_border_setter:nn
 }{
     border, border-top, border-right, border-bottom, border-left
 }
-
 \NewDocumentCommand \cellprops { m } {
     \__cellprops_parse_css:n {#1}
 }
@@ -258,104 +246,172 @@
 \cs_new_protected:Nn \__cellprops_parse_css:n {
     \__cellprops_parse_css:w #1 \q_mark {\q_nil} \q_stop
 }
-
-\tl_new:N \l__cellprops_parse_tmp_tl
+\tl_new:N \l__cellprops_parse_properties_tl
 \NewDocumentCommand \__cellprops_parse_css:w { lmu{\q_stop} } {
     \quark_if_nil:nF {#2} {
-        \__cellprops_parse_properties:Nn \l__cellprops_parse_tmp_tl {#2}
+        \__cellprops_parse_properties:Nn \l__cellprops_parse_properties_tl {#2}
         \clist_map_inline:nn {#1} {
-            \__cellprops_parse_css_addprops:nV {##1} \l__cellprops_parse_tmp_tl
+            \__cellprops_parse_css_addprops:n {##1}
         }
         \__cellprops_parse_css:w #3 \q_stop
     }
 }
-
-\seq_new:N \l__cellprops_parse_selector_seq
-\tl_new:N \l__cellprops_parse_desc_tl
-
-\str_const:Nn \c__cellprops_parse_nthchild_str { :nth-child( }
-\prop_new:N \c__cellprops_parse_replace_prop
-\prop_put:Nnn \c__cellprops_parse_replace_prop { :first-child } { :nth-child(1) }
-
-\cs_new_protected:Nn \__cellprops_parse_selector:Nn {
-    \str_set:Nx \l_tmpa_str {#2}
-    \prop_map_inline:Nn \c__cellprops_parse_replace_prop {
-        \use:x {
-            \exp_not:n { \tl_replace_all:Nnn \l_tmpa_str }
-            { \tl_to_str:n { ##1 } } { \tl_to_str:n { ##2 } }
+\tl_new:N \l__cellprops_current_selector_tl
+\tl_new:N \l__cellprops_current_selector_check_tl
+\cs_new_protected:Nn \__cellprops_parse_css_addprops:n {
+    \__cellprops_parse_selector:n {#1}
+    \tl_set:Nx \l_tmpa_tl { l__cellprops_property_group_\l__cellprops_current_selector_tl _tl }
+    \tl_if_exist:cF { \l_tmpa_tl } { \tl_clear:c { \l_tmpa_tl } }
+    \tl_if_empty:NTF \l__cellprops_current_selector_check_tl {
+        \tl_put_right:cV { \l_tmpa_tl } \l__cellprops_parse_properties_tl
+    }{
+        \tl_put_right:cx { \l_tmpa_tl } {
+            \exp_not:N \bool_if:nT {
+                \exp_not:V \l__cellprops_current_selector_check_tl
+            }{
+                \exp_not:V \l__cellprops_parse_properties_tl
+            }
         }
     }
-    \tl_replace_all:Nnn \l_tmpa_str {~} {\q_stop}
-    \exp_args:NNVV
-        \seq_set_split:Nnn \l_tmpa_seq \c__cellprops_parse_nthchild_str \l_tmpa_str
-    \seq_pop_left:NN \l_tmpa_seq \l_tmpa_tl
-    \tl_replace_all:Nnn \l_tmpa_tl {\q_stop} {~}
-    \seq_clear:N \l__cellprops_parse_selector_seq
-    \seq_put_right:NV \l__cellprops_parse_selector_seq \l_tmpa_tl
-    \seq_map_inline:Nn \l_tmpa_seq {
-        \tl_set:Nn \l_tmpa_tl { ##1 }
-        \tl_replace_all:Nnn \l_tmpa_tl {\q_stop} {~}
-        \tl_replace_once:Nnn \l_tmpa_tl { ) } { \q_stop\prg_do_nothing: }
-        \seq_set_split:NnV \l_tmpa_seq { \q_stop } \l_tmpa_tl
-        \seq_pop_right:NN \l_tmpa_seq \l__cellprops_parse_desc_tl
-        \tl_replace_once:Nnn \l__cellprops_parse_desc_tl { \prg_do_nothing: } {}
-        \seq_get_left:NNT \l_tmpa_seq \l_tmpa_tl {
-            \exp_args:NNV \__cellprops_parse_nth:Nn \l_tmpa_tl \l_tmpa_tl
-            \tl_put_left:Nn \l__cellprops_parse_desc_tl { ) }
-            \tl_put_left:NV \l__cellprops_parse_desc_tl \l_tmpa_tl
+}
+\cs_new_protected:Nn \__cellprops_parse_selector_sanitize:n {
+    \exp_args:Nx \__cellprops_parse_selector_sanitize_aux:n
+        { \tl_to_str:n{#1} }
+}
+\cs_new_protected:Nn \__cellprops_parse_selector_sanitize_aux:n {
+    \cs_set:Npn \__cellprops_parse_selector_sanitize:w ##1:#1(##2)##3\q_stop
+    {
+        \quark_if_nil:nTF {##3} {
+            ##1
+        }{
+            ##1:#1{##2}\__cellprops_parse_selector_sanitize:w ##3\q_stop
         }
-        \seq_put_right:NV \l__cellprops_parse_selector_seq \l__cellprops_parse_desc_tl
     }
-    \tl_set:Nx #1 {
-        \exp_args:NNV \seq_use:Nn
-            \l__cellprops_parse_selector_seq \c__cellprops_parse_nthchild_str
+    \tl_set:Nx \l__cellprops_current_selector_tl {
+        \exp_last_unbraced:NV
+            \__cellprops_parse_selector_sanitize:w
+            \l__cellprops_current_selector_tl
+        :#1()\q_nil\q_stop
     }
 }
+\seq_new:N \l__cellprops_current_selector_seq
+\seq_new:N \l__cellprops_pseudoclasses_seq
+\tl_new:N \l__cellprops_current_element_tl
+\cs_new_protected:Nn \__cellprops_parse_selector:n {
+    \tl_set:Nx \l__cellprops_current_selector_tl { \tl_to_str:n {#1} }
+    \exp_args:NNV \tl_replace_all:Nnn
+        \l__cellprops_current_selector_tl \c_colon_str {:}
+    \__cellprops_parse_selector_sanitize:n {nth-child}
+    \seq_set_split:NnV \l__cellprops_current_selector_seq {~} \l__cellprops_current_selector_tl
+    \tl_clear:N \l__cellprops_current_selector_tl
+    \tl_clear:N \l__cellprops_current_selector_check_tl
+    \seq_map_inline:Nn \l__cellprops_current_selector_seq {
+        \seq_set_split:Nnn \l__cellprops_pseudoclasses_seq {:} {##1}
+        \seq_pop_left:NN \l__cellprops_pseudoclasses_seq \l__cellprops_current_element_tl
+        \tl_put_right:Nn \l__cellprops_current_selector_tl {~}
+        \tl_put_right:NV \l__cellprops_current_selector_tl \l__cellprops_current_element_tl
+        \seq_map_inline:Nn \l__cellprops_pseudoclasses_seq {
+            \__cellprops_parse_pseudoclass:w ####1{}\q_stop
+        }
+    }
+}
+\NewDocumentCommand \__cellprops_parse_pseudoclass:w { lmu{\q_stop} } {
+    \exp_args:Nx \str_case:nn { #1 } {
+        {first-child} { \__cellprops_parse_selector_nth:n {1} }
+        {nth-child} { \__cellprops_parse_selector_nth:n {#2} }
+    }
+}
 
 \str_const:Nn \c__cellprops_parse_n_str {n}
-\seq_new:N \l__cellprops_used_nth_factors_seq
-\cs_new_protected:Nn \__cellprops_parse_nth:Nn {
-    \str_case:nnF {#2} {
+\int_new:N \l__cellprops_nth_coeff_int
+\int_new:N \l__cellprops_nth_offset_int
+\cs_new_protected:Nn \__cellprops_parse_selector_nth:n {
+    \tl_put_right:Nn \l__cellprops_current_selector_tl { :nth-child }
+    \str_case:nnF {#1} {
         {even} { \str_set:Nn \l_tmpa_str {2n} }
         {odd}  { \str_set:Nn \l_tmpa_str {2n+1} }
     }{
-        \str_set:Nn \l_tmpa_str {#2}
+        \str_set:Nn \l_tmpa_str {#1}
     }
-    \exp_args:NNVV
-        \seq_set_split:Nnn \l_tmpa_seq \c__cellprops_parse_n_str \l_tmpa_str
+    \exp_args:NNV
+        \seq_set_split:NnV \l_tmpa_seq \c__cellprops_parse_n_str \l_tmpa_str
     \seq_pop_right:NN \l_tmpa_seq \l_tmpa_tl
-    \int_set:Nn \l_tmpb_int { 0\l_tmpa_tl }
-    \seq_get_left:NNTF \l_tmpa_seq \l_tmpa_tl {
-        \int_set:Nn \l_tmpa_int { 0\l_tmpa_tl }
+    \tl_if_empty:NTF \l_tmpa_tl {
+        \int_zero:N \l__cellprops_nth_offset_int
     }{
-        \int_zero:N \l_tmpa_int
+        \int_set:Nn \l__cellprops_nth_offset_int { \l_tmpa_tl }
     }
-    \int_compare:nNnTF \l_tmpa_int = { 0 } {
-        \tl_set:Nx #1 { \int_use:N \l_tmpb_int }
+    \seq_get_left:NNTF \l_tmpa_seq \l_tmpa_tl {
+        \tl_if_empty:NTF \l_tmpa_tl {
+            \int_set:Nn \l__cellprops_nth_coeff_int {1}
+        }{
+            \exp_args:NV \tl_if_eq:nnTF \l_tmpa_tl {-} {
+                \int_set:Nn \l__cellprops_nth_coeff_int {-1}
+            }{
+                \int_set:Nn \l__cellprops_nth_coeff_int { \l_tmpa_tl }
+            }
+        }
     }{
-        \int_set:Nn \l_tmpb_int { \int_mod:nn {\l_tmpb_int} {\l_tmpa_int} }
-        \tl_set:Nx #1 {
-            \int_use:N \l_tmpa_int \exp_not:V \c__cellprops_parse_n_str
-            + \int_use:N \l_tmpb_int }
-        \seq_put_right:Nx
-            \l__cellprops_used_nth_factors_seq { \int_use:N \l_tmpa_int }
+        \int_zero:N \l__cellprops_nth_coeff_int
     }
+    \exp_args:NV \str_case:nn \l__cellprops_current_element_tl {
+        {tr} { \__cellprops_generate_check_nth:n {\g__cellprops_row_int} }
+        {td} { \__cellprops_generate_check_nth:n {\g__cellprops_col_int} }
+    }
 }
 
-\cs_new_protected:Npn \__cellprops_parse_css_addprops:nV #1 #2 {
-    \__cellprops_parse_selector:Nn \l_tmpa_tl {#1}
-    \tl_set:Nx \l_tmpa_tl { l__cellprops_property_group_\l_tmpa_tl _tl }
-    \tl_if_exist:cF { \l_tmpa_tl } { \tl_clear:c { \l_tmpa_tl } }
-    \tl_put_right:cV { \l_tmpa_tl } #2
+\cs_new_protected_nopar:Nn \__cellprops_generate_check_nth:n {
+    \int_compare:nNnTF \l__cellprops_nth_coeff_int = { 0 } {
+        \tl_set:Nx \l_tmpa_tl {
+            \exp_not:n { \int_compare_p:nNn #1 = }
+            \exp_not:V \l__cellprops_nth_offset_int
+        }
+    }{
+        \tl_set:Nx \l_tmpb_tl {
+            {
+                \exp_not:n { #1 - }
+                \exp_not:V \l__cellprops_nth_offset_int
+            }{
+                \exp_not:V \l__cellprops_nth_coeff_int
+            }
+        }
+        \tl_set:Nx \l_tmpa_tl {
+            \exp_not:N \bool_lazy_and_p:nn {
+                \exp_not:n { \int_compare_p:nNn 0 = }
+                {
+                    \exp_not:N \int_mod:nn
+                    \exp_not:V \l_tmpb_tl
+                }
+            }{
+                \exp_not:n { \int_compare_p:nNn 0 < }
+                {
+                    \exp_not:N \int_div_truncate:nn
+                    \exp_not:V \l_tmpb_tl
+                    \exp_not:n { + 1 }
+                }
+            }
+        }
+    }
+    \tl_if_empty:NTF \l__cellprops_current_selector_check_tl {
+        \tl_set_eq:NN \l__cellprops_current_selector_check_tl \l_tmpa_tl
+    }{
+        \tl_set:Nx \l__cellprops_current_selector_check_tl {
+            \exp_not:N \bool_lazy_and_p:nn {
+                \exp_not:V \l__cellprops_current_selector_check_tl
+            }{
+                \exp_not:V \l_tmpa_tl
+            }
+        }
+    }
 }
 
 \cs_set_protected:Nn \__cellprops_recall_properties:n {
-    \tl_if_exist:cT { l__cellprops_property_group_#1_tl } {
-        \tl_use:c { l__cellprops_property_group_#1_tl }
+    \tl_if_exist:cT { l__cellprops_property_group_~#1_tl } {
+        \tl_use:c { l__cellprops_property_group_~#1_tl }
     }
     \clist_map_inline:nn { \@currenvir } {
-        \tl_if_exist:cT { l__cellprops_property_group_##1~#1_tl } {
-            \tl_use:c { l__cellprops_property_group_##1~#1_tl }
+        \tl_if_exist:cT { l__cellprops_property_group_~##1~#1_tl } {
+            \tl_use:c { l__cellprops_property_group_~##1~#1_tl }
         }
     }
 }
@@ -456,13 +512,34 @@
     \hlx{s[\l__cellprops_tablepadding_top_dim]}
 }
 
+\cs_new_protected_nopar:Nn \__cellprops_maybe_startrow: {
+    \bool_if:NF \g__cellprops_inrow_bool {
+        \bool_gset_true:N \g__cellprops_inrow_bool
+        \int_gincr:N \g__cellprops_row_int
+        \int_gset_eq:NN \g__cellprops_col_int \c_one_int
+        \dim_gzero:N \g__cellprops_ht_dim
+        \dim_gzero:N \g__cellprops_dp_dim
+    }
+}
+
+\cs_new_protected_nopar:Nn \__cellprops_maybe_endrow: {
+    \bool_if:NT \g__cellprops_inrow_bool {
+        \__cellprops_every_cell_end:
+        \bool_gset_false:N \g__cellprops_inrow_bool
+    }
+}
+
+\cs_new_protected_nopar:Nn \__cellprops_every_cell_end: {
+    \int_gincr:N \g__cellprops_col_int
+}
+
 \cs_set_protected_nopar:Nn \__cellprops_readpreamble:n {
     \cs_set_eq:NN \tab at readpreamble \__cellprops_orig_tab at readpreamble:n
-    \tl_put_left:Nn \tab at multicol {\__cellprops_startrow:}
-    \tl_put_left:Nn \tab at tabtext {\int_gincr:N \g__cellprops_col_int}
+    \tl_put_left:Nn \tab at multicol {\__cellprops_maybe_startrow:}
+    \tl_put_left:Nn \tab at tabtext {\__cellprops_every_cell_end:}
     \tab at readpreamble{#1}
     \exp_args:Nx \tab at preamble
-        { \exp_not:N\__cellprops_startrow: \the\tab at preamble \exp_not:N\__cellprops_endrow: }
+        { \the\tab at preamble \exp_not:N\__cellprops_maybe_endrow: }
 }
 \cs_new_protected_nopar:Nn \__cellprops_update_color:Nn {
     \__cellprops_get_property:nN {#2} \l_tmpa_tl
@@ -517,24 +594,8 @@
     \__cellprops_end_array:n { \__cellprops_orig_endLT: }
 }
 
-\cs_new_protected_nopar:Nn \__cellprops_startrow: {
-    \bool_if:NF \g__cellprops_inrow_bool {
-        \bool_gset_true:N \g__cellprops_inrow_bool
-        \int_gincr:N \g__cellprops_row_int
-        \int_gset_eq:NN \g__cellprops_col_int \c_one_int
-        \dim_gzero:N \g__cellprops_ht_dim
-        \dim_gzero:N \g__cellprops_dp_dim
-    }
-}
-
-\cs_new_protected_nopar:Nn \__cellprops_endrow: {
-    \bool_if:NT \g__cellprops_inrow_bool {
-        \bool_gset_false:N \g__cellprops_inrow_bool
-    }
-}
-
 \cs_new_protected_nopar:Nn \__cellprops_cr:n {
-    \__cellprops_endrow:
+    \__cellprops_maybe_endrow:
     \tl_if_empty:NF \g__cellprops_borders_tl {
         \cr
         \noalign{\nobreak}
@@ -557,10 +618,12 @@
 
 \cs_set_eq:NN \__cellprops_orig_multicolumn:w \multicolumn
 \cs_set:Npn \multicolumn#1#2#3 {
-    \__cellprops_orig_multicolumn:w {#1}{#2}{
-        #3
-        \int_gadd:Nn \g__cellprops_col_int {#1}
+    \__cellprops_orig_multicolumn:w {#1}{#2}{#3}
+    \int_gadd:Nn \g__cellprops_col_int {#1}
+    \tl_gput_right:Nx \g__cellprops_borders_tl {
+        \prg_replicate:nn {#1 - 1} {\span\omit}
     }
+    \ignorespaces
 }
 
 }
@@ -643,15 +706,6 @@
 }}
 
 \colpop
-\cs_new_protected_nopar:Nn \__cellprops_seq_nthchild:Nn {
-    \seq_clear:N #1
-    \seq_map_inline:Nn \l__cellprops_used_nth_factors_seq {
-        \seq_put_right:Nx #1 {
-            ##1 n + \int_eval:n{\int_mod:nn{#2}{##1}}
-        }
-    }
-    \seq_put_right:Nx #1 { \int_eval:n{#2} }
-}
 
 \cs_new_protected_nopar:Nn \__cellprops_begincell:n {
     \__cellprops_begin_raw_cell:n {
@@ -690,25 +744,13 @@
             \global\@minipagefalse
             \everypar{}
         }
-        \__cellprops_seq_nthchild:Nn \l_tmpa_seq { \g__cellprops_row_int }
-        \__cellprops_seq_nthchild:Nn \l_tmpb_seq { \g__cellprops_col_int }
         \__cellprops_recall_properties:n {td~p}
-        \seq_map_inline:Nn \l_tmpa_seq {
-            \__cellprops_recall_properties:n {tr:nth-child(##1)~p}
-        }
-        \seq_map_inline:Nn \l_tmpb_seq {
-            \__cellprops_recall_properties:n {td:nth-child(##1)~p}
-        }
         \__cellprops_recall_properties:n {tr~td~p}
-        \seq_map_inline:Nn \l_tmpa_seq {
-            \__cellprops_recall_properties:n {tr:nth-child(##1)~td~p}
-        }
-        \seq_map_inline:Nn \l_tmpa_seq {
-            \seq_map_inline:Nn \l_tmpb_seq {
-                \__cellprops_recall_properties:n {tr:nth-child(##1)~
-                                         td:nth-child(####1)~p}
-            }
-        }
+        \__cellprops_recall_properties:n {tr:nth-child~p}
+        \__cellprops_recall_properties:n {td:nth-child~p}
+        \__cellprops_recall_properties:n {tr:nth-child~td~p}
+        \__cellprops_recall_properties:n {tr~td:nth-child~p}
+        \__cellprops_recall_properties:n {tr:nth-child~td:nth-child~p}
     }
 }
 \cs_new_protected_nopar:Nn \__cellprops_end_par_cell:n {
@@ -723,26 +765,14 @@
 
 \cs_new_protected_nopar:Nn \__cellprops_begin_raw_cell:n {
     \group_begin:
-    \__cellprops_seq_nthchild:Nn \l_tmpa_seq { \g__cellprops_row_int }
-    \__cellprops_seq_nthchild:Nn \l_tmpb_seq { \g__cellprops_col_int }
-    \seq_map_inline:Nn \l_tmpa_seq {
-        \__cellprops_recall_properties:n {tr:nth-child(##1)}
-    }
+    \__cellprops_recall_properties:n {tr:nth-child}
     \__cellprops_update_colors:
     \__cellprops_recall_properties:n {td}
     \__cellprops_recall_properties:n {tr~td}
-    \seq_map_inline:Nn \l_tmpb_seq {
-        \__cellprops_recall_properties:n {td:nth-child(##1)}
-    }
-    \seq_map_inline:Nn \l_tmpa_seq {
-        \__cellprops_recall_properties:n {tr:nth-child(##1)~td}
-    }
-    \seq_map_inline:Nn \l_tmpa_seq {
-        \seq_map_inline:Nn \l_tmpb_seq {
-            \__cellprops_recall_properties:n {tr:nth-child(##1)~
-                                     td:nth-child(####1)}
-        }
-    }
+    \__cellprops_recall_properties:n {td:nth-child}
+    \__cellprops_recall_properties:n {tr:nth-child~td}
+    \__cellprops_recall_properties:n {tr~td:nth-child}
+    \__cellprops_recall_properties:n {tr:nth-child~td:nth-child}
     \__cellprops_update_colors:
     % Additional init code
     #1



More information about the tex-live-commits mailing list.