latex-packages/doc/environments/groupthm/groupthm.dtx

1572 lines
50 KiB
TeX

% \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
%
% -----------------------------------------------------------------------
%
%<*driver>
\documentclass[full,kernel]{l3doc}
\usepackage{mkessler-todo}
\begin{document}
\DocInput{\jobname.dtx}
\end{document}
%</driver>
% \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}%
% }
% \NewDocumentCommand{\ma}{m}
% {
% \{\meta{#1}\}
% }
%
% \begin{documentation}
%
% \tableofcontents
% \newpage
%
% 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, \meta{theorem group}s,
% to structure theorems into groups that can subsequently easily altered,
% as well as a mechanism for easily generating \meta{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 \meta{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 \meta{theorem group} is some named group holding some properties for
% the \meta{theorem}s that are contained in this group.
% Each \meta{theorem} can, when declared, be part of arbitrarily many \meta{theorem group}s,
% and will be subject to the styles these groups defined.
%
% This enables to group similar \meta{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 \meta{theorem group}, and not all \meta{theorem}s separately.
%
% The properties. such a \meta{theorem group} can hold are as follows
%
%
% \begin{description}
% \item[\kw{prename}] A prefix (any \meta{token list}) that will be inserted
% before the theorem name of each member of this \meta{theorem group}.
% \item[\kw{postname}] A suffix (any \meta{token list}) that will be
% inserted before the theorem name for each member of this \meta{theorem group}.
% This could be e.g.~some \enquote{$\star$} appended to the name to indicate
% variants of environments.
% \item[\kw{mapname}] A \meta{function} (some macro that takes exactly one argument)
% that is applied to the \kw{name}.
% \item[\kw{thmtools}] A \meta{clist} of key-value pairs that are passed to the underlying
% \pkg{thmtools} backend of the \meta{theorem}.
% This allows e.g.~to set the \kw{topskip} of a certain class of \meta{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 \meta{theorem} can be member of arbitrary many \meta{theorem group}s,
% and will posses their corresponding properties.
%
% To adjust finer controlling of these \meta{theorem group}s, \meta{theorem group}s can inherit from each other, and \meta{theorem group}s are subject to a hierarchy that controls precedence in case
% of conflicting properties of different \meta{theorem group}s a \meta{theorem} may be part of.
%
% This hierarchy can of course be controlled by the user.
%
% \subsection{Grouped theorems}
%
% A \meta{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 \meta{theorem variant}s of some \meta{theorem}, the most typical
% example being \vocab{starred} version of \meta{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
% \meta{theorem family}, which is based on some \meta{theorem name} and
% parses additional arguments / syntax to control the \meta{theorem groups}
% that this environment is a part of.
%
% So, in addition the name of a \meta{theorem}, the corresponding environment will
% accept some options and toggle the membership of certain \meta{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 \meta{theorem family} by listing the groups that can be toggled
% by this \meta{theorem family}, and declaring the actual option parsing
% of the \meta{theorem family}, which then controls the membership in these groups
% (and of course prior to this the definition of the desired \meta{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}[\meta{keys}]\{\meta{theorem group}\}
% \end{syntax}
%
% This introduces a new \meta{theorem group} with the given name.
% The \meta{keys} available are the same as introduced in \autoref{sec:theorem-groups}:
%
% \begin{description}
% \item
%
% \kw{prename} = \meta{token list}.
% Insert the \meta{token list} in front of the theorem name.
%
% \item
%
% \kw{postname} = \meta{token list}.
% Insert the \meta{token list} after the theorem name.
%
% \item
%
% \kw{mapname} = \meta{function}.
% Apply this \meta{function} to the theorem name.
%
% \item
%
% \kw{thmtools} = $\{$\meta{clist}$\}$.
% Pass these options to \pkg{thmtools}.
%
% \end{description}
%
% For uniqueness of the given options, the \meta{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}[\meta{keyname}]%
% \{\meta{theorem group 1}\}\{\meta{relation}\}\{\meta{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 \meta{keyname} can be one of \kw{prename}, \kw{postname}, \kw{mapname}, \kw{thmtools}.
% If present, it declares the corresponding relation only for this subkey.
% This can lead to \meta{theorem group 1} overwriting \meta{theorem group 2} when given
% contradictory \pkg{thmtools} options, but the \kw{prename} of \meta{theorem group 1}
% being applied after the one of \meta{theorem group 2}.
% When the \meta{keyname} is not given, this applies to all keywords.
%
% \begin{texnote}
% The \meta{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>}]
%
% \meta{theorem group 1} takes precedence over \meta{theorem group 2}.
% Its \kw{prename} is applied after the one of \meta{theorem group 2}.
%
% \item[\kw{lower} or \kw{before} or \kw{\string<}]
%
% \meta{theorem group 2} takes precedence over \meta{theorem group 1}.
% Its \kw{prename} is applied after the one of \meta{theorem group 1}.
%
% \end{description}
%
% \begin{texnote}
% The \meta{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}\{\meta{theorem group 1}\}\{\meta{theorem group 2}\}
% \end{syntax}
% Declares \meta{theorem group 1} to \enquote{inherit} all properties
% of \meta{theorem group 2}.
% In other words, \meta{theorem group 2} is a parent of \meta{theorem group 1}
% in a usual inheritance graph.
%
% The definitions of the groups themselves are unchanged,
% but each new theorem defined with \meta{theorem group 1} will also
% have the properties of \meta{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 \meta{theorem group 1} inherits
% from \meta{theorem group 2}, but \meta{theorem group 2} overwrites
% \meta{theorem group 1}.
% \end{function}
%
% \subsection{Appending to theorem groups}
% \begin{function}{\AppendToTheoremGroup}
% \begin{syntax}
% \cs{AppendToTheoremGroup}[\meta{keys}]\{\meta{theorem group}\}
% \end{syntax}
% Adds the properties given as \meta{keys} to the theorem group.
% The syntax for the \meta{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}[\meta{keys}]\{\meta{theorem name}\}
% \end{syntax}
% This defines \meta{theorem name} as a new theorem environment.
% Its properties can be set by the following keys:
%
% \begin{description}
%
% \item
%
% \kw{name} $=$ \meta{displayed name}.
% If given, this is the displayed name of the environment in the document.
% If not present, the \meta{theorem name} is also used as the \meta{displayed name}
% in capitalized form.
%
% \item
%
% \kw{group} $=$ \{\meta{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} = \{\meta{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*}[\meta{keys}]\{\meta{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}[\meta{keys}]\{\meta{theorem name}\}
% \end{syntax}
%
% This behaves essentially the same as \cs{NewGroupedTheorem},
% but will define two grouped theorems, namely \meta{theorem name} and \meta{theorem name*}.
%
% The \meta{theorem name*} environment has the same properties as the \meta{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}[\meta{keys}]\{\meta{theorem name}\}
% \end{syntax}
% Combines the behavior of \cs{NewGroupedTheorem*} and \cs{NewTheorem}, thus
% declaring \meta{theorem} to (additionally) be member of the \kw{unnumbered}
% and \meta{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}[\meta{keys}]\{\meta{theorem name}\}
% \end{syntax}
%
% Defines a family of grouped theorems.
% The \meta{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}\{\meta{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}\{\meta{theorem name}\}\{\meta{argument specifiation}\}%
% \{\meta{selection body}\}
% \end{syntax}
%
% Defines a new environment with options, given by \meta{theorem name}.
% The \meta{argument specification} can be any valid \pkg{xparse} argument specification.
%
% The \meta{selection body} is there to process the options of
% the \meta{argument specification} and select which variant of the \meta{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 \meta{selection body} is executed.
% Immediately after, the theorem variant of \meta{theorem name} with the specified groups
% by \cs{AddTheoremToGroup} is called.
%
% At the end of the environment, the \meta{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*}\{\meta{theorem name}\}\{\meta{argument specifiation}\}%
% \{\meta{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}\{\meta{theorem name}\}\{\meta{argument specifiation}\}%
% \{\meta{selection body}\}
% \end{syntax}
%
% This behaves essentially the same as \cs{NewGroupedTheoremFamilyOptions},
% but also declares the environment \meta{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*}\{\meta{theorem name}\}\{\meta{argument specifiation}\}%
% \{\meta{selection body}\}
% \end{syntax}
%
% Combines the behavior of \cs{NewGroupedTheoremFamilyOptions*} and \cs{NewTheoremFamilyOptions},
% thus declaring both \meta{theorem name} and \meta{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}\meta{mandatory args}\meta{optional args},
% where the \meta{mandatory args} list the mandatory args of the \LaTeX2e
% interface, and the \meta{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}\{\meta{keys}\}\meta{mandatory args}
% where we pass a \texttt{clist} as the first argument and all mandatory args
% as further mandatory arguments.
% \item \cs{NewFoo}[\meta{keys}]\meta{mandatory args},
% where the keys can be passed optionally.
% \end{itemize}
%
% \subsection{Theorem groups}
%
%
% \begin{function}{\groupthm_new_theorem_group_by_keys:nn}
% \begin{syntax}
% \cs{groupthm_new_theorem_group_by_keys:nn}\ma{keys}\ma{theorem group}
% \end{syntax}
%
% \LaTeX3 version of \cs{NewTheoremGroup}
%
% \end{function}
%
%
%
% \begin{function}{\groupthm_renew_theorem_group_by_keys:nn}
% \begin{syntax}
% \cs{groupthm_renew_theorem_group_by_keys:nn}\ma{keys}
% \ma{theorem group}
% \end{syntax}
%
% \LaTeX3 version of \cs{RenewTheoremGroup}
%
% \end{function}
%
%
%
% \begin{function}{\groupthm_provide_theorem_group_by_keys:nn}
% \begin{syntax}
% \cs{groupthm_provide_theorem_group_by_keys:nn}
% \ma{keys}\ma{theorem group}
% \end{syntax}
%
% \LaTeX3 version of \cs{ProvideTheoremGroup}
%
% \end{function}
%
%
%
% \begin{function}{\groupthm_declare_theorem_group_by_keys:nn}
% \begin{syntax}
% \cs{groupthm_declare_theorem_group_by_keys:nn}
% \ma{keys}\ma{theorem group}
% \end{syntax}
%
% \LaTeX3 version of \cs{DeclareTheoremGroup}
%
% \end{function}
%
%
%
% \begin{function}{\groupthm_new_theorem_group:nnnnn, \groupthm_new_theorem_group:nVVVV}
% \begin{syntax}
% \cs{groupthm_new_theorem_group:nnnnn}\ma{theorem group}\ma{prename tl}
% \ma{postname tl}\ma{mapname clist}\ma{thmtools clist}
% \end{syntax}
%
% Non-keyval version of \cs{groupthm_new_theorem_group_by_keys:nn}
%
% \end{function}
%
%
%
% \begin{function}{\groupthm_renew_theorem_group:nnnnn, \groupthm_renew_theorem_group:nVVVV}
% \begin{syntax}
% \cs{groupthm_renew_theorem_group:nnnnn}\ma{theorem group}\ma{prename tl}
% \ma{postname tl}\ma{mapname clist}\ma{thmtools clist}
% \end{syntax}
%
% Non-keyval version of \cs{groupthm_renew_theorem_group_by_keys:nn}
%
% \end{function}
%
%
% \begin{function}{\groupthm_provide_theorem_group:nnnnn, \groupthm_provide_theorem_group:nVVVV}
% \begin{syntax}
% \cs{groupthm_provide_theorem_group:nnnnn}\ma{theorem group}\ma{prename tl}
% \ma{postname tl}\ma{mapname clist}\ma{thmtools clist}
% \end{syntax}
%
% Non-keyval version of \cs{groupthm_provide_theorem_group_by_keys:nn}
%
% \end{function}
%
%
% \begin{function}{\groupthm_declare_theorem_group:nnnnn, \groupthm_declare_theorem_group:nVVVV}
% \begin{syntax}
% \cs{groupthm_declare_theorem_group:nnnnn}\ma{theorem group}\ma{prename tl}
% \ma{postname tl}\ma{mapname clist}\ma{thmtools clist}
% \end{syntax}
%
% Non-keyval version of \cs{groupthm_declare_theorem_group_by_keys:nn}
%
% \end{function}
%
%
%
% \begin{function}{\groupthm_declare_theorem_group_rule:nnnn}
% \begin{syntax}
% \cs{groupthm_declare_theorem_group_rule:nnnn}\ma{keyname}\ma{theorem group 1}
% \ma{relation}\ma{theorem group 2}
% \end{syntax}
%
% \LaTeX3 version of \cs{DeclareTheoremGroupRule}
%
% \end{function}
%
%
%
% \begin{implementation}
%
% \section{\pkg{groupthm} implementation}
%
% \begin{macrocode}
%<*package>
% \end{macrocode}
%
% \begin{macrocode}
%<@@=groupthm>
% \end{macrocode}
%
% \subsection{Dependencies}
% Identify package
% \begin{macrocode}
\ProvidesExplPackage{groupthm}{2022/01/17}{0.0.1}{Grouped theorems.}
% \end{macrocode}
% First, we import other packages on which we rely on, and
% set up some private wrappers around these.
% \begin{macrocode}
\RequirePackage{amsthm}
\RequirePackage{thmtools}
\RequirePackage{mkessler-powerset}
% \end{macrocode}
%
% \begin{macro}{\@@_declare_theorem_group:nn, \@@_declare_theorem_group:nV}
% \begin{syntax}
% \cs{@@_declare_theorem_group:nn} \meta{theorem name}\meta{thmtools keyval args}
% \end{syntax}
%
% This is just a private wrapper around \cs{declaretheorem} of the \pkg{thmtools} package.
%
% \begin{macrocode}
\cs_new:Npn \@@_declare_theorem_group:nn #1 #2
{
\declaretheorem [ #2 ] { #1 }
}
\cs_generate_variant:Nn \@@_declare_theorem_group:nn { n V }
% \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}\ma{hook}\meta{clist name}\meta{relation}\meta{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 \}\{\meta{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 \}\{\meta{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 \}
% \{\meta{type}\}\{\meta{name}\}\{\meta{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}
%
%
%
%
% \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 { @@/prename }
\hook_new:n { @@/postname }
\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}\{\meta{hook}\}\{\meta{label 1}\}\{\meta{relation}\}\{\meta{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_prename_tl, \l_@@_key_name_tl, \l_@@_key_postname_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_prename_tl
\tl_new:N \l_@@_key_name_tl
\tl_new:N \l_@@_key_postname_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_@@_prename_tl,
% \l_@@_name_tl,
% \l_@@_postname_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_@@_prename_tl
\tl_new:N \l_@@_name_tl
\tl_new:N \l_@@_postname_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}
%
%
%
% \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 }
{
prename .tl_set:N = \l_@@_key_prename_tl,
prename .default:n = \c_empty_tl,
prename .groups:n = { theoremgroup },
name .tl_set:N = \l_@@_key_name_tl,
name .default:n = \c_novalue_tl,
name .groups:n = { groupedtheorem, theoremvariants },
postname .tl_set:N = \l_@@_key_postname_tl,
postname .default:n = \c_empty_tl,
postname .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}\ma{keys}\ma{key group}\ma{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
% \meta{fallback name}.
%
% \begin{macrocode}
\cs_new:Npn \@@_set_normalized_keys:nnn #1 #2 #3
{
\keys_set:nn { groupthm } { prename, name, postname, 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_@@_prename_tl \l_@@_key_prename_tl
\tl_set_eq:NN \l_@@_postname_tl \l_@@_key_postname_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}\ma{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}\ma{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}{\@@_declare_theorem_group_aux:nnnnn}
% \begin{syntax}
% \cs{@@_declare_theorem_group_aux:nnnnn}\{\meta{theorem group}\}\{\meta{prename tl}\}
% \{\meta{postname tl}\}\{\meta{mapname clist}\}\{\meta{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 \@@_declare_theorem_group_aux:nnnnn #1#2#3#4#5
{
% \end{macrocode}
%
% \begin{macro}{\@@_use_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 { @@/prename } { #1 }
{
\tl_put_left:Nx \l_@@_prename_tl { #2 }
}
\hook_gput_code:nnn { @@/postname } { #1 }
{
\tl_put_right:Nx \l_@@_postname_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}{\@@_undeclare_theorem_group_aux:n}
% \begin{syntax}
% \cs{@@_undeclare_theorem_group_aux:n}\ma{theorem group}
% \end{syntax}
%
% Undeclares / undefines the given theorem group.
% This means removing its hook code in the \texttt{prename}, \texttt{postname},
% \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 \@@_undeclare_theorem_group_aux:n #1
{
\cs_undefine:c { @@_use_group_#1: }
% \end{macrocode}
%
% Remove properties from hooks
%
% \begin{macrocode}
\hook_gremove_code:nn { @@/prename } { #1 }
\hook_gremove_code:nn { @@/postname } { #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
{ @@/prename }
\g_@@_defined_theorem_groups_clist
{ unrelated }
{ #1 }
\@@_hook_gset_rule_foreach:nNnn
{ @@/postname }
\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 \groupthm_new_theorem_group:nnnnn #1 #2 #3 #4 #5
{
\cs_if_exist:cTF { @@_use_group_#1: }
{
\msg_error:nnnnn { groupthm } { wrong ~ definition }
{ theorem ~ group } { #1 } { already }
}
{
\@@_declare_theorem_group_aux: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: }
{
\@@_undeclare_theorem_group_aux:n { #1 }
\@@_declare_theorem_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 }
% \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: }
{
\@@_declare_theorem_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: }
{
\@@_undeclare_theorem_group_aux:n { #1 }
}
\@@_declare_theorem_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_by_keys:nn}
% \begin{syntax}
% \cs{groupthm_new_theorem_group_by_keys:nn}\ma{keys}\ma{theorem group}
% \end{syntax}
%
% \begin{macrocode}
\cs_new:Npn \groupthm_new_theorem_group_by_keys:nn #1#2
{
\@@_set_normalized_keys:nnn { #1 } { theoremgroup } { #2 }
\groupthm_new_theorem_group:nVVVV { #2 }
\l_@@_prename_tl
\l_@@_postname_tl
\l_@@_mapname_clist
\l_@@_thmtools_clist
}
% \end{macrocode}
% \end{macro}
%
%
%
% \begin{macro}{\groupthm_renew_theorem_group_by_keys:nn}
% \begin{syntax}
% \cs{groupthm_renew_theorem_group_by_keys:nn}\ma{keys}\ma{theorem group}
% \end{syntax}
%
% \begin{macrocode}
\cs_new:Npn \groupthm_renew_theorem_group_by_keys:nn #1#2
{
\@@_set_normalized_keys:nnn { #1 } { theoremgroup } { #2 }
\groupthm_renew_theorem_group:nVVVV { #2 }
\l_@@_prename_tl
\l_@@_postname_tl
\l_@@_mapname_clist
\l_@@_thmtools_clist
}
% \end{macrocode}
% \end{macro}
%
%
%
% \begin{macro}{\groupthm_provide_theorem_group_by_keys:nn}
% \begin{syntax}
% \cs{groupthm_provide_theorem_group_by_keys:nn}\ma{keys}\ma{theorem group}
% \end{syntax}
%
% \begin{macrocode}
\cs_new:Npn \groupthm_provide_theorem_group_by_keys:nn #1#2
{
\@@_set_normalized_keys:nnn { #1 } { theoremgroup } { #2 }
\groupthm_provide_theorem_group:nVVVV { #2 }
\l_@@_prename_tl
\l_@@_postname_tl
\l_@@_mapname_clist
\l_@@_thmtools_clist
}
% \end{macrocode}
% \end{macro}
%
%
%
% \begin{macro}{\groupthm_declare_theorem_group_by_keys:nn}
% \begin{syntax}
% \cs{groupthm_declare_theorem_group_by_keys:nn}\ma{keys}\ma{theorem group}
% \end{syntax}
%
% \begin{macrocode}
\cs_new:Npn \groupthm_declare_theorem_group_by_keys:nn #1#2
{
\@@_set_normalized_keys:nnn { #1 } { theoremgroup } { #2 }
\groupthm_declare_theorem_group:nVVVV { #2 }
\l_@@_prename_tl
\l_@@_postname_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_by_keys:nn { #1 } { #2 }
}
% \end{macrocode}
% \end{macro}
%
%
%
% \begin{macro}{\RenewTheoremGroup}
%
% \begin{macrocode}
\NewDocumentCommand{\RenewTheoremGroup}{ O{} m }
{
\groupthm_renew_theorem_group_by_keys:nn { #1 } { #2 }
}
% \end{macrocode}
% \end{macro}
%
%
%
% \begin{macro}{\ProvideTheoremGroup}
%
% \begin{macrocode}
\NewDocumentCommand{\ProvideTheoremGroup}{ O{} m }
{
\groupthm_provide_theorem_group_by_keys:nn { #1 } { #2 }
}
% \end{macrocode}
% \end{macro}
%
%
%
% \begin{macro}{\DeclareTheoremGroup}
%
% \begin{macrocode}
\NewDocumentCommand{\DeclareTheoremGroup}{ O{} m }
{
\groupthm_declare_theorem_group_by_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}\ma{keyname}\ma{theorem group 1}
% \ma{relation}\ma{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 \meta{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}[\meta{keyname}]%
% \{\meta{theorem group 1}\}\{\meta{relation}\}\{\meta{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{Grouped Theorems}
%
%
%
%
%
% \begin{macrocode}
%</package>
% \end{macrocode}
%
% \end{implementation}
% \end{documentation}
% \newpage