From 70ddae2307475391e748684f48e8df616be91ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Ke=C3=9Fler?= Date: Thu, 20 Jan 2022 21:39:49 +0100 Subject: [PATCH] higher abstraction for defining (re)new variants new macro carries out all four definitions at once rename all groupthm_new_theorem_group... macros into groupthm_new_group... --- doc/environments/groupthm/5 | 3387 ++++++++++++++++++++++++ doc/environments/groupthm/groupthm.dtx | 146 +- doc/environments/groupthm/groupthm.sty | 79 +- 3 files changed, 3469 insertions(+), 143 deletions(-) create mode 100644 doc/environments/groupthm/5 diff --git a/doc/environments/groupthm/5 b/doc/environments/groupthm/5 new file mode 100644 index 0000000..c6414e0 --- /dev/null +++ b/doc/environments/groupthm/5 @@ -0,0 +1,3387 @@ +% \iffalse meta-comment +% +%% File: groupthm.dtx +% +% Copyright (C) 2022 Maximilian Keßler +% +% It may be distributed and/or modified under the conditions of the +% LaTeX Project Public License (LPPL), either version 1.3c of this +% license or (at your option) any later version. The latest version +% of this license is in the file +% +% https://www.latex-project.org/lppl.txt +% +% ----------------------------------------------------------------------- +%\ProvidesExplPackage{groupthm}{2022/01/17}{0.0.1}{Grouped theorems.} +% +%<*driver> +\documentclass[full,kernel]{l3doc} +\usepackage{mkessler-todo} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +% +% \fi +% +% \title{^^A +% The \pkg{groupthm} package^^A +% } +% +% \author{^^A +% Maximilian Keßler +% } +% +% \date{Released 2022-01-12} +% +% \maketitle +% +% +% \NewDocumentCommand{\kw}{m} +% {% +% \texttt{#1}% +% } +% +% \NewDocumentCommand{\vocab}{m} +% {% +% \emph{#1}% +% } +% +% \ExplSyntaxOn +% \NewDocumentCommand { \mymeta } { O{} m } +% { +% \meta[#1]{#2} +% \__codedoc_special_index_module:nnnnN { #2 } { #2 } { meta } { usage } { \c_false_bool} +% } +% \ExplSyntaxOff +% +% +% +% \begin{documentation} +% +% \tableofcontents +% \listoftodos +% \newpage +% +% \begin{itemize} +% \item Inheritance +% \item Appending to groups +% \item default group integration +% \item better error message to avoid low level tex errors in any case +% \item potentially: detection of star / nonstar misuse +% \item add command to define group rule for all existing groups +% \item various info commands on defined groups? +% \item debugging information? +% \end{itemize} +% A central thing in \LaTeX is the usage of \enquote{theorems}. +% With \enquote{theorems} we actually mean \enquote{environments} that typically +% have a title, some style applied to their contents and are numbered throughout +% the document, often later referenced by number and / or name. +% +% Mechanisms for generating such environments are packages like +% \pkg{amsthm}, \pkg{ntheorem}, \pkg{thmtools}. +% +% While the mechanism in \pkg{thmtools} are pretty versatile and suffice +% for almost all needs, it is pretty time-consuming to largely change +% the behavior of environments, or have small variants of these. +% +% This package aims at both providing a versatile mechanism, \mymeta{theorem group}s, +% to structure theorems into groups that can subsequently easily altered, +% as well as a mechanism for easily generating \mymeta{theorem families}. +% +% As the author is of the opinion that of the mentioned theorem controlling packages +% \pkg{thmtools} provides the most versatile interface, the \pkg{groupthm} +% will be working on top of \pkg{thmtools} and use this as a backend for declaring +% the \mymeta{theorem}s themselves. +% +% Thus, any styles supported by \pkg{thmtools} will be supported by \pkg{groupthm} +% as well, by passing them to \pkg{thmtools}. +% +% \section{Concepts} +% +% \subsection{Theorem groups} +% \label{sec:theorem-groups} +% A \mymeta{theorem group} is some named group holding some properties for +% the \mymeta{theorem}s that are contained in this group. +% Each \mymeta{theorem} can, when declared, be part of arbitrarily many \mymeta{theorem group}s, +% and will be subject to the styles these groups defined. +% +% This enables to group similar \mymeta{theorem}s and alter them at a late stage of +% document development in a unique manner, by only having to change the +% definition of the \mymeta{theorem group}, and not all \mymeta{theorem}s separately. +% +% The properties. such a \mymeta{theorem group} can hold are as follows +% +% +% \begin{description} +% \item[\kw{prefix}] A prefix (any \mymeta{token list}) that will be inserted +% before the theorem name of each member of this \mymeta{theorem group}. +% \item[\kw{suffix}] A suffix (any \mymeta{token list}) that will be +% inserted before the theorem name for each member of this \mymeta{theorem group}. +% This could be e.g.~some \enquote{$\star$} appended to the name to indicate +% variants of environments. +% \item[\kw{mapname}] A \mymeta{function} (some macro that takes exactly one argument) +% that is applied to the \kw{name}. +% \item[\kw{thmtools}] A \mymeta{clist} of key-value pairs that are passed to the underlying +% \pkg{thmtools} backend of the \mymeta{theorem}. +% This allows e.g.~to set the \kw{topskip} of a certain class of \mymeta{theorem}s. +% \end{description} +% +% The most versatile key here is certainly the \kw{thmtools} key, +% providing the most customization to an end user (like you). +% +% As mentioned, each \mymeta{theorem} can be member of arbitrary many \mymeta{theorem group}s, +% and will posses their corresponding properties. +% +% To adjust finer controlling of these \mymeta{theorem group}s, \mymeta{theorem group}s can inherit from each other, and \mymeta{theorem group}s are subject to a hierarchy that controls precedence in case +% of conflicting properties of different \mymeta{theorem group}s a \mymeta{theorem} may be part of. +% +% This hierarchy can of course be controlled by the user. +% +% \subsection{Grouped theorems} +% +% A \mymeta{grouped theorem} is just a theorem that is a member of +% a given set of groups (possibly empty). +% It behaves just a regular theorem, except that by changing the definition of +% its theorem groups, we can alter its behavior. +% +% +% It is the core concept of the \pkg{groupthm} package. +% For brevity, we will often talk about \enquote{theorems}, +% although in fact we mean \enquote{grouped theorems}. +% +% \subsection{Theorem families} +% Often, one needs some small \mymeta{theorem variant}s of some \mymeta{theorem}, the most typical +% example being \vocab{starred} version of \mymeta{theorem}s that are not numbered +% in contrast to their counterparts. +% +% \begin{verbatim} +% \begin{theorem} +% This theorem is numbered. +% \end{theorem} +% +% \begin{theorem*} +% This theorem is not numbered. +% Probably because we do not want a reference to it. +% \end{theorem*} +% \end{verbatim} +% \todo{insert code example output} +% +% \pkg{groupthm} extends this idea and provides a versatile mechanism to define a +% \mymeta{theorem family}, which is based on some \mymeta{theorem name} and +% parses additional arguments / syntax to control the \mymeta{theorem groups} +% that this environment is a part of. +% +% So, in addition the name of a \mymeta{theorem}, the corresponding environment will +% accept some options and toggle the membership of certain \mymeta{theorem groups}, +% thus further customizing its appearance. +% +% This can lead e.g.~to usages like the following: +% +% \begin{verbatim} +% \begin{theorem}* +% This theorem has a visual * at its name. +% \end{theorem} +% \end{verbatim} +% \todo{code} +% +% Providing this consists of two parts: +% declaring the \mymeta{theorem family} by listing the groups that can be toggled +% by this \mymeta{theorem family}, and declaring the actual option parsing +% of the \mymeta{theorem family}, which then controls the membership in these groups +% (and of course prior to this the definition of the desired \mymeta{theorem group}s). +% +% +% +% \subsection{General notions} +% +% In many cases, there are a number of variants of some command, +% call it for example \cs{Foo}. +% Then the documentation will look like +% % +% \begin{function}{\NewFoo, \RenewFoo, \ProvideFoo, \DeclareFoo} +% Defines some \kw{foo} \ldots +% \end{function} +% % +% and will not mention anything about the variants. +% This follows some general naming convention that also \pkg{xparse} uses, +% and is the following: +% +% \begin{description} +% \item[\cs{NewFoo}] +% +% Defines \kw{foo} if not defined already. +% This emits an error in case it has been defined yet. +% +% \item[\cs{RenewFoo}] +% +% Redefines \kw{foo} if defined already. +% This emits an error in case it has \emph{not} been defined yet. +% +% \item[\cs{ProvideFoo}] +% +% Defines \kw{foo} if it is not defined already. +% This does not emit an error if \kw{foo} is already defined +% (and has no effect in this case). +% +% \item[\cs{DeclareFoo}] +% +% Defines \kw{foo} in disregard of any +% existing definitions. Any old definition will be overwritten (if present). +% \end{description} +% % +% The documentation margin will list all variants that are available, +% they follow their respective conventions. +% +% +% \begin{texnote} +% The \pkg{thmtools} package, unfortunately, dose not follow this convention, +% as its \cs{declaretheorem} command actually behaves like a \cs{newtheorem}. +% The reason for this is that \pkg{amsthm} already defines \cs{newtheorem}. +% +% Thus, actually, calls to \cs{NewGroupedTheorem} will have an underlying +% \cs{declaretheorem}, but you do not have to bother with this. +% \end{texnote} +% +% \section{Theorem groups} +% +% \subsection{Defining theorem groups} +% +% \begin{function}{\NewTheoremGroup, \RenewTheoremGroup, \ProvideTheoremGroup, \DeclareTheoremGroup} +% \begin{syntax} +% \cs{NewTheoremGroup}\oarg{keys}\marg{theorem group} +% \end{syntax} +% +% This introduces a new \mymeta{theorem group} with the given name. +% The \mymeta{keys} available are the same as introduced in \autoref{sec:theorem-groups}: +% +% \begin{description} +% \item +% +% \kw{prefix} = \mymeta{token list}. +% Insert the \mymeta{token list} in front of the theorem name. +% +% \item +% +% \kw{suffix} = \mymeta{token list}. +% Insert the \mymeta{token list} after the theorem name. +% +% \item +% +% \kw{mapname} = \mymeta{function}. +% Apply this \mymeta{function} to the theorem name. +% +% \item +% +% \kw{thmtools} = $\{$\mymeta{clist}$\}$. +% Pass these options to \pkg{thmtools}. +% +% \end{description} +% +% For uniqueness of the given options, the \mymeta{clist} given to the \kw{thmtools} key +% has to be surrounded by a pair of braces. +% +% \begin{texnote} +% The \kw{mapname} is expected to be a function of \cs{fun:n}. +% It is subject to an \kw{x}-type expansion prior to being passed further to \pkg{thmtools}. +% \end{texnote} +% +% \end{function} +% +% \subsection{Controlling theorem group precedence} +% +% \begin{function}{\DeclareTheoremGroupRule} +% \begin{syntax} +% \cs{DeclareTheoremGroupRule}\oarg{keyname}% +% \marg{theorem group 1}\marg{relation}\marg{theorem group 2} +% \end{syntax} +% +% This declares some relation between the two theorem groups, +% controlling their order of application in case a theorem is member +% of both groups. +% +% The \mymeta{keyname} can be one of \kw{prefix}, \kw{suffix}, \kw{mapname}, \kw{thmtools}. +% If present, it declares the corresponding relation only for this subkey. +% This can lead to \mymeta{theorem group 1} overwriting \mymeta{theorem group 2} when given +% contradictory \pkg{thmtools} options, but the \kw{prefix} of \mymeta{theorem group 1} +% being applied after the one of \mymeta{theorem group 2}. +% When the \mymeta{keyname} is not given, this applies to all keywords. +% +% \begin{texnote} +% The \mymeta{keyname} is just passed to the corresponding argument +% of the \kw{lthooks} package. +% If the option argument is not present, \kw{??} is used, this has the described effect. +% \end{texnote} +% +% The behavior of the relations is based on the \cs{DeclareHookRule} command +% from the \pkg{xparse} package, and all respective keys are in fact available, +% but typically not needed, so the reader of this manual is referred to the +% \todoref{lthooks} packages documentation for a list of the full keys. +% For us, the following list will suffice: +% +% \begin{description} +% \item[\kw{higher} or \kw{after} or \kw{\string>}] +% +% \mymeta{theorem group 1} takes precedence over \mymeta{theorem group 2}. +% Its \kw{prefix} is applied after the one of \mymeta{theorem group 2}. +% +% \item[\kw{lower} or \kw{before} or \kw{\string<}] +% +% \mymeta{theorem group 2} takes precedence over \mymeta{theorem group 1}. +% Its \kw{prefix} is applied after the one of \mymeta{theorem group 1}. +% +% \end{description} +% +% \begin{texnote} +% The \mymeta{relation} is first stripped, +% then checked if it matches either \kw{higher} or \kw{lower} +% and in this case replaced by the corresponding \pkg{lthooks} variant +% of the relation. +% The rest is passed as is to \pkg{lthooks} and thus subject to the usual +% normalization process of \pkg{lthooks}. +% \end{texnote} +% +% \end{function} +% +% +% \subsection{Inheritance of theorem groups} +% \begin{function}{\AddTheoremGroupParent} +% \begin{syntax} +% \cs{AddTheoremGroupParent}\marg{theorem group 1}\marg{theorem group 2} +% \end{syntax} +% Declares \mymeta{theorem group 1} to \enquote{inherit} all properties +% of \mymeta{theorem group 2}. +% In other words, \mymeta{theorem group 2} is a parent of \mymeta{theorem group 1} +% in a usual inheritance graph. +% +% The definitions of the groups themselves are unchanged, +% but each new theorem defined with \mymeta{theorem group 1} will also +% have the properties of \mymeta{theorem group 2}. +% +% Inheritance is transitive, when defining a new theorem, we just flatten out the +% inheritance graph and apply all properties. +% +% Inheritance is subject to the usual theorem group hierarchies as discussed in \todoref. +% This can even yield to situations, where \mymeta{theorem group 1} inherits +% from \mymeta{theorem group 2}, but \mymeta{theorem group 2} overwrites +% \mymeta{theorem group 1}. +% \end{function} +% +% \subsection{Appending to theorem groups} +% \begin{function}{\AppendToTheoremGroup} +% \begin{syntax} +% \cs{AppendToTheoremGroup}\oarg{keys}\marg{theorem group} +% \end{syntax} +% Adds the properties given as \mymeta{keys} to the theorem group. +% The syntax for the \mymeta{keys} is the same as in \cs{NewTheoremGroup}. +% \end{function} +% +% \subsection{Default theorem groups} +% +% There are a number of theorem groups that \pkg{groupthm} will initially declare +% and that have certain special treatment in some places. +% +% \begin{function}{all} +% Every declared grouped theorem is a member of this group. +% +% Initially, this group has no effect (i.e.~an empty property list). +% It can be redefined by the user to alter the behavior of all grouped theorems +% in a unified way. +% +% It is the lowest theorem group in the hierarchy by default. +% \end{function} +% +% \begin{function}{starred} +% This is group that shall represent the standard variant of theorems that +% are called with a \enquote{*} in the environment name. +% Theorems of this group are not numbered. +% +% The user should not add theorems to this group by hand, +% as this is handled in a unified way by default. +% \todoref{} +% +% It is the highest theorem group in the hierarchy by default, +% except for \texttt{unnumbered}, +% with which it has no relation. +% \end{function} +% \addtocounter{footnote}{-1} +% +% \begin{function}{unnumbered} +% Theorems in this group are not numbered. +% +% It is the highest theorem group in the hierarchy by default, +% except for \cs{starred}, +% with which it has no relation. +% \end{function} +% +% The reason for the two groups \kw{starred} and \kw{unnumbered} +% to both exist is that the \kw{starred} group is \emph{meant} to be applied +% to theorems that were called with a \enquote{*} in their name (thus the name), +% whereas the \enquote{unnumbered} group \emph{means} that the environment +% is 'just unnumbered'. +% +% This has two reasons: +% First, this enables more fine-tuning of the behavior of the theorems in post-processing +% of a document. +% Second, more importantly, this distinguishes semantically between the environments +% \kw{theorem} and \kw{theorem*}, even if \kw{theorem} is in the \kw{unnumbered} group. +% +% So assuming that \kw{theorem} is member of the \kw{unnumbered} group, both calls +% +% \begin{verbatim} +% \begin{theorem} +% This is not numbered. +% \end{theorem} +% \begin{theorem*} +% This is not numbered. +% \end{theorem*} +% \end{verbatim} +% +% are defined and will produce the same result by default, but we could still +% change the definition of the \kw{starred} group later to do anything we want. +% +% \begin{texnote} +% The mentioned hierarchies are kept intact for newly defined theorem groups, +% i.e.~for each new such group, two theorem group rules are created. +% \end{texnote} +% +% \section{Grouped Theorems} +% +% \subsection{Defining grouped theorems} +% +% \begin{function}{\NewGroupedTheorem, \ProvideGroupedTheorem} +% \begin{syntax} +% \cs{NewGroupedTheorem}\oarg{keys}\marg{theorem name} +% \end{syntax} +% This defines \mymeta{theorem name} as a new theorem environment. +% Its properties can be set by the following keys: +% +% \begin{description} +% +% \item +% +% \kw{name} $=$ \mymeta{displayed name}. +% If given, this is the displayed name of the environment in the document. +% If not present, the \mymeta{theorem name} is also used as the \mymeta{displayed name} +% in capitalized form. +% +% \item +% +% \kw{group} $=$ \marg{clist} +% +% Makes this theorem a member of the listed groups. +% It will inherit all respective properties of these groups. +% +% If groups are present more than one time, this has no (additional) effect. +% +% \item +% +% \kw{thmtools} = \marg{clist} +% +% Passes these option to the \pkg{thmtools} environment that is declared internally. +% +% \end{description} +% \end{function} +% +% \begin{function}{\NewGroupedTheorem*,\ProvideGroupedTheorem*} +% \begin{syntax} +% \cs{NewGroupedTheorem*}\oarg{keys}\marg{theorem name} +% \end{syntax} +% Behaves the same as \cs{NewGroupedTheorem}, +% but also adds the theorem to the default \kw{unnumbered} group, +% thus resulting in the environment not being numbered. +% +% This is thus equivalent to using \cs{NewGroupedTheorem} and adding the +% \kw{unnumbered} group. +% \end{function} +% +% \begin{function}{\NewTheorem, \ProvideTheorem} +% \begin{syntax} +% \cs{NewTheorem}\oarg{keys}\marg{theorem name} +% \end{syntax} +% +% This behaves essentially the same as \cs{NewGroupedTheorem}, +% but will define two grouped theorems, namely \mymeta{theorem name} and \mymeta{theorem name*}. +% +% The \mymeta{theorem name*} environment has the same properties as the \mymeta{theorem name}, +% but will be member of the \kw{starred} theorem group. +% It is thus not recommended to call \cs{NewTheorem} +% with an actual \enquote{*} in the environment name, since both environments +% will be generated. +% \end{function} +% +% \begin{function}{\NewTheorem*, \ProvideTheorem*} +% \begin{syntax} +% \cs{NewTheorem}\oarg{keys}\marg{theorem name} +% \end{syntax} +% Combines the behavior of \cs{NewGroupedTheorem*} and \cs{NewTheorem}, thus +% declaring \mymeta{theorem} to (additionally) be member of the \kw{unnumbered} +% and \mymeta{theorem*} to (additionally) be member of the \kw{starred} group. +% +% As mentioned in \todoref, by default both environments will behave the same. +% \end{function} +% +% \subsection{Defining families of grouped theorems} +% +% \begin{function}{\NewGroupedTheoremFamily, \ProvideGroupedTheoremFamily} +% \begin{syntax} +% \cs{NewTheoremFamily}\oarg{keys}\marg{theorem name} +% \end{syntax} +% +% Defines a family of grouped theorems. +% The \mymeta{keys} accept the same arguments as the \cs{NewGroupedTheorem} macro. +% However, for each \emph{subset} of the given groups, +% a grouped theorem is defined. +% +% These grouped theorems are not meant to be accessed directly (but could), +% so we omit their actual (internal) names here. +% To call these, some \kw{GroupedTheoremFamilyOptions} have to specified, +% see \cs{NewGroupedTheoremFamilyOptions}. +% \end{function} +% +% \begin{function}{\NewGroupedTheoremFamily*, \ProvideGroupedTheoremFamily*} +% Behaves the same as \cs{NewGroupedTheoremFamily}, but also adds each variant +% to the default \kw{unnumbered} group, thus resulting in the environments not being +% numbered. +% +% This is \emph{almost} equivalent to calling \cs{NewGroupedTheoremFamily} +% with the \kw{unnumbered} group being present, as it does not generate the variants +% where the \kw{unnumbered} group is not present. +% \end{function} +% +% \begin{function}{\NewTheoremFamily, \ProvideTheoremFamily} +% This behaves essentially the same as \cs{NewGroupedTheoremFamily}, +% but will add the \kw{starred} group to the list of groups and also generate variants +% for these. +% +% It is thus not recommended to call \cs{NewTheoremFamily} with the \kw{starred} +% group explicitly given, since this is added anyways. +% \end{function} +% +% \begin{function}{\NewTheoremFamily*, \ProvideTheoremFamily*} +% Combines the behavior of \cs{NewGroupedTheoremFamily*} and \cs{NewTheoremFamily}, thus +% declaring all variants to (additionally) be member of the \kw{unnumbered} +% group, and also generates definitions with and without the \kw{starred} group. +% +% As mentioned in \todoref, by default both environments will behave the same. +% \end{function} +% +% +% \begin{function}{\AddTheoremToGroup} +% \begin{syntax} +% \cs{AddTheoremToGroup}\marg{theorem group} +% \end{syntax} +% +% Means that the current invocation of a theorem family should +% call the theorem variant with the given group. +% +% Can only be used in the body of \cs{NewGroupedTheoremFamilyOptions} or similarly. +% \end{function} +% +% \begin{function} +% { +% \NewGroupedTheoremFamilyOptions, \RenewGroupedTheoremFamilyOptions, +% \ProvideGroupedTheoremFamilyOptions, \DeclareGroupedTheoremFamilyOptions +% } +% \begin{syntax} +% \cs{NewGroupedTheoremFamilyOptions}\marg{theorem name}\marg{argument specifiation}% +% \marg{selection body} +% \end{syntax} +% +% Defines a new environment with options, given by \mymeta{theorem name}. +% The \mymeta{argument specification} can be any valid \pkg{xparse} argument specification. +% +% The \mymeta{selection body} is there to process the options of +% the \mymeta{argument specification} and select which variant of the \mymeta{theorem name} +% to enter. +% The arguments are available as usual with \pkg{xparse} by \kw{\#1}, \kw{\#2}, \ldots +% +% The body may also call any number of \cs{AddTheoremToGroup} calls, +% which enables the corresponding groups. +% +% When the environment is called within the document, the options are parsed +% as with \pkg{xparse} and the \mymeta{selection body} is executed. +% Immediately after, the theorem variant of \mymeta{theorem name} with the specified groups +% by \cs{AddTheoremToGroup} is called. +% +% At the end of the environment, the \mymeta{selection body} is executed again and the +% called theorem variant is ended again. +% +% The possible theorem variants that the newly declared environment will call +% \emph{have to be generated subsequently} by a call to the \cs{NewGroupedTheoremFamily} +% function. +% +% \end{function} +% +% \begin{function} +% { +% \NewGroupedTheoremFamilyOptions*, \RenewGroupedTheoremFamilyOptions*, +% \ProvideGroupedTheoremFamilyOptions*, \DeclareGroupedTheoremFamilyOptions* +% } +% \begin{syntax} +% \cs{NewGroupedTheoremFamilyOptions*}\marg{theorem name}\marg{argument specifiation}% +% \marg{selection body} +% \end{syntax} +% +% Does the same as \cs{NewGroupedTheoremFamilyOptions}, +% but calls the variants with the additional \kw{unnumbered} group. +% +% The possible theorem variants have to be generated +% with the \cs{NewGroupedTheoremFamily*} command before. +% +% \end{function} +% +% \begin{function} +% { +% \NewTheoremFamilyOptions, \RenewTheoremFamilyOptions, +% \ProvideTheoremFamilyOptions, \DeclareTheoremFamilyOptions +% } +% \begin{syntax} +% \cs{NewTheoremFamilyOptions}\marg{theorem name}\marg{argument specifiation}% +% \marg{selection body} +% \end{syntax} +% +% This behaves essentially the same as \cs{NewGroupedTheoremFamilyOptions}, +% but also declares the environment \mymeta{theorem name*}, +% which behaves the same but calls the theorem variants with the additional \kw{starred} +% subgroup. +% +% The possible theorem variants have to be generated with the \cs{NewTheoremFamily} +% command before. +% +% \end{function} +% +% \begin{function} +% { +% \NewTheoremFamilyOptions*, \RenewTheoremFamilyOptions*, +% \ProvideTheoremFamilyOptions*, \DeclareTheoremFamilyOptions* +% } +% \begin{syntax} +% \cs{NewTheoremFamilyOptions*}\marg{theorem name}\marg{argument specifiation}% +% \marg{selection body} +% \end{syntax} +% +% Combines the behavior of \cs{NewGroupedTheoremFamilyOptions*} and \cs{NewTheoremFamilyOptions}, +% thus declaring both \mymeta{theorem name} and \mymeta{theorem name*} environments, +% the latter calling the \kw{starred} variants of the theorem family, +% and both of them calling \kw{unnumbered} variants of the family. +% +% The possible theorem variants have to be generated with the \cs{NewTheoremFamily*} +% command before. +% +% \end{function} +% +% \section{\LaTeX3 interface} +% +% There is also an underlying \LaTeX3 interface provided by the package +% (and in fact, all prior documented macros are just wrappers around this +% internal programming interface. +% +% When building on top of this package, you can also use this interface, +% which is possibly easier to use. +% +% In general, for functions that use key-value syntax, there are typically +% three (public) versions of the command, namely +% +% \begin{itemize} +% \item A \LaTeX3 command that requires all key-values as mandatory arguments, +% so this does not use the key-value interface. +% Use this if you already know with which keys you deal and know their +% corresponding values. +% \item A \LaTeX3 command having the first argument accepting the keys as a +% comma-separated list. +% Use this if you want to profit of the key-value syntax. +% \item A \LaTeX2e document command. These were documented before, +% and these just wrap the second type of command. +% \end{itemize} +% If the corresponding command would be something like \enquote{new foo}, +% The syntax will typically be +% \begin{itemize} +% \item \cs{groupthm_new_foo:mmm}\mymeta{mandatory args}\mymeta{optional args}, +% where the \mymeta{mandatory args} list the mandatory args of the \LaTeX2e +% interface, and the \mymeta{optional args} list the optional args +% of the key-value interface, but requiring them mandatory as well. +% \item \cs{groupthm_new_foo_from_keys:mmm}\marg{keys}\mymeta{mandatory args} +% where we pass a \texttt{clist} as the first argument and all mandatory args +% as further mandatory arguments. +% \item \cs{NewFoo}\oarg{keys}\mymeta{mandatory args}, +% where the keys can be passed optionally. +% \end{itemize} +% +% \subsection{Theorem groups} +% +% +% \begin{function} +% { +% \groupthm_new_theorem_group_from_keys:nn, +% \groupthm_renew_theorem_group_from_keys:nn, +% \groupthm_provide_theorem_group_from_keys:nn, +% \groupthm_declare_theorem_group_from_keys:nn +% } +% \begin{syntax} +% \cs{groupthm_new_theorem_group_from_keys:nn}\marg{keys}\marg{theorem group} +% \end{syntax} +% +% \LaTeX3 versions of \cs{NewTheoremGroup}, \cs{RenewTheoremGroup}, +% \cs{ProvideTheoremGroup} and \cs{DeclareTheoremGroup} +% +% \end{function} +% +% +% +% \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}\marg{theorem group}\marg{prefix tl} +% \marg{suffix tl}\marg{mapname clist}\marg{thmtools clist} +% \end{syntax} +% +% Non-keyval versions of +% \cs{groupthm_new_theorem_group_from_keys:nn}, +% \cs{groupthm_renew_theorem_group_from_keys:nn}, +% \cs{groupthm_provide_theorem_group_from_keys:nn} +% and +% \cs{groupthm_declare_theorem_group_from_keys:nn} +% +% These take the individual values of the keyval keys directly, in the order +% indicated by the syntax specification. +% +% \end{function} +% +% +% \begin{function}{\groupthm_declare_theorem_group_rule:nnnn} +% \begin{syntax} +% \cs{groupthm_declare_theorem_group_rule:nnnn}\marg{keyname}\marg{theorem group 1} +% \marg{relation}\marg{theorem group 2} +% \end{syntax} +% +% \LaTeX3 version of \cs{DeclareTheoremGroupRule} +% +% \end{function} +% +% +% \subsection{Grouped theorems} +% +% \begin{function}{\groupthm_new_grouped_theorem_from_keys:nn, \groupthm_provide_grouped_theorem_from_keys:nn} +% \begin{syntax} +% \cs{groupthm_provide_grouped_theorem_from_keys:nn}\marg{keys}\marg{environment name} +% \end{syntax} +% +% \LaTeX3 version of \cs{NewGroupedTheorem}, \cs{ProvideGroupedTheorem} +% +% +% \end{function} +% +% \begin{function} +% { +% \groupthm_new_grouped_theorem_star_from_keys:nn, +% \groupthm_provide_grouped_theorem_star_from_keys:nn +% } +% \begin{syntax} +% \cs{groupthm_new_grouped_theorem_star_from_keys:nn}\marg{keys}\marg{environment name} +% \end{syntax} +% +% +% \LaTeX3 version of \cs{NewGroupedTheorem*}, \cs{ProvideGroupedTheorem*} +% +% +% \end{function} +% +% +% +% \begin{function}{\groupthm_new_theorem_from_keys:nn, \groupthm_provide_theorem_from_keys:nn} +% \begin{syntax} +% \cs{groupthm_provide_theorem_from_keys:nn}\marg{keys}\marg{environment name} +% \end{syntax} +% +% \LaTeX3 version of \cs{NewTheorem}, \cs{ProvideTheorem} +% +% +% \end{function} +% +% \begin{function}{\groupthm_new_theorem_star_from_keys:nn, \groupthm_provide_theorem_star_from_keys:nn} +% \begin{syntax} +% \cs{groupthm_new_theorem_star_from_keys:nn}\marg{keys}\marg{environment name} +% \end{syntax} +% +% \LaTeX3 version of \cs{NewTheorem*}, \cs{ProvideTheorem*} +% +% \end{function} +% +% +% \begin{function} +% { +% \groupthm_new_grouped_theorem:nnnn, +% \groupthm_provide_grouped_theorem:nnnn, +% \groupthm_new_grouped_theorem_star:nnnn, +% \groupthm_provide_grouped_theorem_star:nnnn, +% \groupthm_new_theorem:nnnn, +% \groupthm_provide_theorem:nnnn, +% \groupthm_new_theorem_star:nnnn, +% \groupthm_provide_theorem_star:nnnn +% } +% \begin{syntax} +% \cs{groupthm_new_theorem:nnnn}\marg{environment name}\marg{groups clist} +% \marg{theorem name}\marg{thmtools keys} +% \end{syntax} +% +% Non-keyval versions of above macros. +% +% \end{function} +% +% +% \subsection{Theorem families} +% +% +% \begin{function} +% { +% \groupthm_new_grouped_theorem_family_from_keys:nn, +% \groupthm_provide_grouped_theorem_family_from_keys:nn +% } +% \begin{syntax} +% \cs{groupthm_new_grouped_theorem_family_from_keys:nn}\marg{keys}\marg{theorem family} +% \end{syntax} +% +% The \LaTeX3 versions of \cs{NewGroupedTheoremFamily} and \cs{ProvideGroupedTheoremFamily} +% +% \end{function} +% +% +% +% \begin{function} +% { +% \groupthm_new_grouped_theorem_family_star_from_keys:nn, +% \groupthm_provide_grouped_theorem_family_star_from_keys:nn +% } +% \begin{syntax} +% \cs{groupthm_new_grouped_theorem_family_star_from_keys:nn}\marg{keys}\marg{theorem family} +% \end{syntax} +% +% The \LaTeX3 versions of \cs{NewGroupedTheoremFamily*} and \cs{ProvideGroupedTheoremFamily*} +% +% \end{function} +% +% +% +% \begin{function} +% { +% \groupthm_new_theorem_family_from_keys:nn, +% \groupthm_provide_theorem_family_from_keys:nn +% } +% \begin{syntax} +% \cs{groupthm_new_theorem_family_from_keys:nn}\marg{keys}\marg{theorem family} +% \end{syntax} +% +% The \LaTeX3 versions of \cs{NewTheoremFamily} and \cs{ProvideTheoremFamily} +% +% \end{function} +% +% +% +% \begin{function} +% { +% \groupthm_new_theorem_family_star_from_keys:nn, +% \groupthm_provide_theorem_family_star_from_keys:nn +% } +% \begin{syntax} +% \cs{groupthm_new_theorem_family_star_from_keys:nn}\marg{keys}\marg{theorem family} +% \end{syntax} +% +% The \LaTeX3 versions of \cs{NewTheoremFamily*} and \cs{ProvideTheoremFamily*} +% +% \end{function} +% +% +% \begin{function} +% { +% \groupthm_new_grouped_theorem_family:nnnn, +% \groupthm_provide_grouped_theorem_family:nnnn, +% \groupthm_new_grouped_theorem_family_star:nnnn, +% \groupthm_provide_grouped_theorem_family_star:nnnn, +% \groupthm_new_theorem_family:nnnn, +% \groupthm_provide_theorem_family:nnnn, +% \groupthm_new_theorem_family_star:nnnn, +% \groupthm_provide_theorem_family_star:nnnn +% } +% \begin{syntax} +% \cs{groupthm_new_grouped_theorem_family:nnnn}\marg{theorem family} +% \marg{groups}\marg{name}\marg{thmtools clist} +% \end{syntax} +% +% The non-key-value versions of the prior macros. +% +% \end{function} +% +% \end{documentation} +% +% +% +% +% +% +% +% +% +% +% +% +% +% \begin{implementation} +% +% \section{\pkg{groupthm} implementation} +% +% \begin{macrocode} +%<*package> +% \end{macrocode} +% +% \begin{macrocode} +%<@@=groupthm> +% \end{macrocode} +% +% +% +% +% \subsection{Dependencies} +% +% +% +% First, we import other packages on which we rely on, and +% set up some private wrappers around these. +% \begin{macrocode} +\RequirePackage{amsthm} +\RequirePackage{thmtools} +% \end{macrocode} +% +% \begin{macro}{\@@_thmtools_declare_theorem:nn, \@@_thmtools_declare_theorem:Vn} +% \begin{syntax} +% \cs{@@_thmtools_declare_theorem:nn} \mymeta{theorem name}\mymeta{thmtools keyval args} +% \end{syntax} +% +% This is just a private wrapper around \cs{declaretheorem} of the \pkg{thmtools} package. +% +% \begin{macrocode} +\cs_new:Npn \@@_thmtools_declare_theorem:nn #1 #2 +{ + \tl_log:n { Declaring ~ thmtools ~ theorem ~ #2 } + \declaretheorem [ #1 ] { #2 } +} +\cs_generate_variant:Nn \@@_thmtools_declare_theorem:nn { V n } +% \end{macrocode} +% \end{macro} +% +% +% +% It also comes in handy to have a stronger version of the +% hook role setting mechanism: +% \begin{macro}{\@@_hook_gset_rule_foreach:nNnn} +% \begin{syntax} +% \cs{@@_hook_gset_rule_foreach:nNnn}\marg{hook}\mymeta{clist name}\mymeta{relation}\mymeta{label} +% \end{syntax} +% +% This is a wrapper around the \cs{hook_gset_rule:nnnn} macro +% that takes a clist name of labels, and executes the corresponding +% command for each such label. +% +% \begin{macrocode} +\cs_new:Npn \@@_hook_gset_rule_foreach:nNnn #1 #2 #3 #4 + { + \cs_set:Npn \@@_map_aux:n ##1 + { + \hook_gset_rule:nnnn { #1 } { ##1 } { #3 } { #4 } + } + \clist_map_function:NN #2 \@@_map_aux:n + } +% \end{macrocode} +% \end{macro} +% +% +% +% \subsection{Messages} +% These are messages that we might emit. +% +% When an unknown group is used somwhere: +% \begin{syntax} +% \cs{msg_error:nnn}\{ groupthm \}\{ unknown group \}\marg{groupname} +% \end{syntax} +% \begin{macrocode} +\msg_new:nnn { groupthm } { unknown ~ group } +{ + Unknown ~ group ~ '#1' ~ supplied ~ \msg_line_context: +} +% \end{macrocode} +% +% When an unknown key has been used: +% \begin{syntax} +% \cs{msg_error:nnn}\{ groupthm \}\{ unknown key \}\marg{key} +% \end{syntax} +% \begin{macrocode} +\msg_new:nnn { groupthm } { unknown ~ key } +{ + Unknown ~ key ~ '#1' ~ supplied ~ \msg_line_context: +} +% \end{macrocode} +% +% Some data structure is already defined or not defined yet. +% \begin{syntax} +% \cs{msg_error:nnnnn}\{ groupthm \}\{ wrong definition \} +% \marg{type}\marg{name}\marg{already $\|$ not} +% \end{syntax} +% \begin{macrocode} +\msg_new:nnn { groupthm } { wrong ~ definition } +{ + Bad ~ definition ~ of ~ #1 ~ '#2' ~ \msg_line_context:, ~ #1 ~ is ~ #3 ~ defined. +} +% \end{macrocode} +% +% +% When the special \cs{AddTheoremToGroup} macro is issued outside a theorem family options +% body. +% \begin{syntax} +% \cs{msg_error:nn} \{ groupthm \}\{ misuse add theorem to group \} +% \end{syntax} +% \begin{macrocode} +\msg_new:nnn { groupthm } { misuse ~ add ~ theorem ~ to ~ group } + { + Bad ~ usage ~ of ~ 'AddTheoremToGroup' ~ macro ~ outside ~ theorem ~ + family ~ options ~ \msg_line_context: + } +% \end{macrocode} +% +% +% +% When a theorem family is invoked, but has not been generated yet. +% \begin{syntax} +% \cs{msg_error:nn} \{ groupthm \}\{ undefined theorem variant \} +% \end{syntax} +% \begin{macrocode} +\msg_new:nnnn { groupthm } { undefined ~ theorem ~ variant } + { + Bad ~ call ~ of ~ theorem ~ variant ~ of ~ '#1' ~ \msg_line_context: + } + { + You ~ wanted ~ to ~ call ~ the ~ variant ~ with ~ group(s) ~ + '#2' ~ of ~ theorem ~ family ~ '#1', ~ but ~ it ~ has ~ not ~ been ~ + generated ~ yet. ~ + Probably ~ you ~ forgot ~ this. ~ + \msg_see_documentation_text:n { groupthm } + } +% \end{macrocode} +% +% \subsection{Allocation and initialization} +% +% We use hooks at several places. However, these are not intended for outer use, +% and we thus mark them with a preceding \texttt{__}. +% +% \begin{macrocode} +\hook_new:n { @@/prefix } +\hook_new:n { @@/suffix } +\hook_new:n { @@/mapname } +\hook_new:n { @@/thmtools } +% \end{macrocode} +% \begin{macrocode} +\hook_new:n { @@/groupsort } +% \end{macrocode} +% +% \begin{macro}{\hook_gset_rule:nnVn} +% \begin{syntax} +% \cs{hook_gset_rule:nnVn}\marg{hook}\marg{label 1}\marg{relation}\marg{label 2} +% \end{syntax} +% +% Just a variant of the usual \cs{hook_gset_rule:nnnn} macro that we use. +% +% \begin{macrocode} +\cs_generate_variant:Nn \hook_gset_rule:nnnn { n n V n } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{variable} +% { +% \l_@@_key_prefix_tl, \l_@@_key_name_tl, \l_@@_key_suffix_tl, +% \l_@@_key_group_clist, \l_@@_key_mapname_clist, \l_@@_key_thmtools_clist +% } +% These variables will be set by the key-value interface provided by +% \pkg{l3keys} and are used in various places in the package. +% \begin{macrocode} +\tl_new:N \l_@@_key_prefix_tl +\tl_new:N \l_@@_key_name_tl +\tl_new:N \l_@@_key_suffix_tl +\clist_new:N \l_@@_key_group_clist +\clist_new:N \l_@@_key_mapname_clist +\clist_new:N \l_@@_key_thmtools_clist +% \end{macrocode} +% \end{variable} +% +% \begin{variable} +% { +% \l_@@_prefix_tl, +% \l_@@_name_tl, +% \l_@@_suffix_tl, +% \l_@@_mapname_clist, +% \l_@@_thmtools_clist, +% \l_@@_group_clist +% } +% +% General local variables. +% Will typically be used to extract the variables set by the \pkg{l3keys} interface, +% but also in just a local variable sense. +% +% \begin{macrocode} +\tl_new:N \l_@@_prefix_tl +\tl_new:N \l_@@_name_tl +\tl_new:N \l_@@_suffix_tl +\clist_new:N \l_@@_mapname_clist +\clist_new:N \l_@@_thmtools_clist +\clist_new:N \l_@@_group_clist +% \end{macrocode} +% \end{variable} +% +% +% +% \begin{variable}{\g_@@_defined_theorem_groups_clist} +% +% This variable will hold a global list of declared theorem groups +% +% \begin{macrocode} +\clist_new:N \g_@@_defined_theorem_groups_clist +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_@@_in_family_options_environment_bool} +% This variable indicates whether we are in the special environment +% used to parse a set of groups out of options given to a theorem +% family. +% +% This bool toggles the availability of the special \cs{AddTheoremToGroup} macro. +% \begin{macrocode} +\bool_new:N \l_@@_in_family_options_environment_bool +% \end{macrocode} +% \end{variable} +% +% +% \subsection{Key interface} +% As mentioned, all keys will set their corresponding local variables +% (containing \enquote{\texttt{_key_}} in their name) and store the +% user input in these. +% +% Additionally, we group these keys by use cases, +% and provide defaults that in most cases will not require further handling. +% +% +% +% \begin{macrocode} +\keys_define:nn { groupthm } + { + prefix .tl_set:N = \l_@@_key_prefix_tl, + prefix .default:n = \c_empty_tl, + prefix .groups:n = { theoremgroup }, + name .tl_set:N = \l_@@_key_name_tl, + name .default:n = \c_novalue_tl, + name .groups:n = { groupedtheorem, theoremvariants }, + suffix .tl_set:N = \l_@@_key_suffix_tl, + suffix .default:n = \c_empty_tl, + suffix .groups:n = { theoremgroup }, + group .clist_set:N = \l_@@_key_group_clist, + group .default:n = {}, + group .groups:n = { groupedtheorem, theoremvariants }, + mapname .clist_set:N = \l_@@_mapname_clist, + mapname .default:n = {}, + mapname .groups:n = { theoremgroup }, + thmtools .clist_set:N = \l_@@_key_thmtools_clist, + thmtools .default:n = {}, + thmtools .groups:n = + { theoremgroup, groupedtheorem, theoremvariants }, + unknown .code:n = + \msg_error:nnn { groupthm } { unknown ~ group } { \l_keys_key_str } + } +% \end{macrocode} +% +% +% The only key whose default requires such handling is the \enquote{\texttt{name}} key, +% which will be set to a capitalized version of the environment name +% when not specified. +% +% +% \begin{macro}{\@@_set_normalized_keys:nnn} +% \begin{syntax} +% \cs{@@_set_normalized_keys:nnn}\marg{keys}\marg{key group}\marg{fallback name} +% \end{syntax} +% +% Sets the packages keys and normalizes the retrieved values, that is, +% clears old set keys, stores all keys in local variables, +% and replaces the \cs{l_@@_name_tl} with the capitalized version of the +% \mymeta{fallback name}. +% +% \begin{macrocode} +\cs_new:Npn \@@_set_normalized_keys:nnn #1 #2 #3 + { + \keys_set:nn { groupthm } { prefix, name, suffix, group, mapname, thmtools } + \keys_set_groups:nnn { groupthm } { #2 } { #1 } +% \end{macrocode} +% +% Normalize given name +% +% \begin{macrocode} + \tl_if_eq:NnTF \l_@@_key_name_tl { \c_novalue_tl } + { + \tl_set:Nx \l_@@_name_tl + { + \text_titlecase_first:n {#3} + } + } + { + \tl_set_eq:NN \l_@@_name_tl \l_@@_key_name_tl + } +% \end{macrocode} +% +% Copy set keys into local variables +% +% \begin{macrocode} + \tl_set_eq:NN \l_@@_prefix_tl \l_@@_key_prefix_tl + \tl_set_eq:NN \l_@@_suffix_tl \l_@@_key_suffix_tl + \clist_set_eq:NN \l_@@_group_clist \l_@@_key_group_clist + \clist_set_eq:NN \l_@@_mapname_clist \l_@@_key_mapname_clist + \clist_set_eq:NN \l_@@_thmtools_clist \l_@@_key_thmtools_clist + } +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Theorem groups} +% +% For technical reasons explained in the \todoref section, we need to +% some arbitrary, but unique total ordering on the set of all defined theorem groups. +% +% Since unfortunately (by now) there is no standard mechanism for sorting strings +% in \LaTeX3 directly, we use an ugly hack to achieve what we want: +% +% We will use an internal hook, and apply hook rules to each pair of internal groups +% such that the resulting relation is a total order. +% Whenever we want to sort a list of groups now, we do the following: +% First, for each group element in the list, insert into the hook the function +% \enquote{put this group back into the list}, using the group itself as a label. +% Then we clear the list, and finally execute the hook. +% +% Essentially, we thus split up the hook in the single groups, let the \LaTeX3 hook +% mechanism take care of the sorting, and restore the sorted single pieces into our list. +% Of course, this is very inefficient, but for now it seems to be the simplest solution, +% without having to implement an own string sorting function. +% +% Once there is such a proper mechanism, the author will likely update this to proper +% string sorting. +% +% \begin{macro}{\@@_add_to_theorem_group_ordering:n} +% \begin{syntax} +% \cs{@@_add_to_theorem_group_ordering:n}\marg{theorem group} +% \end{syntax} +% +% Sets hook relations for this group and all already defined theorem groups. +% +% \begin{macrocode} +\cs_new:Npn \@@_add_to_theorem_group_ordering:n #1 + { + \@@_hook_gset_rule_foreach:nNnn + { @@/groupsort } + \g_@@_defined_theorem_groups_clist + { before } + { #1 } + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\@@_remove_from_theorem_group_ordering:n} +% \begin{syntax} +% \cs{@@_remove_from_theorem_group_ordering:n}\marg{theorem group} +% \end{syntax} +% +% Removes all relations of this theorem group with the currently defined theorem groups. +% +% \begin{macrocode} +\cs_new:Npn \@@_remove_from_theorem_group_ordering:n #1 + { + \@@_hook_gset_rule_foreach:nNnn + { @@/groupsort } + \g_@@_defined_theorem_groups_clist + { unrelated } + { #1 } + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\@@_add_to_sort_hook:n} +% \begin{syntax} +% \cs{@@_add_to_sort_hook:n}\marg{theorem group} +% \end{syntax} +% +% Adds the theorem group into the sort hook to be restored later from it. +% This already uses the assumption, that we want to use the \cs{l_@@_group_clist} +% variable (which we do). +% +% \begin{macrocode} +\cs_new:Npn \@@_add_to_sort_hook:n #1 +{ + \hook_gput_code:nnn { @@/groupsort } + { #1 } + { + \clist_put_left:Nn \l_@@_group_clist { #1 } + } +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\@@_sort_theorem_group_names:} +% +% As explained briefly before, we first insert all theorems +% into the hook, clear the list, and then use the hook again. +% +% This then sorts the \cs{l_@@_group_clist} variable, +% which is also assumed to hold only defined theorem group names. +% +% \begin{macrocode} +\cs_new:Npn \@@_sort_theorem_group_names: + { + \hook_gremove_code:nn { @@/groupsort }{*} + \clist_map_function:NN \l_@@_group_clist \@@_add_to_sort_hook:n + \clist_clear:N \l_@@_group_clist + \hook_use:n { @@/groupsort } + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\@@_define_group_aux:nnnnn} +% \begin{syntax} +% \cs{@@_define_group_aux:nnnnn}\marg{theorem group}\marg{prefix tl} +% \marg{suffix tl}\marg{mapname clist}\marg{thmtools clist} +% \end{syntax} +% +% This creates a new theorem group out of the given parameters. +% We store all given contents in our (private) hooks, using the group name as the key +% so that we can later retrieve the components of each group separately. +% +% This is an internal function and assumes that the group is currently not defined, +% and also removed from all hooks. +% +% +% \begin{macrocode} +\cs_new:Npn \@@_define_group_aux:nnnnn #1#2#3#4#5 + { +% \end{macrocode} +% +% \begin{macro}{\@@_use_group_\meta{theorem group}:} +% +% This is the internal macro that will be called when retrieving contents of a group. +% We define this here to store the properties of the group. +% +% \begin{macrocode} + \cs_new:cpn { @@_use_group_#1: } + { + \hook_gput_code:nnn { @@/prefix } { #1 } + { + \tl_put_left:Nx \l_@@_prefix_tl { #2 } + } + \hook_gput_code:nnn { @@/suffix } { #1 } + { + \tl_put_right:Nx \l_@@_suffix_tl { #3 } + } + \hook_gput_code:nnn { @@/mapname } { #1 } + { + \clist_put_right:Nn \l_@@_mapname_clist { #4 } + } + \hook_gput_code:nnn { @@/thmtools } { #1 } + { + \clist_put_right:Nn \l_@@_thmtools_clist { #5 } + } + } +% \end{macrocode} +% \end{macro} +% +% This ensures the ordering hacks explained before. +% +% \begin{macrocode} + \@@_add_to_theorem_group_ordering:n { #1 } +% \end{macrocode} +% +% Add defined group to corresponding list +% +% \begin{macrocode} + \clist_gput_left:Nn \g_@@_defined_theorem_groups_clist { #1 } + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\@@_undefine_group_aux:n} +% \begin{syntax} +% \cs{@@_undefine_group_aux:n}\marg{theorem group} +% \end{syntax} +% +% Undeclares / undefines the given theorem group. +% This means removing its hook code in the \texttt{prefix}, \texttt{suffix}, +% \texttt{mapname} and \texttt{thmtools} hooks, +% and removing all relations with other theorem groups globally +% as well as for each hook individually. +% +% This macro assumes that the group was defined prior to calling. +% +% \begin{macrocode} +\cs_new:Npn \@@_undefine_group_aux:n #1 + { + \cs_undefine:c { @@_use_group_#1: } +% \end{macrocode} +% +% Remove properties from hooks +% +% \begin{macrocode} + \hook_gremove_code:nn { @@/prefix } { #1 } + \hook_gremove_code:nn { @@/suffix } { #1 } + \hook_gremove_code:nn { @@/mapname } { #1 } + \hook_gremove_code:nn { @@/thmtools } { #1 } +% \end{macrocode} +% +% Remove theorem group from list of defined theorems +% +% \begin{macrocode} + \clist_gremove_all:Nn \g_@@_defined_theorem_groups_clist { #1 } +% \end{macrocode} +% +% Now, unset all relations with all defined theorem groups in the internal hooks. +% +% \begin{macrocode} + \@@_hook_gset_rule_foreach:nNnn + { ?? } + \g_@@_defined_theorem_groups_clist + { unrelated } + { #1 } + \@@_hook_gset_rule_foreach:nNnn + { @@/prefix } + \g_@@_defined_theorem_groups_clist + { unrelated } + { #1 } + \@@_hook_gset_rule_foreach:nNnn + { @@/suffix } + \g_@@_defined_theorem_groups_clist + { unrelated } + { #1 } + \@@_hook_gset_rule_foreach:nNnn + { @@/mapname } + \g_@@_defined_theorem_groups_clist + { unrelated } + { #1 } + \@@_hook_gset_rule_foreach:nNnn + { @@/thmtools } + \g_@@_defined_theorem_groups_clist + { unrelated } + { #1 } +% \end{macrocode} +% +% Also clear all sorting relations +% +% \begin{macrocode} + \@@_remove_from_theorem_group_ordering:n { #1 } + } +% \end{macrocode} +% \end{macro} +% +% With these two helper functions, we can now easily implement the +% \texttt{new}, \texttt{renew}, \texttt{provide} and \texttt{declare} variants +% of the theorem group macro: +% +% \begin{macro}{\groupthm_new_theorem_group:nnnnn, \groupthm_new_theorem_group:nVVVV} +% +% \begin{macrocode} +\cs_new:Npn \@@_define_aux:nnnNNNn #1 #2 #3 #4 #5 #6 #7 +{ + \bool_if:nT + { + \str_if_eq_p:nn { #1 } { new } + && + \cs_if_exist_p:N #4 + } + { + \msg_error:nnnn { groupthm } { wrong ~ definition } + { #2 } { #3 } { already } + } + + \bool_if:nT + { + \str_if_eq_p:nn { #1 } { renew } + && + ! \cs_if_exist_p:N #4 + } + { + \msg_error:nnnn { groupthm } { wrong ~ definition } + { #2 } { #3 } { not } + } + + \bool_if:nT + { + ( + \str_if_eq_p:nn { #1 } { declare } || + \str_if_eq_p:nn { #1 } { renew } + ) && + \cs_if_exist_p:N #4 + } + { + #5 { #1 } + } + + #6 #7 +} +\cs_generate_variant:Nn \@@_define_aux:nnnNNNn { n n n c N N n } + +\cs_new:Npn \@@_define_list_aux:nnnNNnn #1 #2 #3 #4 #5 #6 #7 +{ + \cs_set:Npn \@@_map_aux:n ##1 + { + \cs_new:cn { #6 } + { + \@@_define_aux:nnncNNn + { ##1 } + { #2 } + { ####1 } + { #3 } + #4 + #5 + { + #7 + } + } + } + \cs_show:N \@@_map_aux:n + + \clist_map_function:nN { #1 } \@@_map_aux:n +} + + +\@@_define_list_aux:nnnNNnn + { new, renew, provide, declare } + { theorem group } + { @@_use_group_##1: } + \@@_undefine_group_aux:n + \@@_define_group_aux:nnnnn + { groupthm_#1_group:nnnnn } + { { ##1 } { ##2 } { ##3 } { ##4 } { ##5 } } +% \end{macrocode} +% +% Finally, generate some extra variant. +% +% \begin{macrocode} +\cs_generate_variant:Nn \groupthm_new_theorem_group:nnnnn { n V V V V } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} + +% \end{macrocode} +% +% +% +% With the \cs{@@_set_normalized_keys:nnn} macro at hand, +% it is also easy to provide key-value interfaces for these commands: +% +% \begin{macro}{\groupthm_new_theorem_group_from_keys:nn} +% \begin{syntax} +% \cs{groupthm_new_theorem_group_from_keys:nn}\marg{keys}\marg{theorem group} +% \end{syntax} +% +% \begin{macrocode} +\cs_new:Npn \groupthm_new_theorem_group_from_keys:nn #1#2 +{ + \@@_set_normalized_keys:nnn { #1 } { theoremgroup } { #2 } + \groupthm_new_theorem_group:nVVVV { #2 } + \l_@@_prefix_tl + \l_@@_suffix_tl + \l_@@_mapname_clist + \l_@@_thmtools_clist +} +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\groupthm_renew_theorem_group_from_keys:nn} +% \begin{syntax} +% \cs{groupthm_renew_theorem_group_from_keys:nn}\marg{keys}\marg{theorem group} +% \end{syntax} +% +% \begin{macrocode} +\cs_new:Npn \groupthm_renew_theorem_group_from_keys:nn #1#2 +{ + \@@_set_normalized_keys:nnn { #1 } { theoremgroup } { #2 } + \groupthm_renew_theorem_group:nVVVV { #2 } + \l_@@_prefix_tl + \l_@@_suffix_tl + \l_@@_mapname_clist + \l_@@_thmtools_clist +} +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\groupthm_provide_theorem_group_from_keys:nn} +% \begin{syntax} +% \cs{groupthm_provide_theorem_group_from_keys:nn}\marg{keys}\marg{theorem group} +% \end{syntax} +% +% \begin{macrocode} +\cs_new:Npn \groupthm_provide_theorem_group_from_keys:nn #1#2 +{ + \@@_set_normalized_keys:nnn { #1 } { theoremgroup } { #2 } + \groupthm_provide_theorem_group:nVVVV { #2 } + \l_@@_prefix_tl + \l_@@_suffix_tl + \l_@@_mapname_clist + \l_@@_thmtools_clist +} +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\groupthm_declare_theorem_group_from_keys:nn} +% \begin{syntax} +% \cs{groupthm_declare_theorem_group_from_keys:nn}\marg{keys}\marg{theorem group} +% \end{syntax} +% +% \begin{macrocode} +\cs_new:Npn \groupthm_declare_theorem_group_from_keys:nn #1#2 +{ + \@@_set_normalized_keys:nnn { #1 } { theoremgroup } { #2 } + \groupthm_declare_theorem_group:nVVVV { #2 } + \l_@@_prefix_tl + \l_@@_suffix_tl + \l_@@_mapname_clist + \l_@@_thmtools_clist +} +% \end{macrocode} +% \end{macro} +% +% +% Finally, we provide \LaTeX2e wrappers as document commands for these. +% +% +% \begin{macro}{\NewTheoremGroup} +% +% \begin{macrocode} +\NewDocumentCommand{\NewTheoremGroup}{ O{} m } + { + \groupthm_new_theorem_group_from_keys:nn { #1 } { #2 } + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\RenewTheoremGroup} +% +% \begin{macrocode} +\NewDocumentCommand{\RenewTheoremGroup}{ O{} m } + { + \groupthm_renew_theorem_group_from_keys:nn { #1 } { #2 } + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\ProvideTheoremGroup} +% +% \begin{macrocode} +\NewDocumentCommand{\ProvideTheoremGroup}{ O{} m } + { + \groupthm_provide_theorem_group_from_keys:nn { #1 } { #2 } + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\DeclareTheoremGroup} +% +% \begin{macrocode} +\NewDocumentCommand{\DeclareTheoremGroup}{ O{} m } + { + \groupthm_declare_theorem_group_from_keys:nn { #1 } { #2 } + } +% \end{macrocode} +% \end{macro} +% +% We also provide the interface for declaring the precedence rules for theorem groups. +% +% +% \begin{macro}{\groupthm_declare_theorem_group_rule:nnnn} +% \begin{syntax} +% \cs{groupthm_declare_theorem_group_rule:nnnn}\marg{keyname}\marg{theorem group 1} +% \marg{relation}\marg{theorem group 2} +% \end{syntax} +% +% We have to normalize the arguments a little bit, namely replacing \texttt{higher} +% and \texttt{lower} with \texttt{before} \texttt{after} respectively, +% and prefix the \mymeta{keyname} with \texttt{__groupthm} +% in case it is not the general hook \enquote{\texttt{??}}. +% +% \begin{macrocode} +\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 { @@ / #1 } {#2} \l_tmpa_tl {#4} + } + } +% \end{macrocode} +% \end{macro} + +% \begin{macro}{\DeclareTheoremGroupRule} +% \begin{syntax} +% \cs{DeclareTheoremGroupRule}\oarg{keyname}% +% \marg{theorem group 1}\marg{relation}\marg{theorem group 2} +% \end{syntax} +% +% \begin{macrocode} +\NewDocumentCommand { \DeclareTheoremGroupRule } { O{??} m m m } + { + \groupthm_declare_theorem_group_rule:nnnn {#1} {#2} {#3} {#4} + } +% \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}\mymeta{clist}\marg{code} +% \end{syntax} +% +% Executes \mymeta{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 \mymeta{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}\mymeta{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}\mymeta{function} +% \end{syntax} +% +% The \mymeta{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}\marg{environment name} +% \marg{groups clist}\marg{theorem name}\marg{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_@@_prefix_tl + \tl_set:Nn \l_@@_name_tl { #3 } + \tl_clear:N \l_@@_suffix_tl + \clist_clear:N \l_@@_mapname_clist + \clist_clear:N \l_@@_thmtools_clist +% \end{macrocode} +% Clear all hooks +% \begin{macrocode} + \hook_gremove_code:nn { @@/prefix }{*} + \hook_gremove_code:nn { @@/suffix }{*} + \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 } \@@_use_theorem_group: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 { @@/prefix } + \hook_use:n { @@/suffix } + \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_@@_prefix_tl + \tl_use:N \l_@@_name_tl + \tl_use:N \l_@@_suffix_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:Nn \l_@@_thmtools_clist { #4 } +% \end{macrocode} +% We can now pass our list to \pkg{thmtools}, declaring the theorem. +% \begin{macrocode} + \@@_thmtools_declare_theorem:Vn + \l_@@_thmtools_clist + { #1 } + } +% \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, +% \groupthm_new_grouped_theorem:nVVV, +% \groupthm_new_grouped_theorem:xVnn +% } +% \begin{syntax} +% \cs{groupthm_new_grouped_theorem:nnnn}\marg{environment name} +% \marg{groups clist}\marg{theorem name}\marg{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:nnnnn { groupthm } { wrong ~ definition } + { grouped ~ theorem } { #1 } { already } + } + { + \@@_declare_grouped_theorem_aux:nnnn + { #1 } { #2 } { #3 } { #4 } + } + } +\cs_generate_variant:Nn \groupthm_new_grouped_theorem:nnnn { n V V V } +% \end{macrocode} +% We need this extra variant here for the generation of theorem families later: +% \begin{macrocode} +\cs_generate_variant:Nn \groupthm_new_grouped_theorem:nnnn { x V n n } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\groupthm_provide_grouped_theorem:nnnn,\groupthm_provide_grouped_theorem:nVVV} +% +% \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 } + { + \@@_declare_grouped_theorem_aux:nnnn + { #1 } { #2 } { #3 } { #4 } + } + } +\cs_generate_variant:Nn \groupthm_provide_grouped_theorem:nnnn { n V V V } +% \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{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}\marg{environment name} +% \marg{groups clist}\marg{theorem name}\marg{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,\groupthm_new_theorem:nVVV} +% \begin{syntax} +% \cs{groupthm_new_theorem:nnnn}\marg{environment name} +% \marg{groups clist}\marg{theorem name}\marg{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 } + } +\cs_generate_variant:Nn \groupthm_new_theorem:nnnn { n V V V } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\groupthm_provide_theorem:nnnn,\groupthm_provide_theorem:nVVV} +% \begin{syntax} +% \cs{groupthm_provide_theorem:nnnn}\marg{environment name} +% \marg{groups clist}\marg{theorem name}\marg{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 } + } +\cs_generate_variant:Nn \groupthm_provide_theorem:nnnn { n V V V } +% \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}\marg{environment name} +% \marg{groups clist}\marg{theorem name}\marg{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}\marg{environment name} +% \marg{groups clist}\marg{theorem name}\marg{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. +% All of these work in the same way: +% We set the normalized keys, and then pass these by value to the +% previously defined macros +% +% +% \begin{macro}{\groupthm_new_grouped_theorem_from_keys:nn} +% \begin{macrocode} +\cs_new:Npn \groupthm_new_grouped_theorem_from_keys:nn #1 #2 + { + \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 } + + \groupthm_new_grouped_theorem:nVVV + { #1 } + \l_@@_key_group_clist + \l_@@_name_tl + \l_@@_key_thmtools_clist + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\groupthm_provide_grouped_theorem_from_keys:nn} +% \begin{macrocode} +\cs_new:Npn \groupthm_provide_grouped_theorem_from_keys:nn #1 #2 + { + \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 } + + \groupthm_provide_grouped_theorem:nVVV + { #1 } + \l_@@_key_group_clist + \l_@@_name_tl + \l_@@_key_thmtools_clist + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\groupthm_new_grouped_theorem_star_from_keys:nn} +% \begin{macrocode} +\cs_new:Npn \groupthm_new_grouped_theorem_star_from_keys:nn #1 #2 + { + \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 } + + \groupthm_new_grouped_theorem_star:nVVV + { #2 } + \l_@@_key_group_clist + \l_@@_name_tl + \l_@@_key_thmtools_clist + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\groupthm_provide_grouped_theorem_star_from_keys:nn} +% \begin{macrocode} +\cs_new:Npn \groupthm_provide_grouped_theorem_star_from_keys:nn #1 #2 + { + \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 } + + \groupthm_provide_grouped_theorem_star:nVVV + { #2 } + \l_@@_key_group_clist + \l_@@_name_tl + \l_@@_key_thmtools_clist + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\groupthm_new_theorem_from_keys:nn} +% \begin{macrocode} +\cs_new:Npn \groupthm_new_theorem_from_keys:nn #1 #2 + { + \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 } + + \groupthm_new_theorem:nVVV + { #2 } + \l_@@_key_group_clist + \l_@@_name_tl + \l_@@_key_thmtools_clist + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\groupthm_provide_theorem_from_keys:nn} +% \begin{macrocode} +\cs_new:Npn \groupthm_provide_theorem_from_keys:nn #1 #2 + { + \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 } + + \groupthm_provide_theorem:nVVV + { #2 } + \l_@@_key_group_clist + \l_@@_name_tl + \l_@@_key_thmtools_clist + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\groupthm_new_theorem_star_from_keys:nn} +% \begin{macrocode} +\cs_new:Npn \groupthm_new_theorem_star_from_keys:nn #1 #2 + { + \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 } + + \groupthm_new_theorem_star:nVVV + { #1 } + \l_@@_key_group_clist + \l_@@_name_tl + \l_@@_key_thmtools_clist + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\groupthm_provide_theorem_star_from_keys:nn} +% \begin{macrocode} +\cs_new:Npn \groupthm_provide_theorem_star_from_keys:nn #1 #2 + { + \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 } + + \groupthm_provide_theorem_star:nVVV + { #1 } + \l_@@_key_group_clist + \l_@@_name_tl + \l_@@_key_thmtools_clist + } +% \end{macrocode} +% \end{macro} +% +% +% +% Now, we can wrap these into document commands +% +% +% \begin{macro}{\NewGroupedTheorem, \NewGroupedTheorem*} +% \begin{syntax} +% \cs{NewGroupedTheorem}\oarg{keys}\marg{theorem name} +% \end{syntax} +% +% \begin{macrocode} +\NewDocumentCommand{\NewGroupedTheorem}{s O{} m} + { + \IfBooleanTF{#1} + { + \groupthm_new_grouped_theorem_star_from_keys:nn { #2 } { #3 } + } + { + \groupthm_new_grouped_theorem_from_keys:nn { #2 } { #3 } + } + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\ProvideGroupedTheorem, \ProvideGroupedTheorem*} +% \begin{syntax} +% \cs{ProvideGroupedTheorem}\oarg{keys}\marg{theorem name} +% \end{syntax} +% +% \begin{macrocode} +\ProvideDocumentCommand{\NewGroupedTheorem}{s O{} m} + { + \IfBooleanTF{#1} + { + \groupthm_provide_grouped_theorem_star_from_keys:nn { #2 } { #3 } + } + { + \groupthm_provide_grouped_theorem_from_keys:nn { #2 } { #3 } + } + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\NewTheorem, \NewTheorem*} +% \begin{syntax} +% \cs{NewTheorem}\oarg{keys}\marg{theorem name} +% \end{syntax} +% +% \begin{macrocode} +\NewDocumentCommand{\NewTheorem}{s O{} m} + { + \IfBooleanTF{#1} + { + \groupthm_new_theorem_star_from_keys:nn { #2 } { #3 } + } + { + \groupthm_new_theorem_from_keys:nn { #2 } { #3 } + } + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\ProvideTheorem, \ProvideTheorem*} +% \begin{syntax} +% \cs{ProvideTheorem}\oarg{keys}\marg{theorem name} +% \end{syntax} +% +% \begin{macrocode} +\ProvideDocumentCommand{\NewTheorem}{s O{} m} + { + \IfBooleanTF{#1} + { + \groupthm_provide_theorem_star_from_keys:nn { #2 } { #3 } + } + { + \groupthm_provide_theorem_from_keys:nn { #2 } { #3 } + } + } +% \end{macrocode} +% \end{macro} +% +% +% +% +% \subsection{Theorem families} +% +% +% We now want to implement the generation of theorem families and their +% corresponding options. +% As a backend, we use the following auxiliary function +% +% +% \begin{macro}{\@@_declare_grouped_theorem_family_aux:nnnnnn} +% \begin{syntax} +% \cs{@@_declare_grouped_theorem_family_aux:nnnnnn}\marg{family name}\marg{groups clist} +% \marg{name}\marg{name}\marg{thmtools clist}\marg{extra groups clist}\marg{generation type} +% \end{syntax} +% +% This will generate a new grouped theorem for each union of a subset of \mymeta{groups clist} +% and the extra set \mymeta{extra groups clist}, with the given properties, that is +% the \mymeta{nam} and \mymeta{thmtools clist} will be passed to the grouped theorem. +% The \mymeta{theorem name} of the grouped theorem will be an internal name that contains +% the \mymeta{family name} and the list of groups of this variant, that will be generated +% in a unique manner to later retrieve the generated theorems when parsing theorem families. +% +% The \mymeta{generation type} can be either \texttt{new} or \texttt{provide}, +% depending on which backend for grouped theorem generation to use +% \begin{macrocode} +\cs_new:Npn \@@_declare_grouped_theorem_family_aux:nnnnnn #1 #2 #3 #4 #5 #6 + { +% \end{macrocode} +% Make a local copy of the \mymeta{groups clist} argument, +% and iterate over its powerset +% \begin{macrocode} + \clist_set:Nn \l_tmpa_clist { #2 } + \powerset_clist_foreach:Nn \l_tmpa_clist + { +% \end{macrocode} +% We read out the current value of the list, and append the extra groups +% This ensures that now \cs{l_@@_group_clist} iterates over the proper subsets +% \begin{macrocode} + \clist_set_eq:NN \l_@@_group_clist \l_tmpa_clist + \clist_put_right:Nn \l_@@_group_clist { #5 } +% \end{macrocode} +% This sorting is necessary so that for each theorem family and set of groups, +% the generated name will be unique: +% \begin{macrocode} + \@@_sort_theorem_group_names: +% \end{macrocode} +% Now just declare the grouped theorem, passing the corresponding arguments and using +% specified \texttt{\#6} as backend. +% \begin{macrocode} + \use:c{groupthm_#6_grouped_theorem:xVnn} + {__#1__groups_\clist_use:Nn \l_@@_group_clist {_}} + \l_@@_group_clist + { #3 } + { #4 } + } + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\groupthm_new_grouped_theorem_family:nnnn,\groupthm_new_grouped_theorem_family:nVVV} +% \begin{syntax} +% \cs{groupthm_new_grouped_theorem_family:nnnn}\marg{family name} +% \marg{groups}\marg{name}\marg{thmtools clist} +% \end{syntax} +% +% Just pass the arguments to the auxiliary function, with no additional groups +% and the \texttt{new} backend. +% +% \begin{macrocode} +\cs_new:Npn \groupthm_new_grouped_theorem_family:nnnn #1 #2 #3 #4 + { + \@@_declare_grouped_theorem_family_aux:nnnnnn + { #1 } { #2 } { #3 } { #4 } { } { new } + } +\cs_generate_variant:Nn \groupthm_new_grouped_theorem_family:nnnn { n V V V } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\groupthm_provide_grouped_theorem_family:nnnn,\groupthm_provide_grouped_theorem_family:nVVV} +% \begin{syntax} +% \cs{groupthm_provide_grouped_theorem_family:nnnn}\marg{family name} +% \marg{groups}\marg{name}\marg{thmtools clist} +% \end{syntax} +% +% Just pass the arguments to the auxiliary function, with no additional groups +% and the \texttt{provide} backend. +% +% \begin{macrocode} +\cs_new:Npn \groupthm_provide_grouped_theorem_family:nnnn #1 #2 #3 #4 + { + \@@_declare_grouped_theorem_family_aux:nnnnnn + { #1 } { #2 } { #3 } { #4 } { } { provide } + } +\cs_generate_variant:Nn \groupthm_provide_grouped_theorem_family:nnnn { n V V V } +% \end{macrocode} +% \end{macro} +% +% +% The starred variants that add the \texttt{unnumbered} group are straightforward: +% +% +% +% \begin{macro}{\groupthm_new_grouped_theorem_family_star:nnnn,\groupthm_new_grouped_theorem_family_star:nVVV} +% \begin{syntax} +% \cs{groupthm_new_grouped_theorem_family_star:nnnn}\marg{family name} +% \marg{groups}\marg{name}\marg{thmtools clist} +% \end{syntax} +% +% Just pass the arguments to the auxiliary function, with the additional +% \texttt{unnumbered group} and the \texttt{new} backend. +% +% \begin{macrocode} +\cs_new:Npn \groupthm_new_grouped_theorem_family_star:nnnn #1 #2 #3 #4 + { + \@@_declare_grouped_theorem_family_aux:nnnnnn + { #1 } { #2 } { #3 } { #4 } { unnumbered } { new } + } +\cs_generate_variant:Nn \groupthm_new_grouped_theorem_family_star:nnnn { n V V V } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\groupthm_provide_grouped_theorem_family_star:nnnn,\groupthm_provide_grouped_theorem_family_star:nVVV} +% \begin{syntax} +% \cs{groupthm_provide_grouped_theorem_family_star:nnnn}\marg{family name} +% \marg{groups}\marg{name}\marg{thmtools clist} +% \end{syntax} +% +% Just pass the arguments to the auxiliary function, with the additional +% \texttt{unnumbered group} and the \texttt{provide} backend. +% +% \begin{macrocode} +\cs_new:Npn \groupthm_provide_grouped_theorem_family_star:nnnn #1 #2 #3 #4 + { + \@@_declare_grouped_theorem_family_aux:nnnnnn + { #1 } { #2 } { #3 } { #4 } { } { provide } + } +\cs_generate_variant:Nn \groupthm_provide_grouped_theorem_family_star:nnnn { n V V V } +% \end{macrocode} +% \end{macro} +% +% +% Now define the variants that also generate the starred and unstarred family versions. +% +% +% \begin{macro}{\groupthm_new_theorem_family:nnnn,\groupthm_new_theorem_family:nVVV} +% \begin{syntax} +% \cs{groupthm_new_theorem_family:nnnn}\marg{family name} +% \marg{groups}\marg{name}\marg{thmtools clist} +% \end{syntax} +% +% +% \begin{macrocode} +\cs_new:Npn \groupthm_new_theorem_family:nnnn #1 #2 #3 #4 + { + \@@_declare_grouped_theorem_family_aux:nnnnnn + { #1 } { #2, starred } { #3 } { #4 } { } { new } + } +\cs_generate_variant:Nn \groupthm_new_theorem_family:nnnn { n V V V } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\groupthm_provide_theorem_family:nnnn,\groupthm_provide_theorem_family:nVVV} +% \begin{syntax} +% \cs{groupthm_provide_theorem_family:nnnn}\marg{family name} +% \marg{groups}\marg{name}\marg{thmtools clist} +% \end{syntax} +% +% +% \begin{macrocode} +\cs_new:Npn \groupthm_provide_theorem_family:nnnn #1 #2 #3 #4 + { + \@@_declare_grouped_theorem_family_aux:nnnnnn + { #1 } { #2, starred } { #3 } { #4 } { } { provide } + } +\cs_generate_variant:Nn \groupthm_provide_theorem_family:nnnn { n V V V } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\groupthm_new_theorem_family_star:nnnn,\groupthm_new_theorem_family_star:nVVV} +% \begin{syntax} +% \cs{groupthm_new_theorem_family_star:nnnn}\marg{family name} +% \marg{groups}\marg{name}\marg{thmtools clist} +% \end{syntax} +% +% +% \begin{macrocode} +\cs_new:Npn \groupthm_new_theorem_family_star:nnnn #1 #2 #3 #4 + { + \@@_declare_grouped_theorem_family_aux:nnnnnn + { #1 } { #2, starred } { #3 } { #4 } { unnumbered } { new } + } +\cs_generate_variant:Nn \groupthm_new_theorem_family_star:nnnn { n V V V } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\groupthm_provide_theorem_family_star:nnnn,\groupthm_provide_theorem_family_star:nVVV} +% \begin{syntax} +% \cs{groupthm_provide_theorem_family_star:nnnn}\marg{family name} +% \marg{groups}\marg{name}\marg{thmtools clist} +% \end{syntax} +% +% +% \begin{macrocode} +\cs_new:Npn \groupthm_provide_theorem_family_star:nnnn #1 #2 #3 #4 + { + \@@_declare_grouped_theorem_family_aux:nnnnnn + { #1 } { #2, starred } { #3 } { #4 } { } { provide } + } +\cs_generate_variant:Nn \groupthm_provide_theorem_family_star:nnnn { n V V V } +% \end{macrocode} +% \end{macro} +% +% +% +% We now make the key variants available of these, all of the work in the same way +% as we just have to set the normalized keys and pass to our non-key-value versions. +% +% +% +% +% \begin{macro}{\groupthm_new_grouped_theorem_family_from_keys:nn} +% \begin{syntax} +% \cs{groupthm_new_grouped_theorem_family_from_keys:nn}\marg{keys}\marg{family name} +% \end{syntax} +% +% Just retrieve the normalized keys and pass on arguments. +% +% \begin{macrocode} +\cs_new:Npn \groupthm_new_grouped_theorem_family_from_keys:nn #1 #2 + { + \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 } + \groupthm_new_grouped_theorem_family:nVVV + { #2 } + \l_@@_group_clist + \l_@@_name_tl + \l_@@_thmtools_clist + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\groupthm_provide_grouped_theorem_family_from_keys:nn} +% \begin{syntax} +% \cs{groupthm_provide_grouped_theorem_family_from_keys:nn}\marg{keys}\marg{family name} +% \end{syntax} +% +% Just retrieve the normalized keys and pass on arguments. +% +% \begin{macrocode} +\cs_new:Npn \groupthm_provide_grouped_theorem_family_from_keys:nn #1 #2 + { + \@@_set_normalized_keys:nnn { #1 } {groupedtheorem} { #2 } + \groupthm_provide_grouped_theorem_family:nVVV + { #2 } + \l_@@_group_clist + \l_@@_name_tl + \l_@@_thmtools_clist + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\groupthm_new_grouped_theorem_family_star_from_keys:nn} +% \begin{syntax} +% \cs{groupthm_new_grouped_theorem_family_star_from_keys:nn}\marg{keys}\marg{family name} +% \end{syntax} +% +% Just retrieve the normalized keys and pass on arguments. +% +% \begin{macrocode} +\cs_new:Npn \groupthm_new_grouped_theorem_family_star_from_keys:nn #1 #2 + { + \@@_set_normalized_keys:nnn { #1 } { groupedtheorem }{ #2 } + \groupthm_new_grouped_theorem_family_star:nVVV + { #2 } + \l_@@_group_clist + \l_@@_name_tl + \l_@@_thmtools_clist + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\groupthm_provide_grouped_theorem_family_star_from_keys:nn} +% \begin{syntax} +% \cs{groupthm_provide_grouped_theorem_family_star_from_keys:nn}\marg{keys}\marg{family name} +% \end{syntax} +% +% Just retrieve the normalized keys and pass on arguments. +% +% \begin{macrocode} +\cs_new:Npn \groupthm_provide_grouped_theorem_family_star_from_keys:nn #1 #2 + { + \@@_set_normalized_keys:nnn { #1 } { groupedtheorem }{ #2 } + \groupthm_provide_grouped_theorem_family_star:nVVV + { #2 } + \l_@@_group_clist + \l_@@_name_tl + \l_@@_thmtools_clist + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\groupthm_new_theorem_family_from_keys:nn} +% \begin{syntax} +% \cs{groupthm_new_theorem_family_from_keys:nn}\marg{keys}\marg{family name} +% \end{syntax} +% +% Just retrieve the normalized keys and pass on arguments. +% +% \begin{macrocode} +\cs_new:Npn \groupthm_new_theorem_family_from_keys:nn #1 #2 + { + \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 } + \groupthm_new_theorem_family:nVVV + { #2 } + \l_@@_group_clist + \l_@@_name_tl + \l_@@_thmtools_clist + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\groupthm_provide_theorem_family_from_keys:nn} +% \begin{syntax} +% \cs{groupthm_provide_theorem_family_from_keys:nn}\marg{keys}\marg{family name} +% \end{syntax} +% +% Just retrieve the normalized keys and pass on arguments. +% +% \begin{macrocode} +\cs_new:Npn \groupthm_provide_theorem_family_from_keys:nn #1 #2 + { + \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 } + \groupthm_provide_theorem_family:nVVV + { #2 } + \l_@@_group_clist + \l_@@_name_tl + \l_@@_thmtools_clist + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\groupthm_new_theorem_family_star_from_keys:nn} +% \begin{syntax} +% \cs{groupthm_new_theorem_family_star_from_keys:nn}\marg{keys}\marg{family name} +% \end{syntax} +% +% Just retrieve the normalized keys and pass on arguments. +% +% \begin{macrocode} +\cs_new:Npn \groupthm_new_theorem_family_star_from_keys:nn #1 #2 + { + \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 } + \groupthm_new_theorem_family_star:nVVV + { #2 } + \l_@@_group_clist + \l_@@_name_tl + \l_@@_thmtools_clist + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\groupthm_provide_theorem_family_star_from_keys:nn} +% \begin{syntax} +% \cs{groupthm_provide_theorem_family_star_from_keys:nn}\marg{keys}\marg{family name} +% \end{syntax} +% +% Just retrieve the normalized keys and pass on arguments. +% +% \begin{macrocode} +\cs_new:Npn \groupthm_provide_theorem_family_star_from_keys:nn #1 #2 + { + \@@_set_normalized_keys:nnn { #1 } { groupedtheorem } { #2 } + \groupthm_provide_theorem_family_star:nVVV + { #2 } + \l_@@_group_clist + \l_@@_name_tl + \l_@@_thmtools_clist + } +% \end{macrocode} +% \end{macro} +% +% +% +% Finally, we can provide document commands that make these available. +% +% +% \begin{macro}{\NewGroupedTheoremFamily,\NewGroupedTheoremFamily*} +% \begin{syntax} +% \cs{NewGroupedTheoremFamily}\oarg{keys}\marg{family name} +% \end{syntax} +% +% +% +% \begin{macrocode} +\NewDocumentCommand{\NewGroupedTheoremFamily}{s O{} m} + { + \IfBooleanTF { #1 } + { + \groupthm_new_grouped_theorem_family_star_from_keys:nn { #2 } { #3 } + } + { + \groupthm_new_grouped_theorem_family_from_keys:nn { #2 } { #3 } + } + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\ProvideGroupedTheoremFamily,\ProvideGroupedTheoremFamily*} +% \begin{syntax} +% \cs{ProvideGroupedTheoremFamily}\oarg{keys}\marg{family name} +% \end{syntax} +% +% +% +% \begin{macrocode} +\NewDocumentCommand{\ProvideGroupedTheoremFamily}{s O{} m} + { + \IfBooleanTF { #1 } + { + \groupthm_provide_grouped_theorem_family_star_from_keys:nn { #2 } { #3 } + } + { + \groupthm_provide_grouped_theorem_family_from_keys:nn { #2 } { #3 } + } + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\NewTheoremFamily,\NewTheoremFamily*} +% \begin{syntax} +% \cs{NewTheoremFamily}\oarg{keys}\marg{family name} +% \end{syntax} +% +% +% +% \begin{macrocode} +\NewDocumentCommand{\NewTheoremFamily}{s O{} m} + { + \IfBooleanTF { #1 } + { + \groupthm_new_theorem_family_star_from_keys:nn { #2 } { #3 } + } + { + \groupthm_new_theorem_family_from_keys:nn { #2 } { #3 } + } + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\ProvideTheoremFamily,\ProvideTheoremFamily*} +% \begin{syntax} +% \cs{ProvideTheoremFamily}\oarg{keys}\marg{family name} +% \end{syntax} +% +% +% +% \begin{macrocode} +\NewDocumentCommand{\ProvideTheoremFamily}{s O{} m} + { + \IfBooleanTF { #1 } + { + \groupthm_provide_theorem_family_star_from_keys:nn { #2 } { #3 } + } + { + \groupthm_provide_theorem_family_from_keys:nn { #2 } { #3 } + } + } +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Theorem family options} +% +% +% +% \begin{macro}{\groupthm_add_theorem_to_group:n} +% \begin{syntax} +% \cs{groupthm_add_theorem_to_group:n}\marg{theorem group} +% \end{syntax} +% +% +% \begin{macrocode} +\cs_new:Npn \groupthm_add_theorem_to_group:n #1 + { +% \end{macrocode} +% As mentioned earlier, this bool will indicate whether we are +% executing a \mymeta{selection body} from some family options. +% If used outside, we emit an error message. +% \begin{macrocode} + \bool_if:NTF \l_@@_in_family_options_environment_bool + { + \clist_put_left:Nn \l_@@_group_clist { #1 } + } + { + \msg_error:nn { groupthm } { misuse ~ add ~ theorem ~ to ~ group } + } + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\AddTheoremToGroup} +% \begin{syntax} +% \cs{AddTheoremToGroup}\marg{theorem group} +% \end{syntax} +% +% +% +% \begin{macrocode} + \NewDocumentCommand { \AddTheoremToGroup } { m } + { + \groupthm_add_theorem_to_group:n { #1 } + } +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\@@_declare_theorem_family_options_aux:nnnnn} +% \begin{syntax} +% \c{@@_declare_theorem_family_options_aux:nnnnn}\marg{theorem family} +% \marg{argument specification}\marg{selection body}\marg{extra groups}\marg{declaring backend} +% \end{syntax} +% +% This declares a new theorem variant option parser, i.e.~ introduces the environment +% \mymeta{theorem family} with signature \marg{argument specification}. +% +% The \mymeta{selection body} will be executed and selects some groups the environment shall have. +% The \mymeta{extra groups} will be added regardless of the arguments given +% to the \mymeta{theorem family} +% The \mymeta{declaring backend} is one of \texttt{New}, \texttt{Renew}, \texttt{Provide} +% and \texttt{Declare} and is given to the \texttt{DocumentEnvironment} command from \pkg{xpars}. +% +% \begin{macrocode} +\cs_new:Npn \@@_declare_theorem_family_options_aux:nnnnn #1 #2 #3 #4 #5 + { + \use:c{ #5 DocumentEnvironment } + { #1 } + { #2 } + { +% \end{macrocode} +% We can now clear the group list and execute the \mymeta{selection body} +% that populates this list again. +% Additionally, we add the groups that should always be present and activate the +% \cs{AddTheoremToGroup} macro by setting the bool. +% \begin{macrocode} + \clist_clear:N \l_@@_group_clist + \bool_set_true:N \l_@@_in_family_options_environment_bool + #3 + \bool_set_false:N \l_@@_in_family_options_environment_bool + \clist_put_right:Nn \l_@@_group_clist { #4 } +% \end{macrocode} +% We now got the list of groups parsed. We sort this and start the corresponding +% environment that has been generated by a \cs{NewGroupedTheoremFamily} command +% or similar. +% \begin{macrocode} + \@@_sort_theorem_group_names: + \cs_if_exist:cTF { __#1__groups_ \clist_use:Nn \l_@@_group_clist { _ } } + { + \begin { __#1__groups_ \clist_use:Nn \l_@@_group_clist { _ } } + } + { + \msg_error:nnxx { groupthm } { undefined ~ theorem ~ variant } + { #1 } + { \clist_use:Nnnn \l_@@_group_clist { ~ and ~ } {, ~} { , ~ and ~ } } + } + } + { +% \end{macrocode} +% At the end of the environment, we have to do the same parsing again. +% \begin{macrocode} + \clist_clear:N \l_@@_group_clist + \bool_set_true:N \l_@@_in_family_options_environment_bool + #3 + \bool_set_false:N \l_@@_in_family_options_environment_bool + \clist_put_right:Nn \l_@@_group_clist { #4 } +% \end{macrocode} +% End the corresponding environment. +% \begin{macrocode} + \@@_sort_theorem_group_names: + \end { __#1__groups_ \clist_use:Nn \l_@@_group_clist { _ } } + } + } +% \end{macrocode} +% \end{macro} +% +% +% All other macros are now essentially wrappers around this aux macro, +% passing different \mymeta{extra groups} to them +% +% \begin{macro}{\groupthm_new_grouped_theorem_family_options:nnn} +% \begin{syntax} +% \cs{groupthm_new_grouped_theorem_family_options:nnn}\marg{theorem family} +% \marg{signature}\marg{selection body} +% \end{syntax} +% +% \begin{macrocode} +\cs_new:Npn \groupthm_new_grouped_theorem_family_options:nnn #1 #2 #3 +{ + \@@_declare_theorem_family_options_aux:nnnnn + { #1 } { #2 } { #3 } { } { New } +} +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\groupthm_renew_grouped_theorem_family_options:nnn} +% \begin{syntax} +% \cs{groupthm_renew_grouped_theorem_family_options:nnn}\marg{theorem family} +% \marg{signature}\marg{selection body} +% \end{syntax} +% +% \begin{macrocode} +\cs_new:Npn \groupthm_renew_grouped_theorem_family_options:nnn #1 #2 #3 +{ + \@@_declare_theorem_family_options_aux:nnnnn + { #1 } { #2 } { #3 } { } { Renew } +} +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\groupthm_provide_grouped_theorem_family_options:nnn} +% \begin{syntax} +% \cs{groupthm_provide_grouped_theorem_family_options:nnn}\marg{theorem family} +% \marg{signature}\marg{selection body} +% \end{syntax} +% +% \begin{macrocode} +\cs_new:Npn \groupthm_provide_grouped_theorem_family_options:nnn #1 #2 #3 +{ + \@@_declare_theorem_family_options_aux:nnnnn + { #1 } { #2 } { #3 } { } { Provide } +} +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\groupthm_declare_grouped_theorem_family_options:nnn} +% \begin{syntax} +% \cs{groupthm_declare_grouped_theorem_family_options:nnn}\marg{theorem family} +% \marg{signature}\marg{selection body} +% \end{syntax} +% +% \begin{macrocode} +\cs_new:Npn \groupthm_declare_grouped_theorem_family_options:nnn #1 #2 #3 +{ + \@@_declare_theorem_family_options_aux:nnnnn + { #1 } { #2 } { #3 } { } { Declare } +} +% \end{macrocode} +% \end{macro} +% +% +% +% The variants without \enquote{grouped} in their name will just issue two commands, +% one with and one without the \texttt{starred} group, and add a \enquote{*} to the name. +% +% \begin{macro}{\groupthm_new_theorem_family_options:nnn} +% \begin{syntax} +% \cs{groupthm_new_theorem_family_options:nnn}\marg{theorem family} +% \marg{signature}\marg{selection body} +% \end{syntax} +% +% +% \begin{macrocode} +\cs_new:Npn \groupthm_new_theorem_family_options:nnn #1 #2 #3 +{ + \@@_declare_theorem_family_options_aux:nnnnn + { #1 } { #2 } { #3 } { } { New } + \@@_declare_theorem_family_options_aux:nnnnn + { #1* } { #2 } { #3 } { starred } { New } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\groupthm_renew_theorem_family_options:nnn} +% \begin{syntax} +% \cs{groupthm_renew_theorem_family_options:nnn}\marg{theorem family} +% \marg{signature}\marg{selection body} +% \end{syntax} +% +% +% \begin{macrocode} +\cs_new:Npn \groupthm_renew_theorem_family_options:nnn #1 #2 #3 +{ + \@@_declare_theorem_family_options_aux:nnnnn + { #1 } { #2 } { #3 } { } { Renew } + \@@_declare_theorem_family_options_aux:nnnnn + { #1* } { #2 } { #3 } { starred } { Renew } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\groupthm_provide_theorem_family_options:nnn} +% \begin{syntax} +% \cs{groupthm_provide_theorem_family_options:nnn}\marg{theorem family} +% \marg{signature}\marg{selection body} +% \end{syntax} +% +% +% \begin{macrocode} +\cs_new:Npn \groupthm_provide_theorem_family_options:nnn #1 #2 #3 +{ + \@@_declare_theorem_family_options_aux:nnnnn + { #1 } { #2 } { #3 } { } { Provide } + \@@_declare_theorem_family_options_aux:nnnnn + { #1* } { #2 } { #3 } { starred } { Provide } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\groupthm_declare_theorem_family_options:nnn} +% \begin{syntax} +% \cs{groupthm_declare_theorem_family_options:nnn}\marg{theorem family} +% \marg{signature}\marg{selection body} +% \end{syntax} +% +% +% \begin{macrocode} +\cs_new:Npn \groupthm_declare_theorem_family_options:nnn #1 #2 #3 +{ + \@@_declare_theorem_family_options_aux:nnnnn + { #1 } { #2 } { #3 } { } { Declare } + \@@_declare_theorem_family_options_aux:nnnnn + { #1* } { #2 } { #3 } { starred } { Declare } +} +% \end{macrocode} +% \end{macro} +% +% +% It remains to wrap these into document commands +% +% +% \begin{macro}{\NewGroupedTheoremFamilyOptions, \NewGroupedTheoremFamilyOptions*} +% \begin{syntax} +% \cs{NewGroupedTheoremFamilyOptions}\marg{family name}\marg{signature} +% \marg{selection body} +% \end{syntax} +% +% \begin{macrocode} +\NewDocumentCommand { \NewGroupedTheoremFamilyOptions } { s m m m } +{ + \IfBooleanTF { #1 } + { + \groupthm_new_grouped_theorem_family_options:nnn + { #2 } + { #3 } + { + #4 + \groupthm_add_theorem_to_group:n { unnumbered } + } + } + { + \groupthm_new_grouped_theorem_family_options:nnn + { #2 } + { #3 } + { #4 } + } +} +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\RenewGroupedTheoremFamilyOptions, \RenewGroupedTheoremFamilyOptions*} +% \begin{syntax} +% \cs{RenewGroupedTheoremFamilyOptions}\marg{family name}\marg{signature} +% \marg{selection body} +% \end{syntax} +% +% \begin{macrocode} +\NewDocumentCommand { \RenewGroupedTheoremFamilyOptions } { s m m m } +{ + \IfBooleanTF { #1 } + { + \groupthm_renew_grouped_theorem_family_options:nnn + { #2 } + { #3 } + { + #4 + \groupthm_add_theorem_to_group:n { unnumbered } + } + } + { + \groupthm_renew_grouped_theorem_family_options:nnn + { #2 } + { #3 } + { #4 } + } +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\ProvideGroupedTheoremFamilyOptions, \ProvideGroupedTheoremFamilyOptions*} +% \begin{syntax} +% \cs{ProvideGroupedTheoremFamilyOptions}\marg{family name}\marg{signature} +% \marg{selection body} +% \end{syntax} +% +% \begin{macrocode} +\NewDocumentCommand { \ProvideGroupedTheoremFamilyOptions } { s m m m } +{ + \IfBooleanTF { #1 } + { + \groupthm_provide_grouped_theorem_family_options:nnn + { #2 } + { #3 } + { + #4 + \groupthm_add_theorem_to_group:n { unnumbered } + } + } + { + \groupthm_provide_grouped_theorem_family_options:nnn + { #2 } + { #3 } + { #4 } + } +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\DeclareGroupedTheoremFamilyOptions, \DeclareGroupedTheoremFamilyOptions*} +% \begin{syntax} +% \cs{DeclareGroupedTheoremFamilyOptions}\marg{family name}\marg{signature} +% \marg{selection body} +% \end{syntax} +% +% \begin{macrocode} +\NewDocumentCommand { \DeclareGroupedTheoremFamilyOptions } { s m m m } +{ + \IfBooleanTF { #1 } + { + \groupthm_declare_grouped_theorem_family_options:nnn + { #2 } + { #3 } + { + #4 + \groupthm_add_theorem_to_group:n { unnumbered } + } + } + { + \groupthm_declare_grouped_theorem_family_options:nnn + { #2 } + { #3 } + { #4 } + } +} +% \end{macrocode} +% \end{macro} +% +% +% +% +% +% \begin{macro}{\NewTheoremFamilyOptions, \NewTheoremFamilyOptions*} +% \begin{syntax} +% \cs{NewTheoremFamilyOptions}\marg{family name}\marg{signature} +% \marg{selection body} +% \end{syntax} +% +% \begin{macrocode} +\NewDocumentCommand { \NewTheoremFamilyOptions } { s m m m } +{ + \IfBooleanTF { #1 } + { + \groupthm_new_theorem_family_options:nnn + { #2 } + { #3 } + { + #4 + \groupthm_add_theorem_to_group:n { unnumbered } + } + } + { + \groupthm_new_theorem_family_options:nnn + { #2 } + { #3 } + { #4 } + } +} +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\RenewTheoremFamilyOptions, \RenewTheoremFamilyOptions*} +% \begin{syntax} +% \cs{RenewTheoremFamilyOptions}\marg{family name}\marg{signature} +% \marg{selection body} +% \end{syntax} +% +% \begin{macrocode} +\NewDocumentCommand { \RenewTheoremFamilyOptions } { s m m m } +{ + \IfBooleanTF { #1 } + { + \groupthm_renew_theorem_family_options:nnn + { #2 } + { #3 } + { + #4 + \groupthm_add_theorem_to_group:n { unnumbered } + } + } + { + \groupthm_renew_theorem_family_options:nnn + { #2 } + { #3 } + { #4 } + } +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\ProvideTheoremFamilyOptions, \ProvideTheoremFamilyOptions*} +% \begin{syntax} +% \cs{ProvideTheoremFamilyOptions}\marg{family name}\marg{signature} +% \marg{selection body} +% \end{syntax} +% +% \begin{macrocode} +\NewDocumentCommand { \ProvideTheoremFamilyOptions } { s m m m } +{ + \IfBooleanTF { #1 } + { + \groupthm_provide_theorem_family_options:nnn + { #2 } + { #3 } + { + #4 + \groupthm_add_theorem_to_group:n { unnumbered } + } + } + { + \groupthm_provide_theorem_family_options:nnn + { #2 } + { #3 } + { #4 } + } +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\DeclareTheoremFamilyOptions, \DeclareTheoremFamilyOptions*} +% \begin{syntax} +% \cs{DeclareTheoremFamilyOptions}\marg{family name}\marg{signature} +% \marg{selection body} +% \end{syntax} +% +% \begin{macrocode} +\NewDocumentCommand { \DeclareTheoremFamilyOptions } { s m m m } +{ + \IfBooleanTF { #1 } + { + \groupthm_declare_theorem_family_options:nnn + { #2 } + { #3 } + { + #4 + \groupthm_add_theorem_to_group:n { unnumbered } + } + } + { + \groupthm_declare_theorem_family_options:nnn + { #2 } + { #3 } + { #4 } + } +} +% \end{macrocode} +% \end{macro} +% +% +% +% +% +% +% \begin{macrocode} +% +% \end{macrocode} +% +% \end{implementation} +% +% +% +% +% \ExplSyntaxOn +% \__codedoc_special_index_module:nnnnN { key } { macro } { module } { main } { \c_false_bool} +% \__codedoc_special_index_module:nnnnN { l } { bla } { module } { usage } { \c_false_bool} +% \ExplSyntaxOff +% +% \newpage +% \PrintIndex diff --git a/doc/environments/groupthm/groupthm.dtx b/doc/environments/groupthm/groupthm.dtx index 44c10d9..958a96a 100644 --- a/doc/environments/groupthm/groupthm.dtx +++ b/doc/environments/groupthm/groupthm.dtx @@ -712,13 +712,13 @@ % % \begin{function} % { -% \groupthm_new_theorem_group_from_keys:nn, -% \groupthm_renew_theorem_group_from_keys:nn, +% \groupthm_new_group_from_keys:nn, +% \groupthm_renew_group_from_keys:nn, % \groupthm_provide_theorem_group_from_keys:nn, % \groupthm_declare_theorem_group_from_keys:nn % } % \begin{syntax} -% \cs{groupthm_new_theorem_group_from_keys:nn}\marg{keys}\marg{theorem group} +% \cs{groupthm_new_group_from_keys:nn}\marg{keys}\marg{theorem group} % \end{syntax} % % \LaTeX3 versions of \cs{NewTheoremGroup}, \cs{RenewTheoremGroup}, @@ -730,23 +730,23 @@ % % \begin{function} % { -% \groupthm_new_theorem_group:nnnnn, -% \groupthm_renew_theorem_group:nnnnn, +% \groupthm_new_group:nnnnn, +% \groupthm_renew_group:nnnnn, % \groupthm_provide_theorem_group:nnnnn, % \groupthm_declare_theorem_group:nnnnn, -% \groupthm_new_theorem_group:nVVVV, -% \groupthm_renew_theorem_group:nVVVV, +% \groupthm_new_group:nVVVV, +% \groupthm_renew_group:nVVVV, % \groupthm_provide_theorem_group:nVVVV, % \groupthm_declare_theorem_group:nVVVV % } % \begin{syntax} -% \cs{groupthm_new_theorem_group:nnnnn}\marg{theorem group}\marg{prefix tl} +% \cs{groupthm_new_group:nnnnn}\marg{theorem group}\marg{prefix tl} % \marg{suffix tl}\marg{mapname clist}\marg{thmtools clist} % \end{syntax} % % Non-keyval versions of -% \cs{groupthm_new_theorem_group_from_keys:nn}, -% \cs{groupthm_renew_theorem_group_from_keys:nn}, +% \cs{groupthm_new_group_from_keys:nn}, +% \cs{groupthm_renew_group_from_keys:nn}, % \cs{groupthm_provide_theorem_group_from_keys:nn} % and % \cs{groupthm_declare_theorem_group_from_keys:nn} @@ -1501,7 +1501,7 @@ % \texttt{new}, \texttt{renew}, \texttt{provide} and \texttt{declare} variants % of the theorem group macro: % -% \begin{macro}{\groupthm_new_theorem_group:nnnnn, \groupthm_new_theorem_group:nVVVV} +% \begin{macro}{\groupthm_new_group:nnnnn, \groupthm_new_group:nVVVV} % % \begin{macrocode} \cs_new:Npn \@@_define_aux:nnnNNNn #1 #2 #3 #4 #5 #6 #7 @@ -1544,112 +1544,64 @@ } \cs_generate_variant:Nn \@@_define_aux:nnnNNNn { n n n c N N n } -\cs_new:Npn \groupthm_new_theorem_group:nnnnn #1 #2 #3 #4 #5 +\cs_new:Npn \@@_define_list_aux:nnnNNnn #1 #2 #3 #4 #5 #6 #7 { - \@@_define_aux:nnncNNn - { new } - { theorem group } - { #1 } - { @@_use_group_#1: } - \@@_undefine_group_aux:n - \@@_define_group_aux:nnnnn + \cs_set:Npn \@@_map_aux:n ##1 + { + \cs_new:cn { #6 } { - { #1 } { #2 } { #3 } { #4 } { #5 } + \@@_define_aux:nnncNNn + { ##1 } + { #2 } + { ####1 } + { #3 } + #4 + #5 + { + #7 + } } + } + \clist_map_function:nN { #1 } \@@_map_aux:n } + + +\@@_define_list_aux:nnnNNnn + { new, renew, provide, declare } + { theorem group } + { @@_use_group_##1: } + \@@_undefine_group_aux:n + \@@_define_group_aux:nnnnn + { groupthm_#1_group:nnnnn } + { { ##1 } { ##2 } { ##3 } { ##4 } { ##5 } } % \end{macrocode} % % Finally, generate some extra variant. % % \begin{macrocode} -\cs_generate_variant:Nn \groupthm_new_theorem_group:nnnnn { n V V V V } -% \end{macrocode} -% \end{macro} -% -% -% -% \begin{macro}{\groupthm_renew_theorem_group:nnnnn, \groupthm_renew_theorem_group:nVVVV} -% -% \begin{macrocode} -\cs_new:Npn \groupthm_renew_theorem_group:nnnnn #1 #2 #3 #4 #5 - { - \cs_if_exist:cTF { @@_use_group_#1: } - { - \@@_undefine_group_aux:n { #1 } - \@@_define_group_aux:nnnnn { #1 } { #2 } { #3 } { #4 } { #5 } - } - { - \msg_error:nnnnn { groupthm } { wrong ~ definition } - { theorem ~ group } { #1 } { not } - } - } -% \end{macrocode} -% -% Finally, generate some extra variant. -% -% \begin{macrocode} -\cs_generate_variant:Nn \groupthm_renew_theorem_group:nnnnn { n V V V V } +\cs_generate_variant:Nn \groupthm_new_group:nnnnn { n V V V V } % \end{macrocode} % \end{macro} % -% -% -% \begin{macro}{\groupthm_provide_theorem_group:nnnnn, \groupthm_provide_theorem_group:nVVVV} -% % \begin{macrocode} -\cs_new:Npn \groupthm_provide_theorem_group:nnnnn #1 #2 #3 #4 #5 - { - \cs_if_exist:cF { @@_use_group_#1: } - { - \@@_define_group_aux:nnnnn { #1 } { #2 } { #3 } { #4 } { #5 } - } - } + % \end{macrocode} -% -% Finally, generate some extra variant. -% -% \begin{macrocode} -\cs_generate_variant:Nn \groupthm_provide_theorem_group:nnnnn { n V V V V } -% \end{macrocode} -% \end{macro} % % -% -% \begin{macro}{\groupthm_declare_theorem_group:nnnnn, \groupthm_declare_theorem_group:nVVVV} -% -% -% \begin{macrocode} -\cs_new:Npn \groupthm_declare_theorem_group:nnnnn #1 #2 #3 #4 #5 - { - \cs_if_exist:cT { @@_use_group_#1: } - { - \@@_undefine_group_aux:n { #1 } - } - \@@_define_group_aux:nnnnn { #1 } { #2 } { #3 } { #4 } { #5 } - } -% \end{macrocode} -% -% Finally, generate some extra variant. -% -% \begin{macrocode} -\cs_generate_variant:Nn \groupthm_declare_theorem_group:nnnnn { n V V V V } -% \end{macrocode} -% \end{macro} -% % % With the \cs{@@_set_normalized_keys:nnn} macro at hand, % it is also easy to provide key-value interfaces for these commands: % -% \begin{macro}{\groupthm_new_theorem_group_from_keys:nn} +% \begin{macro}{\groupthm_new_group_from_keys:nn} % \begin{syntax} -% \cs{groupthm_new_theorem_group_from_keys:nn}\marg{keys}\marg{theorem group} +% \cs{groupthm_new_group_from_keys:nn}\marg{keys}\marg{theorem group} % \end{syntax} % % \begin{macrocode} -\cs_new:Npn \groupthm_new_theorem_group_from_keys:nn #1#2 +\cs_new:Npn \groupthm_new_group_from_keys:nn #1#2 { \@@_set_normalized_keys:nnn { #1 } { theoremgroup } { #2 } - \groupthm_new_theorem_group:nVVVV { #2 } + \groupthm_new_group:nVVVV { #2 } \l_@@_prefix_tl \l_@@_suffix_tl \l_@@_mapname_clist @@ -1660,16 +1612,16 @@ % % % -% \begin{macro}{\groupthm_renew_theorem_group_from_keys:nn} +% \begin{macro}{\groupthm_renew_group_from_keys:nn} % \begin{syntax} -% \cs{groupthm_renew_theorem_group_from_keys:nn}\marg{keys}\marg{theorem group} +% \cs{groupthm_renew_group_from_keys:nn}\marg{keys}\marg{theorem group} % \end{syntax} % % \begin{macrocode} -\cs_new:Npn \groupthm_renew_theorem_group_from_keys:nn #1#2 +\cs_new:Npn \groupthm_renew_group_from_keys:nn #1#2 { \@@_set_normalized_keys:nnn { #1 } { theoremgroup } { #2 } - \groupthm_renew_theorem_group:nVVVV { #2 } + \groupthm_renew_group:nVVVV { #2 } \l_@@_prefix_tl \l_@@_suffix_tl \l_@@_mapname_clist @@ -1727,7 +1679,7 @@ % \begin{macrocode} \NewDocumentCommand{\NewTheoremGroup}{ O{} m } { - \groupthm_new_theorem_group_from_keys:nn { #1 } { #2 } + \groupthm_new_group_from_keys:nn { #1 } { #2 } } % \end{macrocode} % \end{macro} @@ -1739,7 +1691,7 @@ % \begin{macrocode} \NewDocumentCommand{\RenewTheoremGroup}{ O{} m } { - \groupthm_renew_theorem_group_from_keys:nn { #1 } { #2 } + \groupthm_renew_group_from_keys:nn { #1 } { #2 } } % \end{macrocode} % \end{macro} diff --git a/doc/environments/groupthm/groupthm.sty b/doc/environments/groupthm/groupthm.sty index 1402d99..cade1ed 100644 --- a/doc/environments/groupthm/groupthm.sty +++ b/doc/environments/groupthm/groupthm.sty @@ -260,63 +260,50 @@ } \cs_generate_variant:Nn \__groupthm_define_aux:nnnNNNn { n n n c N N n } -\cs_new:Npn \groupthm_new_theorem_group:nnnnn #1 #2 #3 #4 #5 +\cs_new:Npn \__groupthm_define_list_aux:nnnNNnn #1 #2 #3 #4 #5 #6 #7 { - \__groupthm_define_aux:nnncNNn - { new } - { theorem group } - { #1 } - { __groupthm_use_group_#1: } - \__groupthm_undefine_group_aux:n - \__groupthm_define_group_aux:nnnnn + \cs_set:Npn \__groupthm_map_aux:n ##1 + { + \cs_new:cn { #6 } { - { #1 } { #2 } { #3 } { #4 } { #5 } + \__groupthm_define_aux:nnncNNn + { ##1 } + { #2 } + { ####1 } + { #3 } + #4 + #5 + { + #7 + } } + } + \clist_map_function:nN { #1 } \__groupthm_map_aux:n } -\cs_generate_variant:Nn \groupthm_new_theorem_group:nnnnn { n V V V V } -\cs_new:Npn \groupthm_renew_theorem_group:nnnnn #1 #2 #3 #4 #5 - { - \cs_if_exist:cTF { __groupthm_use_group_#1: } - { - \__groupthm_undefine_group_aux:n { #1 } - \__groupthm_define_group_aux:nnnnn { #1 } { #2 } { #3 } { #4 } { #5 } - } - { - \msg_error:nnnnn { groupthm } { wrong ~ definition } - { theorem ~ group } { #1 } { not } - } - } -\cs_generate_variant:Nn \groupthm_renew_theorem_group:nnnnn { n V V V V } -\cs_new:Npn \groupthm_provide_theorem_group:nnnnn #1 #2 #3 #4 #5 - { - \cs_if_exist:cF { __groupthm_use_group_#1: } - { - \__groupthm_define_group_aux:nnnnn { #1 } { #2 } { #3 } { #4 } { #5 } - } - } -\cs_generate_variant:Nn \groupthm_provide_theorem_group:nnnnn { n V V V V } -\cs_new:Npn \groupthm_declare_theorem_group:nnnnn #1 #2 #3 #4 #5 - { - \cs_if_exist:cT { __groupthm_use_group_#1: } - { - \__groupthm_undefine_group_aux:n { #1 } - } - \__groupthm_define_group_aux:nnnnn { #1 } { #2 } { #3 } { #4 } { #5 } - } -\cs_generate_variant:Nn \groupthm_declare_theorem_group:nnnnn { n V V V V } -\cs_new:Npn \groupthm_new_theorem_group_from_keys:nn #1#2 + +\__groupthm_define_list_aux:nnnNNnn + { new, renew, provide, declare } + { theorem group } + { __groupthm_use_group_##1: } + \__groupthm_undefine_group_aux:n + \__groupthm_define_group_aux:nnnnn + { groupthm_#1_group:nnnnn } + { { ##1 } { ##2 } { ##3 } { ##4 } { ##5 } } +\cs_generate_variant:Nn \groupthm_new_group:nnnnn { n V V V V } + +\cs_new:Npn \groupthm_new_group_from_keys:nn #1#2 { \__groupthm_set_normalized_keys:nnn { #1 } { theoremgroup } { #2 } - \groupthm_new_theorem_group:nVVVV { #2 } + \groupthm_new_group:nVVVV { #2 } \l__groupthm_prefix_tl \l__groupthm_suffix_tl \l__groupthm_mapname_clist \l__groupthm_thmtools_clist } -\cs_new:Npn \groupthm_renew_theorem_group_from_keys:nn #1#2 +\cs_new:Npn \groupthm_renew_group_from_keys:nn #1#2 { \__groupthm_set_normalized_keys:nnn { #1 } { theoremgroup } { #2 } - \groupthm_renew_theorem_group:nVVVV { #2 } + \groupthm_renew_group:nVVVV { #2 } \l__groupthm_prefix_tl \l__groupthm_suffix_tl \l__groupthm_mapname_clist @@ -342,11 +329,11 @@ } \NewDocumentCommand{\NewTheoremGroup}{ O{} m } { - \groupthm_new_theorem_group_from_keys:nn { #1 } { #2 } + \groupthm_new_group_from_keys:nn { #1 } { #2 } } \NewDocumentCommand{\RenewTheoremGroup}{ O{} m } { - \groupthm_renew_theorem_group_from_keys:nn { #1 } { #2 } + \groupthm_renew_group_from_keys:nn { #1 } { #2 } } \NewDocumentCommand{\ProvideTheoremGroup}{ O{} m } {