In the accepted answer to Code between \begin{environment} and \end{environment} stored in an array it's shown how to create an automatic list of theorems using expl3
syntax. However the \printtheorems
command only works if it's called after the theorems.
Is there a way to call it before the theorems? I was thinking a possible way to do it would be to compile the .tex twice, the first time to get the theorems and the second one to display them (like the Table of Contents does with chapters, sections ecc..).
The code linked above and the corresponding output are:
\documentclass{article}
\usepackage{amsmath}
\usepackage{amsthm}
\usepackage{environ}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\newtheoremx}{momo}
{
% * Let's duplicate the working of \newtheorem; \newtheoremx should
% be used for theorems that need to be listed
% * \newtheoremx{theorem}{Theorem} will actually do
% \newtheorem{theorem@inner}{Theorem} (honoring the usual optional arguments)
% * We also need a property list to store along with the theorem
% the one which it is subordinate to
\IfValueTF{#2}
{
\newtheorem{#1@inner}[#2@inner]{#3}
% #1 is subordinate to #2
\prop_gput:Nnn \g_riccardo_theorems_prop { #1 } { #2 }
}
{
\IfValueTF{#4}
{
\newtheorem{#1@inner}{#3}[#4]
}
{
\newtheorem{#1@inner}{#3}
}
% #1 is not subordinate, store the name itself
\prop_gput:Nnn \g_riccardo_theorems_prop { #1 } { #1 }
}
% define a "grabbing" environment #1 with the usual features
\NewEnviron{#1}[1][]
{
% start the inner environment (without or with optional argument)
\tl_if_empty:nTF { ##1 }
{ \begin{#1@inner} }
{ \begin{#1@inner}[##1] }
% save the statement number
\tl_gset:Nx \g__riccardo_theorems_number_tl { \use:c {@currentlabel} }
% typeset the statement
\BODY
% end the inner environment
\end{#1@inner}
% store the statement in a sequence variable, actually as
% four arguments as shown
\seq_gput_right:Nx \g_riccardo_theorems_seq
{
{ #1 } % name
{ \g__riccardo_theorems_number_tl } % number
{ \exp_not:n { ##1 } } % attribution
{ \exp_not:V \BODY } } % body
}
}
% allocate the needed variables
\prop_new:N \g_riccardo_theorems_prop
\seq_new:N \g_riccardo_theorems_seq
\tl_new:N \g__riccardo_theorems_number_tl
% print the stored theorems
\NewDocumentCommand{\printtheorems}{}
{
% we need a group where nullifying the action of \label
\group_begin:
\cs_set_eq:NN \label \use_none:n
% map the sequence, passing each item to the function that prints a theorem
\seq_map_function:NN \g_riccardo_theorems_seq \riccardo_printtheorems:n
% end the group
\group_end:
}
\cs_new_protected:Nn \riccardo_printtheorems:n
{
% just pass the argument in the form {name}{number}{attribution}{text}
% to a four argument function
\__riccardo_printtheorems:nnnn #1
}
\cs_new_protected:Nn \__riccardo_printtheorems:nnnn
{
% redefine \the<statement>@inner to yield the stored number
% we use the property list to use the correct counter
% (for instance, in case of "lemma", <statement> will be "theorem"
\cs_set:cpn { the \prop_item:Nn \g_riccardo_theorems_prop {#1} @inner } { #2 }
\tl_if_empty:nTF { #3 }
{
% no attribution
\begin{#1@inner} #4 \end{#1@inner}
}
{
% attribution
\begin{#1@inner}[#3] #4 \end{#1@inner}
}
}
\ExplSyntaxOff
\newtheoremx{theorem}{Theorem}[section]
\newtheoremx{lemma}[theorem]{Lemma}
\begin{document}
\section{First test}
\begin{theorem}[Important]\label{thm:important}
This is a theorem about $\log_a x$.
\end{theorem}
\begin{lemma}\label{lem:whatever}
This is a lemma.
\end{lemma}
\begin{theorem}\label{thm:unimportant}
This is another theorem
\end{theorem}
\section{Second test}
\begin{theorem}\label{thm:soandso}
Again a theorem.
\end{theorem}
\section{Theorems}
\printtheorems
\end{document}
EDIT: MWE showing the problem
\documentclass{memoir}
\usepackage{amsmath, amsthm, hyperref, environ, xparse, showkeys}
\ExplSyntaxOn
\NewDocumentCommand{\newtheoremx}{momo}
{
% * Let's duplicate the working of \newtheorem; \newtheoremx should
% be used for theorems that need to be listed
% * \newtheoremx{theorem}{Theorem} will actually do
% \newtheorem{theorem@inner}{Theorem} (honoring the usual optional arguments)
% * We also need a property list to store along with the theorem
% the one which it is subordinate to
\IfValueTF{#2}
{
\newtheorem{#1@inner}[#2@inner]{#3}
% #1 is subordinate to #2
\prop_gput:Nnn \g_riccardo_theorems_prop { #1 } { #2 }
}
{
\IfValueTF{#4}
{
\newtheorem{#1@inner}{#3}[#4]
}
{
\newtheorem{#1@inner}{#3}
}
% #1 is not subordinate, store the name itself
\prop_gput:Nnn \g_riccardo_theorems_prop { #1 } { #1 }
\seq_gput_right:Nn \g_riccardo_theorems_counters_seq { #1 }
}
% define a "grabbing" environment #1 with the usual features
\NewEnviron{#1}[1][]
{
% start the inner environment (without or with optional argument)
\tl_if_empty:nTF { ##1 }
{ \begin{#1@inner} }
{ \begin{#1@inner}[##1] }
% save the statement number
\tl_gset:Nx \g__riccardo_theorems_number_tl { \use:c {@currentlabel} }
% typeset the statement
\BODY
% end the inner environment
\end{#1@inner}
% store the statement in a sequence variable, actually as
% four arguments as shown
\seq_gput_right:Nx \g_riccardo_theorems_seq
{
{ #1 } % name
{ \g__riccardo_theorems_number_tl } % number
{ \exp_not:n { ##1 } } % attribution
{ \exp_not:V \BODY } }% body
}
}
% allocate the needed variables
\prop_new:N \g_riccardo_theorems_prop
\seq_new:N \g_riccardo_theorems_seq
\tl_new:N \g__riccardo_theorems_number_tl
\iow_new:N \g_riccardo_theorems_stream
\seq_new:N \g_riccardo_theorems_counters_seq
% print the stored theorems
\NewDocumentCommand{\printtheorems}{}
{
% we need a group where nullifying the action of \label
\group_begin:
\cs_set_eq:NN \label \use_none:n
% map the sequence, passing each item to the function that prints a theorem
\file_if_exist_input:n { \c_sys_jobname_str.thl }
% end the group
\group_end:
\seq_map_inline:Nn \g_riccardo_theorems_counters_seq
{
\setcounter{##1@inner}{0}
}
}
\cs_new_protected:Nn \riccardo_theorems_save:
{
\seq_map_function:NN \g_riccardo_theorems_seq \__riccardo_theorems_save:n
}
\cs_new_protected:Nn \__riccardo_theorems_save:n
{
\iow_now:Nn \g_riccardo_theorems_stream
{
\savedtheorem #1
}
}
\AtEndDocument
{
\iow_open:Nn \g_riccardo_theorems_stream { \c_sys_jobname_str.thl }
\riccardo_theorems_save:
\iow_close:N \g_riccardo_theorems_stream
}
\NewDocumentCommand{\savedtheorem}{mmmm}
{
% redefine \the<statement>@inner to yield the stored number
% we use the property list to use the correct counter
% (for instance, in case of "lemma", <statement> will be "theorem"
\cs_set:cpn { the \prop_item:Nn \g_riccardo_theorems_prop {#1} @inner } { #2 }
\tl_if_empty:nTF { #3 }
{
% no attribution
\begin{#1@inner} #4 \end{#1@inner}
}
{
% attribution
\begin{#1@inner}[#3] #4 \end{#1@inner}
}
}
\ExplSyntaxOff
\newtheoremx{theorem}{Theorem}[chapter]
\newtheoremx{lemma}[theorem]{Lemma}
\begin{document}
\chapter{Theorems}
\printtheorems
\clearpage
\section{First theorem}
\begin{theorem}[Important] \label{thm_1}
This is a theorem about $\log_a x$.
\end{theorem}
\clearpage
This is a link to \hyperref[thm_1]{Theorem 1}.
\end{document}
\printtheorems
can be used more than once?\printtheorems
twice that's causing the issue, right?\printtheorems
from the MWE I posted, but the theorem in the first chapter is still numbered incorrectly, so I guess different chapters are actually part of the problem.\setcounter{theorem@inner}{0}
before the first theorem of every chapter seems to do the job.