% \iffalse meta-comment
%
% Copyright (c) 2024- Jesse Straat
% 
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3c
% of this license or (at your option) any later version.
% The latest version of this license is in
%   https://www.latex-project.org/lppl.txt
% and version 1.3c or later is part of all distributions of LaTeX
% version 2008 or later.
%
% This work has the LPPL maintenance status `maintained'.
% 
% The Current Maintainer of this work is Jesse Straat.
%
% This work consists of the main file reptheorem.dtx
% and the derived files
%	reptheorem.sty, reptheorem.pdf, reptheorem.ins
%
% Unpacking:
% (a) If reptheorem.ins is present:
%		latex reptheorem.ins
% (b) If reptheorem.ins is absent:
%		latex reptheorem.dtx
%
% Documentation:
% 		pdflatex reptheorem.dtx
%       makeindex -s gind.ist -o reptheorem.ind reptheorem.idx
%       makeindex -s gglo.ist -o reptheorem.gls reptheorem.glo
%       pdflatex reptheorem.dtx
% dtx file based on https://www.texdev.net/2009/10/06/a-model-dtx-file/
%
%<*ignore>
\iffalse
%</ignore>
%
%<*readme>
# `reptheorem`

When writing a large manuscript, it is sometimes
beneficial to repeat a theorem (or lemma or…) at
an earlier or later point for didactical purposes.
However, `thmtools`'s built-in `restatable`
only allows replicating theorems *after* they
have been stated, and only in the same document.
`reptheorem` solves the issue by making use
of the `.aux` file, and also introduces its own file
extension, `.thm`, to replicate theorems in other files.

# Installation
Run the following in the command line:
1. If reptheorem.ins is present:
	`latex reptheorem.ins`
2. If reptheorem.ins is absent:
		`latex reptheorem.dtx`

Move `reptheorem.sty` to a folder that TeX can find.

# Documentation
Run the following in the command line:
```
pdflatex reptheorem.dtx
makeindex -s gind.ist -o reptheorem.ind reptheorem.idx
makeindex -s gglo.ist -o reptheorem.gls reptheorem.glo
pdflatex reptheorem.dtx
```
This automatically unpacks the package, as well.

---

&copy; 2024- Jesse Straat

License: [LPPL1.3c](https://www.latex-project.org/lppl.txt)

[GitHub Repository](https://github.com/JesseStraat/reptheorem)

%</readme>
%
%<*ignore>
\fi
\def\plainTeXstring{plain}
\ifx\fmtname\plainTeXstring\else
  \expandafter\begingroup
\fi
%</ignore>
%
%<*install>
\input docstrip.tex
\Msg{************************************************************************}
\Msg{* Installation}
\Msg{* Package: reptheorem 2026-08-11 v1.5}
\Msg{************************************************************************}

\keepsilent
\askforoverwritefalse

\preamble

Copyright (c) 2024- Jesse Straat

This work may be distributed and/or modified under the
conditions of the LaTeX Project Public License, either version 1.3c
of this license or (at your option) any later version.
The latest version of this license is in
  https://www.latex-project.org/lppl.txt
and version 1.3c or later is part of all distributions of LaTeX
version 2008 or later.

This work has the LPPL maintenance status `maintained'.

The Current Maintainer of this work is Jesse Straat.

This work consists of the main file reptheorem.dtx
and the derived files
	reptheorem.sty, reptheorem.pdf, reptheorem.ins

\endpreamble

\usedir{tex/latex/reptheorem}
\generate{
	\file{\jobname.sty}{\from{\jobname.dtx}{package}}
}

\obeyspaces
\Msg{************************************************************************}
\Msg{*}
\Msg{* To finish the installation you have to move the following}
\Msg{* file into a directory searched by TeX:}
\Msg{*}
\Msg{*     reptheorem.sty}
\Msg{*}
\Msg{* To produce the documentation run the file `reptheorem.dtx'}
\Msg{* through LaTeX.}
\Msg{*}
\Msg{* Happy TeXing!}
\Msg{*}
\Msg{************************************************************************}

%</install>
%<install>\endbatchfile
%
%<*ignore>
\usedir{source/latex/reptheorem}
\generate{
	\file{\jobname.ins}{\from{\jobname.dtx}{install}}
}

\nopreamble\nopostamble
\usedir{doc/latex/reptheorem}
\generate{
	\file{README.md}{\from{\jobname.dtx}{readme}}
}

\ifx\fmtname\plainTeXstring
  \expandafter\endbatchfile
\else
  \expandafter\endgroup
\fi
%</ignore>

%<*driver>
\NeedsTeXFormat{LaTeX2e}[2026/06/01]
\documentclass{ltxdoc}
\usepackage{\jobname}
\usepackage{amsthm}
\newtheorem{theorem}{Theorem}
\newtheorem*{theorem*}{Theorem}
\usepackage[final,
hyperindex=false,
colorlinks,
]{hyperref}
\EnableCrossrefs
\CodelineIndex
\RecordChanges
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% \GetFileInfo{\jobname.sty}
%
% \DoNotIndex{\begin,\end,\begingroup,\endgroup,\csname,\endcsname,\ifcsname,\if,\else,\IfFileExists,\IfValueTF,\fi}
% \DoNotIndex{\def,\edef,\expandafter,\gdef}
% \DoNotIndex{\immediate,\input}
% \DoNotIndex{\jobname,\label,\let,\long,\newcounter,\NewDocumentCommand}
% \DoNotIndex{\NewDocumentEnvironment,\noexpand}
% \DoNotIndex{\ProvidesPackage,\ref,\relax,\setcounter}
% \DoNotIndex{\string,\value,\write,\expanded,\IfBooleanT,\IfValueT,\ifx}
% \DoNotIndex{\makeatletter,\makeatother,\NewExpandableDocumentCommand,\providecommand}
% \DoNotIndex{\{,\},\@auxout,\c,\g,\l,\regex,\tl,\renewcommand}
%
% \title{^^A
%     \textsf{reptheorem}\thanks{^^A
%         Version \fileversion, last revised \filedate.^^A
%     }^^A
% }^^A
% \author{^^A
% 	Jesse Straat^^A
% }
% \date{\filedate}
%
% \maketitle
%^^A
% \begin{abstract}
%     \noindent When writing a large manuscript, it is sometimes
%     beneficial to repeat a theorem (or lemma or \dots) at
%     an earlier or later point for didactical purposes.
%     However, \textsf{thmtools}'s built-in |restatable|
%     only allows replicating theorems \textit{after} they
%     have been stated, and only in the same document.
%     \textsf{reptheorem} solves the issue by making use
%     of the |.aux| file, and also introduces its own file
%     extension, |.thm|, to replicate theorems in other files.
% \end{abstract}
%^^A
% \tableofcontents
%^^A
%\changes{v1.0}{2024/03/27}{First public release}
%^^A
%^^A
%^^A
%\StopEventually{^^A
%  \PrintChanges
%  \PrintIndex
%}
%^^A
%^^A
%^^A
%^^A
% \section{Repeating theorems}
% Let's say we define a theorem as follows:
% \begin{verbatim}
% \begin{theorem}[Yoneda Lemma]
%     For \(F\colon \mathcal{C}^\mathrm{op}\to \mathbf{Set}\) a functor,
%     \([\mathcal{C}^\mathrm{op},\mathbf{Set}](YA, F) \cong F(A)\)%
%     for all objects \(A\) in \(\mathcal{C}\).
% \end{theorem}
% \end{verbatim}
% Its output is of course
% \begin{makethm}{theorem}{thm:Yoneda}[Yoneda Lemma]
%     For \(F\colon \mathcal{C}^\mathrm{op}\to \mathbf{Set}\) a functor,
%     \([\mathcal{C}^\mathrm{op},\mathbf{Set}](YA, F) \cong F(A)\)
%     for all objects \(A\) in \(\mathcal{C}\).
% \end{makethm}
% Now let's say we want to replicate the theorem
% within the same document. That is what the new
% environment \DescribeEnv{makethm} |makethm| is
% used for.
% \begin{verbatim}
% \begin{makethm}{theorem}{thm:Yoneda}[Yoneda Lemma]
%     For \(F\colon \mathcal{C}^\mathrm{op}\to \mathbf{Set}\) a functor,
%     \([\mathcal{C}^\mathrm{op},\mathbf{Set}](YA, F) \cong F(A)\)
%     for all objects \(A\) in \(\mathcal{C}\).
% \end{makethm}
% \end{verbatim}
% Its output is the same (in fact, we've secretly used
% |makethm| in the previous example), but the important
% difference is that we have saved the theorem for later use.\par
% The |makethm| environment takes two mandatory arguments
% and one optional one. The first mandatory argument is the
% type of theorem environment as defined in \textsf{amsthm}, like |theorem|, |lemma|,
% |definition|, etc. The second is the theorem's label.
% The label is mandatory since, to replicate the theorem,
% we need to have a ``name'' attached to it. |makethm|
% automatically attaches a |\label|, as well, so |\ref{thm:Yoneda}|
% becomes \ref{thm:Yoneda}. The optional argument is passed
% right to the optional argument of the theorem environment,
% giving the theorem a name.\par
%^^A
% Now let's say we want to replicate the theorem later
% or earlier in the text. This may be done if, for example,
% the theorem is proven at a later point, or we want to
% ``tease'' the reader with a powerful theorem that will be
% proven later in the chapter. To do this, we use the
% \DescribeMacro{\repthm} |\repthm| command: |\repthm{thm:Yoneda}|.
% This outputs the theorem again.
% \repthm{thm:Yoneda}
% The label of this theorem is a |\ref|, and automatically
% links to the original theorem statement.\par
% If the original theorem statement exists in a different
% file, or has not been created yet, we can add a placeholder
% alt text to the |\repthm| as an optional argument, which
% only displays if the theorem is undefined. For example,
% |\repthm{thm:foo}[bar]| returns
% \repthm{thm:foo}[bar]
% \noindent If we do the same without providing an alt text, we get
% \repthm{thm:foo}
% \noindent together with a warning: ``Package \textsf{reptheorem}: Theorem |thm:foo|
% not defined; rebuild your project. If the issue persists, create the theorem
% using |\begin{makethm}| or consider adding alt text to |\repthm| using the optional
% parameter.''\par
% Since we're using the |.aux| file, it is possible
% to replicate a theorem before it is stated. For example,
% \begin{verbatim}
% \repthm{thm:later}
% \begin{makethm}{theorem}{thm:later}
%     Alligator!
% \end{makethm}
% \end{verbatim}
% returns
% \repthm{thm:later}
% \begin{makethm}{theorem}{thm:later}
%     Alligator!
% \end{makethm}
% Note that it is necessary to run a |.tex| file twice
% to replicate theorems ahead of time, similarly to
% how one has to run a file twice to make sure the
% references are correct.\par
% It is also possible to use a starred version, \DescribeMacro{\repthm*} |\repthm*|.
% It then automatically adds a star to the end of the theorem environment.
% For example, |\repthm*{thm:later}| returns
% \repthm*{thm:later}
%^^A
% \section{Replicating theorems between files}
% Let's say we have the following files for our project:
% \begin{verbatim}
% foo.tex
% bar.tex
% \end{verbatim}
% Let's say that we have defined a theorem |thm:baz|
% in |bar.tex|, and we want to replicate it in |foo.tex|.
% To achieve this, we first use the \DescribeMacro{\theoremfile}
% |\theoremfile| command in the preamble of |bar.tex|. This
% compiles all theorems defined in |bar.tex| and outputs them
% into a file |bar.thm|. To then import these into |foo.tex|, we
% use \DescribeMacro{\loadtheorems} |\loadtheorems{bar.thm}| in
% the preamble, which loads all theorems saved in |bar.thm|.
% One can then use |\repthm| as usual.\par
% Since the |.aux| file is loaded at |\begin{document}|, putting
% |\loadtheorems| in the preamble of a file will guarantee that
% the loaded theorem file will be overwritten by the theorems in
% the |.aux| file, i.e., theorems defined in the same document.
% In our example, if we also defined a |thm:baz| in |foo.tex|,
% loading |bar.thm| into |foo.tex| will not overwrite the local
% |thm:baz|.
%^^A
% \subsection{Replicating theorems to subfiles}
% Replicating theorems to different files is particularly
% useful when working in big documents with multiple subfiles.
% For example, let's say we have the files
% \begin{verbatim}
% main.tex
% foo.tex
% bar.tex
% \end{verbatim}
% Here, |main.tex| is generated by including |foo.tex|
% and |bar.tex| as chapters, creating a single large document.
% It is now possible to replicate theorems within the
% subfiles by running |\theoremfile| in |main.tex|,
% and then using |\loadtheorems{main.thm}| in
% |foo.tex| and |bar.tex|. This will allow us to
% use all theorems in the final |main.tex| in each of
% the subfiles.
%^^A
%^^A
%^^A
% \section{Source code}
%    \begin{macrocode}
%<*package>
\ProvidesPackage{reptheorem}[2026-08-11 v1.5 Reptheorem package]
%    \end{macrocode}
% \begin{macro}{\theoremfile}
% Using |\theoremfile| will output all saved theorems into an output file.
% By default, if your \LaTeX file is |foo.tex|, the output file is |foo.thm|.
%    \begin{macrocode}
\def\reptheorem@theoremfile{\relax}
\NewDocumentCommand{\theoremfile}{ O{\jobname.thm} }{
	% O: the path of the file to which we should save theorems
	%
 	\def\reptheorem@theoremfile{#1}
	\newwrite\@thmlist
	\immediate\openout\@thmlist=#1
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\loadtheorems}
% \changes{v1.4}{2025/04/15}{Now makes @ catcode 11 to fix incompatibility.}
% If you have exported saved theorems to a file, you can load them
% into another file using the macro |\loadtheorems|.
%    \begin{macrocode}
\NewDocumentCommand{\loadtheorems}{ m }{
	\IfFileExists{#1}{
		\makeatletter
		\input{#1}
		\makeatother
	}{
		\PackageWarning{reptheorem}{%
			File #1 not found. I will not import any theorems%
		}
	}
}
%    \end{macrocode}
% The |\makeatletter| is included here to assure that any macros that are
% expanded into macros that contain an |@| are interpreted correctly.
% \end{macro}
% \begin{macro}{\repthm@firstoffive}
% \changes{v1.4.1}{2025/08/20}{Added firstoffive command}
% This returns the first of five arguments. It is used to get
% the theorem number of a label.
%    \begin{macrocode}
\NewExpandableDocumentCommand{\repthm@firstoffive}{ m m m m m }{%
    #1%
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\repthm@ifrefexists}
% \changes{v1.4.1}{2025/09/03}{Added ifrefexists command}
% This command checks whether a label was defined in the auxiliary file.
% Using just |\ifcsname r@foo\endcsname| is not sufficient, since
% |\ref{foo}| defines |\r@foo| using a placeholder variable if the reference
% does not exist.
%    \begin{macrocode}
\NewExpandableDocumentCommand{\repthm@ifrefexists}{ m +m +m }{%
	% m: the label
	% m: code to run if true
	% m: code to run if false
	\ifcsname r@#1\endcsname
		% reference exists but might be dummy
		\expandafter\ifx\csname r@#1\endcsname\relax
			% reference is a dummy
			#3%
		\else
			% reference exists and is not a dummy
			#2%
		\fi
	\else
		% reference doesn't exist
		#3%
	\fi
}
%    \end{macrocode}
% \end{macro}
% \begin{environment}{makethm}
% \changes{v1.1}{2024/05/03}{Now saves theorem environment type, breaking backwards compatibility.}
% \changes{v1.2}{2024/09/21}{Environment end moved to fix vertical spacing.}
% \changes{v1.2}{2024/09/22}{Theorem name is only saved if it exists.}
% \changes{v1.2}{2024/09/22}{Renamed theorem output variable to be unique for each theorem.}
% \changes{v1.4}{2025/08/15}{Added theorem label to aux file.}
% \changes{v1.4.1}{2025/08/20}{Replaced theorem label saving macro.}
% \changes{v1.5}{2026/07/28}{Labels are now disabled in saved theorem.}
% On to defining the actual theorems to be saved.
%    \begin{macrocode}
\ExplSyntaxOn
\tl_new:N \g_reptheorem_thminput_tl
\NewDocumentEnvironment{makethm}{ m m o +b }
	% m: the type of theorem environment
	% m: the name of the theorem
	% o: optional parameter for environment
	% b: the content of the theorem
	%
	{%
		\IfValueTF{#3}{% Check if theorem has optional arguments
			\begin{#1}[#3]\label{#2}
		}{
			\begin{#1}\label{#2}
		}
		% \begin{theorem}
			#4
%    \end{macrocode}
% Saving labels inside theorems leads to all sorts of issues
% (multiply defining labels, the |.aux| file breaking), so we
% should filter those out using regex.
%    \begin{macrocode}
			\tl_set:Nn \l_tmpa_tl {#4}
			\regex_replace_all:nnN { \c{label}\{[^{}]*\} } { } \l_tmpa_tl
			\tl_gset_eq:NN \g_reptheorem_thminput_tl \l_tmpa_tl
			\expandafter\gdef\csname thmtype@#2\endcsname{#1}%
			\expandafter\long\expandafter\gdef\csname thm@#2\endcsname{
				\tl_use:N \g_reptheorem_thminput_tl
			}%
			\IfValueT{#3}{% Only save theorem name if it exists
				\expandafter\gdef\csname thmdesc@#2\endcsname{#3}%
			}
			% Saving parameters to aux file
			\expandafter\long\expandafter\gdef\csname thmoutput@#2\endcsname{%
				\string\expandafter\string\gdef\noexpand%
				\csname thmtype@#2\string\endcsname{#1}%
				^^J%
				\string\expandafter\string\long\string\expandafter%
				\string\gdef\noexpand\csname thm@#2\string\endcsname{
					\tl_use:N \g_reptheorem_thminput_tl
				}%
				\IfValueT{#3}{%
				^^J%
				\string\expandafter\string\gdef\noexpand%
				\csname thmdesc@#2\string\endcsname{#3}%
				}%
				^^J%
				\string\expandafter\string\gdef\noexpand%
				\csname thmlabel@#2\string\endcsname{%
				\repthm@ifrefexists{#2}{%
					\expandafter\repthm@firstoffive\expanded{\csname r@#2\endcsname}%
				}{}%
				}%
			}
			\write\@auxout{\csname thmoutput@#2\endcsname}
			\if\reptheorem@theoremfile\relax
				% No file has been set
			\else
				% We have a theorem file
				% Saving parameters to theorem file
				\write\@thmlist{\csname thmoutput@#2\endcsname}
			\fi
		\end{#1}
	}{}
\ExplSyntaxOff
%    \end{macrocode}
% \end{environment}
% \begin{macro}{\repthm}
% \changes{v1.1}{2024/05/03}{Now saves theorem environment type, breaking backwards compatibility.}
% \changes{v1.2}{2024/09/22}{Fixed bug where theorems got a name even if undefined.}
% \changes{v1.3}{2024/10/07}{Added hyperref named destination compatibility by setting counter to very low value.}
% \changes{v1.3}{2024/10/07}{Changed thetheorem to csname to fix compatibility with theorem types not called ``theorem''.}
% \changes{v1.4}{2024/11/05}{Added warnings for unknown counter and unknown theorem type.}
% \changes{v1.4}{2025/08/15}{If reference doesn't exist, saved label is now used instead of ??. Added star option.}
% \changes{v1.4.1}{2025/09/03}{Added fallback for when no label is saved.}
% \changes{v1.5}{2026/07/28}{Removed reference to thmtools since counter aliases are now part of \LaTeX{}.}
% \changes{v1.5}{2026/08/10}{Improved warnings (instructing a rerun), added counter backup, and replaced some thmtypes with thmcounters.}
% \changes{v1.5}{2026/08/10}{Changed defs to renewcommands in reference for beamer compatibility.}
% To repeat a theorem, use the |\repthm| command.
%    \begin{macrocode}
\newcounter{old@counter}
\NewDocumentCommand{\repthm}{ s m +o }{
	% s: optional star to add to theorem environment
	% m: the name of the theorem
	% o: alt text
	\begingroup
		% Check if thmtype is given
		\ifcsname thmtype@#2\endcsname%
			\expandafter\let\expandafter\@@thmtype\csname thmtype@#2\endcsname%
		\else%
			\def\@@thmtype{theorem}%
			\PackageWarning{reptheorem}{%
				Theorem '#2' has unknown theorem type. Assuming it is of
				type 'theorem'. If you just changed the theorem's type,
				rerun the file%
			}
		\fi%
		\edef\@@thmcounter{\@@thmtype}
		\IfBooleanT{#1}{\edef\@@thmtype{\@@thmtype*}}
		%
		% Save theorem counter so we don't increase it
		\ifcsname c@\@@thmcounter\endcsname
		\else
			\PackageWarning{reptheorem}{%
				Counter '\@@thmcounter' not defined. Reverting to counter
				'theorem'. If you just changed the theorem's type,
				rerun the file%
			}
			\def\@@thmcounter{theorem}
		\fi
		\setcounter{old@counter}{\value{\@@thmcounter}}
		\setcounter{\@@thmcounter}{-900}
		%
		% Set label number
		\repthm@ifrefexists{#2}{%
			% Reference exists: set number as reference
			\expandafter\renewcommand\csname the\@@thmcounter\endcsname{\ref{#2}}
		}{%
			% Force label number as saved
			\ifcsname thmlabel@#2\endcsname
				\expandafter\renewcommand\csname the\@@thmcounter\endcsname{%
					\csname thmlabel@#2\endcsname%
				}
			\else
				% No label number saved: revert to ??
				\expandafter\renewcommand\csname the\@@thmcounter\endcsname{\ref{#2}}
			\fi
		}
		%
		\ifcsname thm@#2\endcsname% Check if theorem is even defined
			% Theorem is defined
			\expandafter\let\expandafter\@@thm\csname thm@#2\endcsname
			% Output theorem
			\ifcsname thmdesc@#2\endcsname % Check if theorem has name
				\begin{\@@thmtype}[\csname thmdesc@#2\endcsname]
					\@@thm
				\end{\@@thmtype}
			\else % No optionals
				\begin{\@@thmtype}
					\@@thm
				\end{\@@thmtype}
			\fi
		\else
			% Theorem undefined
			\IfValueTF{#3}{
				\begin{\@@thmtype}
					#3
				\end{\@@thmtype}
			}{% No theorem or alt text provided: throw warning
				\begin{\@@thmtype}
				\end{\@@thmtype}
				\PackageWarning{reptheorem}{%
					Theorem '#2' not defined; rebuild your project.
					If the issue persists, create the theorem using
					\begin{makethm} or consider adding alt text to \repthm
					using the optional parameter%
				}
			}
		\fi
		\setcounter{\@@thmcounter}{\value{old@counter}}
		% Reset theorem counter back to original
    \endgroup
}
%    \end{macrocode}
% \end{macro}
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%\Finale
