diff --git a/doc/environments/groupthm/groupthm.tex b/doc/environments/groupthm/groupthm.tex index e1ce07f..474a8db 100644 --- a/doc/environments/groupthm/groupthm.tex +++ b/doc/environments/groupthm/groupthm.tex @@ -26,7 +26,6 @@ \begin{document} \maketitle -\section{test} \begin{documentation} \tableofcontents @@ -96,6 +95,18 @@ of conflicting properties of different \meta{theorem group}s a \meta{theorem} ma 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 @@ -138,7 +149,58 @@ 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). -\section{End user interface} + +\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} @@ -181,40 +243,15 @@ of the \meta{theorem family}, which then controls the membership in these groups It is subject to an \kw{x}-type expansion prior to being passed further to \pkg{thmtools}. \end{texnote} - As in the \pkg{xparse} package, the behavior of the prefixes is as follows: - \begin{description} - \item[\cs{NewTheoremGroup}] +\end{function} - Defines the theorem group if not defined already. - This emits an error in case the theorem group is already defined. +\subsection{Controlling theorem group precedence} - \item[\cs{RenewTheoremGroup}] - - Defines the theorem group although defined already. - This emits an error in case the theorem group has not been defined yet. - - \item[\cs{ProviedTheoremGroup}] - - Defines the theorem group if it is not defined already. - This does not emit an error if the group is already defined - (and has no effect in this case). - Typically used to ensure that some group exists, whilst not overwriting prior - (potentially more custom) definitions of the group. - - \item[\cs{DeclareTheoremGroup}] - - Defines the theorem group in disregard of any - existing definitions. An old definition will be overwritten. - \end{description} - - \subsection{Controlling theorem group precedence} - - \begin{function}{\DeclareTheoremGroupRule} +\begin{function}{\DeclareTheoremGroupRule} \begin{syntax} \cs{DeclareTheoremGroupRule}[\meta{keyname}]% \{\meta{theorem group 1}\}\{\meta{relation}\}\{\meta{theorem group 2}\} \end{syntax} - \end{function} This declares some relation between the two theorem groups, controlling their order of application in case a theorem is member @@ -240,12 +277,12 @@ of the \meta{theorem family}, which then controls the membership in these groups For us, the following list will suffice: \begin{description} - \item[\kw{higher} or \kw{after} or \k{>}] + \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[\k{lower} or \kw{before} or \k{<}] + \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}. @@ -263,6 +300,330 @@ of the \meta{theorem family}, which then controls the membership in these groups \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{group them} 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 \cs{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{xpars} 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* + } + + 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} \end{documentation} diff --git a/src/environments/groupthm.pysty3 b/src/environments/groupthm.pysty3 index 8a9fa6a..b199a37 100644 --- a/src/environments/groupthm.pysty3 +++ b/src/environments/groupthm.pysty3 @@ -393,7 +393,7 @@ __HEADER__(Grouping theorems for easier customization.) \add_theorem_to_group:n { #1 } } -\DeclareDocumentCommand{ \DeclareTheoremVariants }{ m m m } +\NewDocumentCommand{ \DeclareTheoremVariants }{ m m m } { \new_theorem_variant_parser:nnn { #1 } { #2 } { #3 } } @@ -430,7 +430,7 @@ __HEADER__(Grouping theorems for easier customization.) % TODO } -\DeclareDocumentCommand{\GenerateDefaultTheoremVariants}{ O{} m } +\NewDocumentCommand{\GenerateDefaultTheoremVariants}{ O{} m } { \generate_standard_theorem_variants_from_keys:nn { #2 } { #1 } } @@ -446,6 +446,11 @@ __HEADER__(Grouping theorems for easier customization.) thmtools = { numbered = no } ] { starred } +\NewTheoremGroup +[ + thmtools = { numbered = no } +] { unnumbered } + %% \NewTheoremGroup