diff --git a/doc/environments/groupthm/groupthm.dtx b/doc/environments/groupthm/groupthm.dtx index e8d2e03..82d05c4 100644 --- a/doc/environments/groupthm/groupthm.dtx +++ b/doc/environments/groupthm/groupthm.dtx @@ -692,98 +692,49 @@ % \subsection{Theorem groups} % % -% \begin{function}{\groupthm_new_theorem_group_by_keys:nn} +% \begin{function} +% { +% \groupthm_new_theorem_group_by_keys:nn, +% \groupthm_renew_theorem_group_by_keys:nn, +% \groupthm_provide_theorem_group_by_keys:nn, +% \groupthm_declare_theorem_group_by_keys:nn +% } % \begin{syntax} % \cs{groupthm_new_theorem_group_by_keys:nn}\ma{keys}\ma{theorem group} % \end{syntax} % -% \LaTeX3 version of \cs{NewTheoremGroup} +% \LaTeX3 versions of \cs{NewTheoremGroup}, \cs{RenewTheoremGroup}, +% \cs{ProvideTheoremGroup} and \cs{DeclareTheoremGroup} % % \end{function} % % % -% \begin{function}{\groupthm_renew_theorem_group_by_keys:nn} -% \begin{syntax} -% \cs{groupthm_renew_theorem_group_by_keys:nn}\ma{keys} -% \ma{theorem group} -% \end{syntax} -% -% \LaTeX3 version of \cs{RenewTheoremGroup} -% -% \end{function} -% -% -% -% \begin{function}{\groupthm_provide_theorem_group_by_keys:nn} -% \begin{syntax} -% \cs{groupthm_provide_theorem_group_by_keys:nn} -% \ma{keys}\ma{theorem group} -% \end{syntax} -% -% \LaTeX3 version of \cs{ProvideTheoremGroup} -% -% \end{function} -% -% -% -% \begin{function}{\groupthm_declare_theorem_group_by_keys:nn} -% \begin{syntax} -% \cs{groupthm_declare_theorem_group_by_keys:nn} -% \ma{keys}\ma{theorem group} -% \end{syntax} -% -% \LaTeX3 version of \cs{DeclareTheoremGroup} -% -% \end{function} -% -% -% -% \begin{function}{\groupthm_new_theorem_group:nnnnn, \groupthm_new_theorem_group:nVVVV} +% \begin{function} +% { +% \groupthm_new_theorem_group:nnnnn, +% \groupthm_renew_theorem_group:nnnnn, +% \groupthm_provide_theorem_group:nnnnn, +% \groupthm_declare_theorem_group:nnnnn, +% \groupthm_new_theorem_group:nVVVV, +% \groupthm_renew_theorem_group:nVVVV, +% \groupthm_provide_theorem_group:nVVVV, +% \groupthm_declare_theorem_group:nVVVV +% } % \begin{syntax} % \cs{groupthm_new_theorem_group:nnnnn}\ma{theorem group}\ma{prename tl} % \ma{postname tl}\ma{mapname clist}\ma{thmtools clist} % \end{syntax} % -% Non-keyval version of \cs{groupthm_new_theorem_group_by_keys:nn} +% Non-keyval versions of +% \cs{groupthm_new_theorem_group_by_keys:nn}, +% \cs{groupthm_renew_theorem_group_by_keys:nn}, +% \cs{groupthm_provide_theorem_group_by_keys:nn} +% and +% \cs{groupthm_declare_theorem_group_by_keys:nn} % % \end{function} % -% -% -% \begin{function}{\groupthm_renew_theorem_group:nnnnn, \groupthm_renew_theorem_group:nVVVV} -% \begin{syntax} -% \cs{groupthm_renew_theorem_group:nnnnn}\ma{theorem group}\ma{prename tl} -% \ma{postname tl}\ma{mapname clist}\ma{thmtools clist} -% \end{syntax} -% -% Non-keyval version of \cs{groupthm_renew_theorem_group_by_keys:nn} -% -% \end{function} -% -% -% \begin{function}{\groupthm_provide_theorem_group:nnnnn, \groupthm_provide_theorem_group:nVVVV} -% \begin{syntax} -% \cs{groupthm_provide_theorem_group:nnnnn}\ma{theorem group}\ma{prename tl} -% \ma{postname tl}\ma{mapname clist}\ma{thmtools clist} -% \end{syntax} -% -% Non-keyval version of \cs{groupthm_provide_theorem_group_by_keys:nn} -% -% \end{function} -% -% -% \begin{function}{\groupthm_declare_theorem_group:nnnnn, \groupthm_declare_theorem_group:nVVVV} -% \begin{syntax} -% \cs{groupthm_declare_theorem_group:nnnnn}\ma{theorem group}\ma{prename tl} -% \ma{postname tl}\ma{mapname clist}\ma{thmtools clist} -% \end{syntax} -% -% Non-keyval version of \cs{groupthm_declare_theorem_group_by_keys:nn} -% -% \end{function} -% -% % % \begin{function}{\groupthm_declare_theorem_group_rule:nnnn} % \begin{syntax} @@ -1599,11 +1550,363 @@ } % \end{macrocode} % \end{macro} +% + % \subsection{Iterating over powersets} +% For generating the different variants of a theorem family, +% we need to iterate over over the powerset of some list. +% This is a collection of hacks that perform exactly this, +% but these are poorly documented for now. +% +% +% \begin{macro}{\@@_powerset_clist_foreach:Nn} +% \begin{syntax} +% \cs{@@_powerset_clist_foreach:Nn}\meta{clist}\ma{code} +% \end{syntax} +% +% Executes \meta{code} for each subset of the given clist variable. +% The value of the (local) variable is changes throughout the iteration, +% and is thus available regularly in \meta{code}. +% Its value is restored at the end of the iteration. +% +% \begin{macrocode} +\clist_new:N \l_powerset_copied_clist +\seq_new:N \l_powerset_saved_seq +\cs_generate_variant:Nn \clist_remove_all:Nn { N V } +\cs_new:Npn \__powerset_clist_foreach_aux:Nn #1 #2 + { + \clist_if_empty:NTF \l_powerset_copied_clist + { + #2 + } + { + \clist_get:NN \l_powerset_copied_clist \l_tmpa_tl + \seq_push:NV \l_powerset_saved_seq \l_tmpa_tl + \clist_pop:NN \l_powerset_copied_clist { \l_tmpa_tl } + + \__powerset_clist_foreach_aux:Nn #1 {#2} + + \seq_get:NN \l_powerset_saved_seq \l_tmpa_tl + \clist_put_left:NV #1 \l_tmpa_tl + + \__powerset_clist_foreach_aux:Nn #1 {#2} + + \seq_get:NN \l_powerset_saved_seq \l_tmpa_tl + \clist_remove_all:NV #1 \l_tmpa_tl + \clist_push:NV \l_powerset_copied_clist \l_tmpa_tl + \seq_pop:NN \l_powerset_saved_seq \l_tmpa_tl + } + } +\cs_new:Npn \powerset_clist_foreach:Nn #1 #2 + { + \clist_set_eq:NN \l_powerset_copied_clist #1 + \clist_clear:N #1 + \clist_remove_duplicates:N \l_powerset_copied_clist + \__powerset_clist_foreach_aux:Nn #1 {#2} + \clist_set_eq:NN #1 \l_powerset_copied_clist + } +% \end{macrocode} +% \end{macro} +% +% % % % \subsection{Grouped Theorems} % % +% \begin{macro}{\@@_use_theorem_group:n} +% \begin{syntax} +% \cs{@@_use_theorem_group:n}\meta{theorem group} +% \end{syntax} +% +% Uses this theorem group, i.e.~applies its definition by writing +% to the internal hooks. +% A proper error message is emitted if the group is not defined. +% +% \begin{macrocode} +\cs_new:Npn \@@_use_theorem_group:n #1 + { + \cs_if_exist_use:cF { @@_use_group_#1: } + { + \msg_error:nnn { groupthm } { unknown ~ group } { #1 } + } + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\@@_use_function_on_name:n} +% \begin{syntax} +% \cs{@@_use_function_on_name:n}\meta{function} +% \end{syntax} +% +% The \meta{function} is expected to be of type \texttt{:n}, +% This applies the function to the \cs{l_@@_name_tl} +% +% \begin{macrocode} +\cs_new:Npn \@@_use_function_on_name:n #1 + { + \tl_set:Nx \l_@@_name_tl + { + #1 { \tl_use:N \l_@@_name_tl } + } + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\@@_declare_grouped_theorem_aux:nnnn} +% \begin{syntax} +% \cs{@@_declare_grouped_theorem_aux:nnnn}\ma{environment name} +% \ma{groups clist}\ma{theorem name}\ma{thmtools keys} +% \end{syntax} +% +% This is the internal backend that declares a grouped theorem +% by retrieving all the group properties and issuing a (single) \cs{declaretheorem} +% command of \pkg{thmtools}. +% +% \begin{macrocode} +\cs_new:Npn \@@_declare_grouped_theorem_aux:nnnn #1 #2 #3 #4 + { +% \end{macrocode} +% First, set local variables to default values and store current name. +% \begin{macrocode} + \tl_clear:N \l_@@_prename_tl + \tl_set:Nn \l_@@_name_tl { #3 } + \tl_clear:N \l_@@_postname_tl + \clist_clear:N \l_@@_mapname_clist + \clist_clear:N \l_@@_thmtools_clist +% \end{macrocode} +% Clear all hooks +% \begin{macrocode} + \hook_gremove_code:nn { @@/prename }{*} + \hook_gremove_code:nn { @@/postname }{*} + \hook_gremove_code:nn { @@/mapname }{*} + \hook_gremove_code:nn { @@/thmtools }{*} +% \end{macrocode} +% Now, retrieve the group properties, by writing these into the hooks +% \begin{macrocode} + \clist_map_function:nN { #2 } \group_use:n +% \end{macrocode} +% Execute the hooks, so that local variables will get modified according to the groups +% and in the order that were specified for the hooks. +% \begin{macrocode} + \hook_use:n { @@/prename } + \hook_use:n { @@/postname } + \hook_use:n { @@/mapname } + \hook_use:n { @@/thmtools } +% \end{macrocode} +% We are left with dealing with the obtained data. +% We first map on the name, before appending to it. +% \begin{macrocode} + \clist_map_function:NN \l_@@_mapname_clist \map_use_on_name:n +% \end{macrocode} +% We now glue the name together of its three parts, +% and pass this key directly to the \pkg{thmtools} arguments +% \begin{macrocode} + \clist_put_right:Nx \l_@@_thmtools_clist + { + name = \tl_use:N \l_@@_prename_tl + \tl_use:N \l_@@_name_tl + \tl_use:N \l_@@_postname_tl + } +% \end{macrocode} +% Finally, apply the additional \pkg{thmtools} keys for this specific theorem. +% Putting them last will overwrite keys that were given by the groups. +% \begin{macrocode} + \clist_put_right:n \l_@@_thmtools_clist { #4 } +% \end{macrocode} +% We can now pass our list to \pkg{thmtools}, declaring the theorem. +% \begin{macrocode} + \@@_declare_theorem:nV + { #1 } + \l_@@_thmtools_clist + } +% \end{macrocode} +% \end{macro} +% +% +% +% As usual, we provide a \texttt{new} and a \texttt{provide} variant wrapped +% around this that do proper error checking. +% +% +% +% \begin{macro}{\groupthm_new_grouped_theorem:nnnn} +% \begin{syntax} +% \cs{groupthm_new_grouped_theorem:nnnn}\ma{environment name} +% \ma{groups clist}\ma{theorem name}\ma{thmtools keys} +% \end{syntax} +% +% \begin{macrocode} +\cs_new:Npn \groupthm_new_grouped_theorem:nnnn #1 #2 #3 #4 + { +% \end{macrocode} +% Note that the next comparison depends on \pkg{thmtools} declaring +% environments, and that \LaTeX\ handles environments called with the +% |\begin{environment}| syntax by calling |\environment| subsequently. +% \begin{macrocode} + \cs_if_exist:cTF { #1 } + { + \msg_error:{ groupthm } { wrong ~ definition } + { grouped ~ theorem } { #1 } { already } + } + { + \@@_groupthm_declare_grouped_theorem_aux:nnnn + { #1 } { #2 } { #3 } { #4 } + } + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\groupthm_provide_grouped_theorem:nnnn} +% \begin{syntax} +% \cs{groupthm_provide_grouped_theorem:nnnn}\ma{environment name} +% \ma{groups clist}\ma{theorem name}\ma{thmtools keys} +% \end{syntax} +% +% \begin{macrocode} +\cs_new:Npn \groupthm_provide_grouped_theorem:nnnn #1 #2 #3 #4 + { +% \end{macrocode} +% Note that the next comparison depends on \pkg{thmtools} declaring +% environments, and that \LaTeX\ handles environments called with the +% |\begin{environment}| syntax by calling |\environment| subsequently. +% \begin{macrocode} + \cs_if_exist:cF { #1 } + { + \@@_groupthm_declare_grouped_theorem_aux:nnnn + { #1 } { #2 } { #3 } { #4 } + } + } +% \end{macrocode} +% \end{macro} +% +% +% The star variants of these that add the \texttt{unnumbered} group +% are straightforward: +% +% +% \begin{macro}{\groupthm_new_grouped_theorem_star:nnnn} +% \begin{syntax} +% \cs{groupthm_new_grouped_theorem_star:nnnn}\ma{environment name} +% \ma{groups clist}\ma{theorem name}\ma{thmtools keys} +% \end{syntax} +% +% \begin{macrocode} +\cs_new:Npn \groupthm_new_grouped_theorem_star:nnnn #1 #2 #3 #4 + { + \groupthm_new_grouped_theorem:nnnn + { #1 } { #2, unnumbered } { #3 } { #4 } + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\groupthm_provide_grouped_theorem_star:nnnn} +% \begin{syntax} +% \cs{groupthm_provide_grouped_theorem_star:nnnn}\ma{environment name} +% \ma{groups clist}\ma{theorem name}\ma{thmtools keys} +% \end{syntax} +% +% \begin{macrocode} +\cs_new:Npn \groupthm_provide_grouped_theorem_star:nnnn #1 #2 #3 #4 + { + \groupthm_provide_grouped_theorem:nnnn + { #1 } { #2, unnumbered } { #3 } { #4 } + } +% \end{macrocode} +% \end{macro} +% +% +% On top of these, we can provide the shorter versions that will generate +% two theorems each, one with and one without a \enquote{*} in its +% environment name +% +% +% +% \begin{macro}{\groupthm_new_theorem:nnnn} +% \begin{syntax} +% \cs{groupthm_new_theorem:nnnn}\ma{environment name} +% \ma{groups clist}\ma{theorem name}\ma{thmtools keys} +% \end{syntax} +% +% +% \begin{macrocode} +\cs_new:Npn \groupthm_new_theorem:nnnn #1 #2 #3 #4 + { + \groupthm_new_grouped_theorem:nnnn + { #1 } { #2 } { #3 } { #4 } + \groupthm_new_grouped_theorem:nnnn + { #1* } { #2, starred } { #3 } { #4 } + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\groupthm_provide_theorem:nnnn} +% \begin{syntax} +% \cs{groupthm_provide_theorem:nnnn}\ma{environment name} +% \ma{groups clist}\ma{theorem name}\ma{thmtools keys} +% \end{syntax} +% +% +% \begin{macrocode} +\cs_new:Npn \groupthm_provide_theorem:nnnn #1 #2 #3 #4 + { + \groupthm_provide_grouped_theorem:nnnn + { #1 } { #2 } { #3 } { #4 } + \groupthm_provide_grouped_theorem:nnnn + { #1* } { #2, starred } { #3 } { #4 } + } +% \end{macrocode} +% \end{macro} +% +% +% Combining these is also not difficult: +% +% +% +% +% \begin{macro}{\groupthm_new_theorem_star:nnnn} +% \begin{syntax} +% \cs{groupthm_new_theorem_star:nnnn}\ma{environment name} +% \ma{groups clist}\ma{theorem name}\ma{thmtools keys} +% \end{syntax} +% +% \begin{macrocode} +\cs_new:Npn \groupthm_new_theorem_star:nnnn #1 #2 #3 #4 + { + \groupthm_new_theorem:nnnn + { #1 } { #2, unnumbered } { #3 } { #4 } + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\groupthm_provide_theorem_star:nnnn} +% \begin{syntax} +% \cs{groupthm_provide_theorem_star:nnnn}\ma{environment name} +% \ma{groups clist}\ma{theorem name}\ma{thmtools keys} +% \end{syntax} +% +% \begin{macrocode} +\cs_new:Npn \groupthm_provide_theorem_star:nnnn #1 #2 #3 #4 + { + \groupthm_provide_theorem:nnnn + { #1 } { #2, unnumbered } { #3 } { #4 } + } +% \end{macrocode} +% \end{macro} +% +% We now provide the corresponding key-valued interfaces around these. +% +% % % % diff --git a/doc/environments/groupthm/groupthm.sty b/doc/environments/groupthm/groupthm.sty index 6f6defb..e60fcf0 100644 --- a/doc/environments/groupthm/groupthm.sty +++ b/doc/environments/groupthm/groupthm.sty @@ -129,6 +129,21 @@ { unrelated } { #1 } } +\cs_new:Npn \__groupthm_add_to_sort_hook:n #1 +{ + \hook_gput_code:nnn { __groupthm/groupsort } + { #1 } + { + \clist_put_left:Nn \l__groupthm_group_clist { #1 } + } +} +\cs_new:Npn \__groupthm_sort_theorem_group_names: + { + \hook_gremove_code:nn { __groupthm/groupsort }{*} + \clist_map_function:NN \l__groupthm_group_clist \__add_to_sort_hook:n + \clist_clear:N \l__groupthm_group_clist + \hook_use:n { __groupthm/groupsort } + } \cs_new:Npn \__groupthm_declare_theorem_group_aux:nnnnn #1#2#3#4#5 { \cs_new:cpn { __groupthm_use_group_#1: } @@ -282,6 +297,33 @@ { \groupthm_declare_theorem_group_by_keys:nn { #1 } { #2 } } +\cs_new:Npn \groupthm_declare_theorem_group_rule:nnnn #1 #2 #3 #4 + { + \str_set:Nx \l_tmpa_str { \tl_trim_spaces:n { #3 } } + + \str_if_eq:VnT \l_tmpa_str { higher } + { + \str_set:Nn \l_tmpa_tl { after } + } + + \str_if_eq:VnT \l_tmpa_str { lower } + { + \str_set:Nn \l_tmpa_tl { before } + } + + \str_if_eq:nnTF { #1 } { ?? } + { + \hook_gset_rule:nnVn {??} {#2} \l_tmpa_tl {#4} + } + { + \hook_gset_rule:nnVn { __groupthm / #1 } {#2} \l_tmpa_tl {#4} + } + } + +\NewDocumentCommand { \DeclareTheoremGroupRule } { O{??} m m m } + { + \groupthm_declare_theorem_group_rule:nnnn {#1} {#2} {#3} {#4} + } \endinput %% %% End of file `groupthm.sty'.