%% %% This is file `proof-at-the-end.sty', %% generated with the docstrip utility. %% %% The original source files were: %% %% proof-at-the-end.dtx (with options: `proof-at-the-end.sty,package') %% %% proof-at-the-end.dtx %% Copyright 2022 Léo Colisson %% %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License, either version 1.3 %% of this license or (at your option) any later version. %% The latest version of this license is in %% http://www.latex-project.org/lppl.txt %% and version 1.3 or later is part of all distributions of LaTeX %% version 2005/12/01 or later. %% %% This work has the LPPL maintenance status `maintained'. %% %% The Current Maintainer of this work is Léo Colisson. %% %% This work consists of the files proof-at-the-end.dtx and proof-at-the-end.ins and the derived file proof-at-the-end.sty. %% %% \CharacterTable %% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z %% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z %% Digits \0\1\2\3\4\5\6\7\8\9 %% Exclamation \! Double quote \" Hash (number) \# %% Dollar \$ Percent \% Ampersand \& %% Acute accent \' Left paren \( Right paren \) %% Asterisk \* Plus \+ Comma \, %% Minus \- Point \. Solidus \/ %% Colon \: Semicolon \; Less than \< %% Equals \= Greater than \> Question mark \? %% Commercial at \@ Left bracket \[ Backslash \\ %% Right bracket \] Circumflex \^ Underscore \_ %% Grave accent \` Left brace \{ Vertical bar \| %% Right brace \} Tilde \~} \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{proof-at-the-end}[2022/02/07 A package to move proofs in appendix] \RequirePackage{etoolbox} \RequirePackage{thmtools} \RequirePackage{thm-restate} \RequirePackage{catchfile} \RequirePackage{pgfkeys} \RequirePackage{xparse} \AtEndPreamble{% \RequirePackage{hyperref} }% \RequirePackage{kvoptions} %% https://tex.stackexchange.com/questions/109747/put-all-package-options-into-one-command %% Forward the options list to the command \pratendOptdefconf %% in order to use: %% \usepackage[conf={normal}]{proof-at-the-end} \SetupKeyvalOptions{ family=pratendOpt, prefix=pratendOpt, % "Namespace": Prefix of the commands, conditions.... } \DeclareStringOption{conf} \DeclareLocalOptions{conf}% \pratendOptdefconf contains the proof \DeclareBoolOption{disablePatchSection} % Use \ifpratendOptdisablePatchSection ... \else ... \fi \DeclareStringOption[autoref]{commandRef} % Use commandRef=cref to use cleveref. Defaults to autoref. \DeclareBoolOption{createShortEnv} % To create thmE, theoremE, proofE, lemmaE, corrolaryE \ProcessKeyvalOptions* %% https://tex.stackexchange.com/a/13289/116348 \newwrite\appendwrite \newcount\pratend@count@makeallother %%% Loop to make sure all chars are normal letters, including #. \newcommand{\makeallother}{% \pratend@count@makeallother0\relax \loop\ifnum\pratend@count@makeallother<255\relax \catcode\pratend@count@makeallother12\relax \advance\pratend@count@makeallother by 1\relax \repeat } %%% This command allows the user to append things to a file. But the content may contain macros that %%% will be evaluated before writing them to the file. %%% TODO: Efficiency may be improved by writing to the file only before the printProof. \NewDocumentCommand\appendtofile{m+m}{% \begingroup %% Read the content \begingroup% \IfFileExists{#1}{% \newlinechar\endlinechar% \makeallother% Turn all chars into normal letters. \everyeof{\noexpand}% \edef\fileContent{\@@input #1 }% }{% \let\fileContent\empty }% %% Open the file to write in it: \immediate\openout\appendwrite #1\relax% %% Write the text \immediate\write\appendwrite{\fileContent}% \endgroup% \immediate\write\appendwrite{#2}% %% Close the file \immediate\closeout\appendwrite% \endgroup } %% Get the prefix of the file, given the jobname. \NewDocumentCommand\pratendGeneratePrefixFile{m}{#1-pratend} \def\prefixPrAtEndFiles{\pratendGeneratePrefixFile{\jobname}} %% This functions takes one input: the category (without .tex), %% If it's the first time we write in this %% category file, it "blanks" it. \newcommand*\eraseIfNeeded[1]{% % A macro 'pratendmacrocat{category}' is created to check % if it's the first time we write in this category file. \protected@edef\macroname{pratendmacrocat#1}% \ifcsdef{\macroname}{% The macro exists, nothing to do }{ % The macro does not exists, create it, and empty the file \global\expandafter\def\csname \macroname\endcsname{true}% \immediate\openout\appendwrite=\prefixPrAtEndFiles#1.tex% \immediate\write\appendwrite{}% \immediate\closeout\appendwrite% }% } \newif\ifproofhere \newif\ifproofend \newif\ifrestatethm \newif\ifexternalAppendix% True if the output file should me inputable in another file (using xr for crossref). Useful to remote restate. \newif\iflinktoproof \newif\ifboth \newif\ifallattheend \newif\ifrestatedbefore \pgfkeys{ /prAtEnd/.cd, %% Proof at end will be the main path %% Category of the proof (if you want to put proofs %% at several places), can be anything category/.initial=defaultcategory, category/.store in=\category, category/.get=\category, %% Display the proof in the main part proof here/.is if=proofhere, no proof here/.style={proof here=false}, % alias %% Display the proof when using \printProofs proof end/.is if=proofend, no proof end/.style={proof end=false}, %% Restate the theorem when using \printProofs only external appendix/.is if=externalAppendix, text link external appendix/.style={ text link={The proof is in the appendix.} }, external appendix/.style={ only external appendix, text link external appendix, }, %% Restate the theorem when using \printProofs restate/.is if=restatethm, no restate/.style={restate=false}, %% Put a link to the proof after the theorem link to proof/.is if=linktoproof, no link to proof/.style={link to proof=false}, %% Put the theorem and proof only in appendix opt all end/.is if=allattheend, no opt all end/.style={opt all end=false}, %% Text of link text link/.code={\def\pratendtextlink{#1}}, %% Text of proof. Make sure also to "\renewcommand*{\proofname}{Name of the proof}" %% to make sure the proof for normal theorems are changed text proof/.code={\def\pratendtextproof{#1}}, %% Custom restate command restate command/.code={\protected@edef\pratendcustomrestate{#1}}, %% (Re)stated before %% If the theorems has been stated before, then we just need to put the restate command in %% place of the argument, and we set this value to true: restated before/.is if=restatedbefore, no restated before/.style={restated before=false}, %% In star version, we don't want %% Put the text (defined only for \textInAppendix) in both the %% current location and in appendix both/.is if=both, no both/.style={both=false}, %%%% Alias and styles normal/.style={ proof here, no opt all end, no proof end, no link to proof, no restate, no both, }, proof at the end/.style={ no proof here, no opt all end, proof end, no both, }, end/.style={ proof at the end, link to proof, }, all end/.style={ end, opt all end, }, debug/.style={ no opt all end, proof here }, no link to theorem/.style={ % Remove the link to the theorem text proof={\proofname}, }, stared/.style={ % Remove text proof={\string\mbox{\string\hyperref[thm:prAtEnd\pratendcountercurrent]{\proofname}}}, }, no number/.style={ stared }, see full proof/.style={ text link={See \hyperref[proof:prAtEnd\pratendcountercurrent]{full proof} on page~\pageref{proof:prAtEnd\pratendcountercurrent}.} }, one big link/.style={ text link={\hyperref[proof:prAtEnd\pratendcountercurrent] {#1}} }, one big link/.default={% See proof on page~\pageref*{proof:prAtEnd\pratendcountercurrent}. }, one big link translated/.style={ one big link={#1~\pageref*{proof:prAtEnd\pratendcountercurrent}.} }, text link section/.style={% text link={See \hyperref[proof:prAtEnd\pratendcountercurrent]{proof} in \pratendSectionlikeCref.} }, text link section full proof/.style={% text link={See \hyperref[proof:prAtEnd\pratendcountercurrent]{full proof} in \pratendSectionlikeCref.} }, default text link/.style={ text link={See \hyperref[proof:prAtEnd\pratendcountercurrent]{proof} on page~\pageref{proof:prAtEnd\pratendcountercurrent}.}, }, text proof translated/.style={ text proof={#1 \string\pratendRef{thm:prAtEnd\pratendcountercurrent}}, }, default text proof/.style={ text proof={Proof of \string\pratendRef{thm:prAtEnd\pratendcountercurrent}}, }, %%%% Defaults bare defaults/.style={ end, link to proof, no restate, category=defaultcategory, default text link, default text proof, restate command=pratenddummymacro, }, configuration options/.style/.expand once={ % This styles will contain the configuration % given as options of the package like: % \usepackage[conf={normal, no link to proof}]{proof-at-the-end} % The package options does not accept macros and valued keys % due to some fundamental issues: % https://tex.stackexchange.com/questions/489564/use-unexpanded-macro-in-package-options/489570#489570 % so if you need to write macro/valued key, edit instead the % style "/prAtEnd/global custom defaults" or % "local /prAtEnd/custom defaults" for local changes instead. \pratendOptconf% }, global custom defaults/.style={ %% you can put in this style any global defaults %% that should overwrite the usual defaults. }, local custom defaults/.style={ %% you can put in this style any overwrite of the defaults %% that should be "local" and changed over the file, like % the category for a given section. }, all defaults/.style={ %% Load all the style that sets the default values bare defaults, configuration options, global custom defaults, local custom defaults, }, } \newcounter{counterAllProofEnd} \stepcounter{counterAllProofEnd} \NewDocumentEnvironment{theoremEndRestateBefore}{mO{}m+b}{ \stepcounter{counterAllProofEnd}% \protected@edef\currcounterval{\roman{counterAllProofEnd}} \protected@edef\temprest{\noexpand\begin{restatable*}[#2]{#1}{prAtEndRestate\currcounterval}\noexpand\label{thm:prAtEnd\currcounterval}}% \expandafter\protected@xdef\csname #3\endcsname{\currcounterval}% \temprest% #4% \end{restatable*}% }{} \NewDocumentEnvironment{theoremEnd}{O{}mO{}+b}{ % The first facultative argument will be the options: type of proof you want, the file to which you want to write... % The first mandatory option is the type of the theorem (thm,lemma,...) % The second facultative argument will be the title % the second mandatory option is the theorem (will \label inside eventually) % the last mandatory option is the proof \global\def\pratendlastoptions{#1}% \pgfkeys{% /prAtEnd/.cd, all defaults, #1 }% \stepcounter{counterAllProofEnd}% %% Pre-expand the restatable environment. Need protected %% otherwise can't have $\mathtt{G}$ in the title \protected@edef\temprest{\noexpand\begin{restatable}[#3]{#2}{prAtEndRestate\roman{counterAllProofEnd}}}% %% Create the file if it's the first time \eraseIfNeeded{\category}% %% If the theorem must be written here: \unless\ifallattheend% %% Restate the theorem if it was stated before: \ifrestatedbefore% \protected@xdef\pratendcountercurrent{\csname #4\endcsname} % Store the current (alpha value of the) counter \csname prAtEndRestate\pratendcountercurrent\endcsname % Restate the theorem \fi% %% Otherwise just state the theorem in a restatable environment \unless\ifrestatedbefore% \temprest% \label{thm:prAtEnd\roman{counterAllProofEnd}}% #4% \end{restatable}% %% Store the current (alpha value of the) counter %% in \pratendcountercurrent \protected@xdef\pratendcountercurrent{\roman{counterAllProofEnd}} % \fi% %% Create a custom alias to restate the theorem \expandafter\protected@xdef\csname \pratendcustomrestate\endcsname{\noexpand\csname prAtEndRestate\pratendcountercurrent\endcsname}% %% Restate the theorem if needed in appendix. %% As explained in https://github.com/leo-colisson/proof-at-the-end/issues/8 %% No need to restate of there is no proof at the end. \ifproofend% \ifrestatethm% \ifexternalAppendix% We write the full theorem, useful to compile in a separate file (use xr for references) \appendtofile{\prefixPrAtEndFiles\category.tex}{\string\begingroup\string\renewcommand\string\the\detokenize{#2}{\string\ref{thm:prAtEnd\pratendcountercurrent}}\string\begin{\detokenize{#2}}[#3]\detokenize{#4}\string\end{\detokenize{#2}}\string\endgroup}% \else% \appendtofile{\prefixPrAtEndFiles\category.tex}{\string\prAtEndRestate\pratendcountercurrent*}% \fi% \fi% \fi% \fi% %% If the theorem is not stated in the main text, %% write it at the end \ifallattheend% %% Store the current (alpha value of the) counter %% in \pratendcountercurrent \protected@xdef\pratendcountercurrent{\roman{counterAllProofEnd}} %% Create a custom alias to restate the theorem \expandafter\protected@xdef\csname \pratendcustomrestate\endcsname{\noexpand\csname prAtEndRestate\pratendcountercurrent\endcsname}% \appendtofile{\prefixPrAtEndFiles\category.tex}{\string\begin{restatable}[\detokenize{#3}]{#2}{prAtEndRestate\pratendcountercurrent}\string\label{thm:prAtEnd\pratendcountercurrent}\detokenize{#4}\string\end{restatable}}% \fi% }{} \NewDocumentEnvironment{proofEnd}{O{}+b}{ \pgfkeys{% /prAtEnd/.cd, all defaults, prAtEndTmpStyle/.style/.expand once={\pratendlastoptions}, prAtEndTmpStyle, #1 }% \unless\ifallattheend %% Write eventually a link to the proof \iflinktoproof% \pratendtextlink{}% \fi% %% And eventually the proof \ifproofhere% \begin{proof}% #2% \end{proof}% \fi% \fi% %% Write the proof at the end \ifproofend% \appendtofile{\prefixPrAtEndFiles\category.tex}{% %% The label alone adds some space, see e.g. %% https://tex.stackexchange.com/questions/600118/selectlanguage-in-the-middle-of-text-causes-extra-vertical-space/600142#600142 %% and https://tex.stackexchange.com/questions/600577/adding-a-label-between-two-proofs-adds-unwanted-space %% The solution is to use \\Hy@SaveLastskip and \Hy@RestoreLastskip from hyperref %% See also %% https://tex.stackexchange.com/questions/553394/reliably-add-a-label-to-the-current-section-even-if-the-label-is-not-placed-rig/600847#600847 \string\makeatletter\string\Hy@SaveLastskip% %% This tries to recover the label of the current section... But it is very bad. I keep it only for backward compatibility. I tried to fix it by changing the value of \@counter, but it's not always working %% as cref is not using it apparently, and it turns Appendix A into appendix a after using phantomsection. %% https://github.com/leo-colisson/proof-at-the-end/issues/2 \string\label{proofsection:prAtEnd\pratendcountercurrent}% WARNING <-- do not use this label in new documents! % the problem is that setting the \@currentlabel does not work for cref, and turns Appendix A % into section A when a phantomsection lies in between (not sure why): % https://github.com/leo-colisson/proof-at-the-end/issues/2 %% Now, we prefer a different method: instead we generate a single label per section, and we generate %% a new macro in the aux file that will save this label, by creating one such macro per theorem. %% This is basically doing something like \pratend@section@for@proofiii{prAtEnd:sectionlike3} %% Note that I need sometimes 3 \string because I write two times: the first time I write in the FILE-pratendCATEGORY.tex %% file, and this file will be in charge of writting into the .aux file. \string\ifdefined\string\pratend@current@sectionlike@label% But before, we check if the section was defined, or the code may fail if no section are defined. \string\immediate\string\write\string\@auxout{% \string\string\string\gdef\string\string\string\pratend@section@for@proof\pratendcountercurrent{\string\pratend@current@sectionlike@label}% }% \string\fi % See above \string\Hy@RestoreLastskip\string\makeatother% % We start the proof \string\begin{proof}[\pratendtextproof]% % We add a label to have a reference to the section \string\phantomsection\string\label{proof:prAtEnd\pratendcountercurrent}% % We add the proof \detokenize{#2}% % We end the proof \string\end{proof}}% \fi% }{} %%%%% Text in appendix \NewDocumentEnvironment{textAtEnd}{O{}+b}{ % Use it to put normal text in Appendix. \pgfkeys{ /prAtEnd/.cd, all defaults, #1 }% \ifboth% #2% \fi% \eraseIfNeeded{\category}% \appendtofile{\prefixPrAtEndFiles\category.tex}{\detokenize{#2}}% }{} \NewDocumentCommand\textEnd{O{}+m}{% \begin{textAtEnd}[#1]% #2% \end{textAtEnd}% } \NewDocumentCommand\printProofs{O{defaultcategory}}{ \input{\prefixPrAtEndFiles#1.tex} } %%% You can easily modify the defaults: %%% Or create new styles to apply: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Patch sections, chapters... %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \newcounter{pratend@counter@sectionlike} %% Command to add after a label like "prAtEnd:sectionlike10". Useful to patch \section, \chapter... \NewDocumentCommand\pratendAddLabel{}{% %% First, we get the label %% Cool explaination of expandafter, edef, noexpand: %%% https://www.tug.org/TUGboat/tb09-1/tb20bechtolsheim.pdf %% The label \pratend@current@sectionlike@label is used later. \edef\pratend@current@sectionlike@label{prAtEnd:sectionlike\thepratend@counter@sectionlike}% \expandafter\label{\pratend@current@sectionlike@label}% \stepcounter{pratend@counter@sectionlike}% }% %% Returns the label of the section (in appendix) that contains the proof of the current theorem. %% The first time, it will return an empty label. \NewDocumentCommand\pratendLabelProofSection{}{% \ifcsname pratend@section@for@proof\pratendcountercurrent\endcsname% \csname pratend@section@for@proof\pratendcountercurrent\endcsname% \fi% }% \NewDocumentCommand\pratendSectionlikeCref{}{% % \pratendRef{proofsection:prAtEnd\pratendcountercurrent}% This is not robust enough. Lets change strategy. \expandafter\pratendRef{\pratendLabelProofSection} } \ifpratendOptdisablePatchSection% \else % %% Add the above command to \chapter if the command exists \ifdef{\@chapter}{ \ifpatchable*{\@chapter}{ \apptocmd{\@chapter}{\pratendAddLabel}{}{}% }{\PackageWarning{proof-at-the-end}{Chapters are not patchable.}{}} }{} %% patch sections/subsections/paragraph/... %% https://tex.stackexchange.com/questions/631713/patch-section-command-fails/631717?noredirect=1#comment1575337_631717 \ifdef{\@sect}{ % \apptocmd{\section}{\pratendAddLabel}{}{}% \ifpatchable*{\@sect}{ \apptocmd{\@sect}{\pratendAddLabel}{}{}% }{\PackageWarning{proof-at-the-end}{Sections are not patchable.}{}} }{} \fi %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Allow cref/autoref/... %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Instead of \autoref{proof:blabla} use \pratendRef{proof:blabla}, it allows the ref command to be customized %% as an option of the package. \NewDocumentCommand\pratendRef{m}{% \csname \pratendOptcommandRef\endcsname{#1}% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Create automatically wrapper %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Defines a shortcut to avoid typing the whole theoremEnd environment. %% Avoid to manually type \NewDocumentEnvironment... %% Usage: \newEndThm[default options]{new environment}{old environment} \NewDocumentCommand{\newEndThm}{O{}mm}{% % \expandafter\NewDocumentEnvironment{#2}{O{}O{}+b}{% % \begin{theoremEnd}[#1,##2]{#3}[##1]% % ##3% % \end{theoremEnd}% % }{} \NewDocumentEnvironment{#2}{O{}O{}}{% \begin{theoremEnd}[#1,##2]{#3}[##1]% }{\end{theoremEnd}}% } %% Avoid to manually type \NewDocumentEnvironment... %% Usage: \newEndProof[default options]{new proof environment}{old proof environment} \NewDocumentCommand{\newEndProof}{O{}m}{% \NewDocumentEnvironment{#2}{O{}+b}{% \begin{proofEnd}[#1,##1]% ##2% \end{proofEnd}% }{}% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Create even more automatically wrapper with option "createShortEnv" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ifpratendOptcreateShortEnv %%% We create automatically the environments. \newEndProof{proofE} \newEndThm{thmE}{thm} \newEndThm{lemmaE}{lemma} \newEndThm{theoremE}{theorem} \newEndThm{corollaryE}{corollary} \newEndThm{propositionE}{proposition} \newEndThm{propertyE}{proposition} \newEndThm{factE}{proposition} \fi %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Create functions to easily overwrite defaults %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \NewDocumentCommand\pratendSetGlobal{m}{% \pgfkeys{/prAtEnd/global custom defaults/.style={ #1 }% }% } \NewDocumentCommand\pratendSetLocal{m}{% \pgfkeys{/prAtEnd/local custom defaults/.style={ #1 }% }% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Create functions to load the category file in another file (external bibliography) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \NewDocumentCommand\includeExternalAppendix{O{defaultcategory}m}{% \expandafter\input{\pratendGeneratePrefixFile{#2}#1} } \endinput %% %% End of file `proof-at-the-end.sty'.