% Maintained by Matthew Bertucci, 2024-present % Please report all issues and feature requests at https://github.com/mbertucci47/keytheorems % This work is licensed under the LPPL version 1.3c or later: https://www.latex-project.org/lppl.txt \ProvidesExplFile{keythms-beamer-support}{\@keythms@date}{\@keythms@version} {keytheorems~support~for~the~beamer~class} % disable \listofkeytheorems, add warning \msg_new:nnn { keytheorems } { beamer-listof } { \protect\listofkeytheorems\space not~supported~with~beamer } \RenewDocumentCommand \listofkeytheorems { +o } { \msg_warning:nn { keytheorems } { beamer-listof } } % besides above, do nothing if noamsthm loaded \IfClassLoadedWithOptionsT{ beamer }{ noamsthm }{ \file_input_stop: } \tl_new:N \g__keythms_thmstyle_example_metakeys_tl \tl_gset:Nn \g__keythms_thmstyle_example_metakeys_tl { bodyfont = \normalfont, headfont = \def\inserttheoremblockenv{exampleblock}, } \cs_set_protected:Npn \__keythms_thm_tcbcode:nn #1#2 { % #1 = name, #2 = tcolorbox keys \__keythms_thm_tcbshared:nn { #1 } { #2 } \tl_gput_left:cn { g__keythms_thm_preheadfromkeys_#1_tl } { \cs_set:Npn \inserttheoremblockenv { keythms_beamer_tcb } } } \cs_set_protected:Npn \__keythms_thm_tcbnotitlebarcode:nn #1#2 { % #1 = name, #2 = tcolorbox keys \__keythms_thm_tcbshared:nn { #1 } { #2 } \tl_gput_left:cn { g__keythms_thm_preheadfromkeys_#1_tl } { \cs_set:Npn \inserttheoremblockenv { keythms_beamer_tcbnotitlebar } } } \cs_set_protected:Npn \__keythms_thm_tcbshared:nn #1#2 { \RequirePackage{tcolorbox} \AddToHook{env/#1/begin} { % fix labels adding extra space \keys_define:nn { keytheorems/thmuse } { label .code:n = \tcbset{ phantom = { \label{##1} } } } } \tcbset { keythms_tcb_#1/.style = { savedelimiter=#1, #2 } } \tl_if_empty:NTF \l__keythms_thm_style_tl { \tl_set_eq:NN \l__keythms_thm_tempstyle_tl \l__keythms_thm_currentthmstyle_tl } { \tl_set_eq:NN \l__keythms_thm_tempstyle_tl \l__keythms_thm_style_tl } \tl_gput_right:ce { g__keythms_thm_preheadfromkeys_#1_tl } { % don't mess with tcolorbox defaults unless explicitly asked to in style \exp_not:N \tl_put_right:cn { th@ \l__keythms_thm_tempstyle_tl } { \thm@preskip=0pt \thm@postskip=0pt } } \tl_if_exist:cT { g__keythms_thmstyle_ \l__keythms_thm_tempstyle_tl _tcbspaceabove_skip } { \exp_args:Ne \tcbset { keythms_tcb_#1/.prefix~style = { before~skip = \skip_use:c { g__keythms_thmstyle_ \l__keythms_thm_tempstyle_tl _tcbspaceabove_skip } } } } \tl_if_exist:cT { g__keythms_thmstyle_ \l__keythms_thm_tempstyle_tl _tcbspacebelow_skip } { \exp_args:Ne \tcbset { keythms_tcb_#1/.prefix~style = { after~skip = \skip_use:c { g__keythms_thmstyle_ \l__keythms_thm_tempstyle_tl _tcbspacebelow_skip } } } } } \NewDocumentEnvironment{ keythms_beamer_tcb }{ m d<> } { \tl_if_novalue:nF { #2 } { \begin{actionenv}<#2> } \begin{tcolorbox}[ title={\usebeamerfont*{block title} #1}, keythms_tcb_\l_keythms_thmuse_envname_tl ] } { \end{tcolorbox} \tl_if_novalue:nF { #2 } { \end{actionenv} } } \NewDocumentEnvironment{ keythms_beamer_tcbnotitlebar }{ m d<> } { \tl_if_novalue:nF { #2 } { \begin{actionenv}<#2> } \begin{tcolorbox}[ keythms_tcb_\l_keythms_thmuse_envname_tl ] \group_begin: \usebeamerfont*{block title} #1 \thmheadnl \hskip\thm@headsep \group_end: } { \end{tcolorbox} \tl_if_novalue:nF { #2 } { \end{actionenv} } } \cs_set_protected:Npn \keythms_keyify_theorem:n #1 { % #1 = theorem name \DeclareEnvironmentCopy { keythms_orig_#1 } { #1 } \DeclareDocumentEnvironment { keythms_beamer_grab_#1 } { m m m +b } { % ##1 = keys, ##2 = note, ##3 = action spec, ##4 = theorem body \__keythms_thm_prehead_code:n { #1 } \tl_if_empty:nTF { ##3 } { \begin{keythms_orig_#1}[{##2}] } { \begin{keythms_orig_#1}[{##2}]<##3> } \clist_map_inline:Nn \g__keythms_restatecounters_clist { \prop_gput:Nne \g__keythms_thmuse_othercounters_prop { ####1 } { \the\value{####1} } } \__keythms_thm_posthead_code:n { #1 } % below needs to come after posthead so that correct \@currentHref % is stored for tcolorbox theorems \__keythms_thm_addcontentsdata:nnnn { #1 } { \prop_to_keyval:N \g__keythms_thmuse_othercounters_prop } { ##1 } { ##4 } \__keythms_thm_tempstorerestatedata:nnn { #1 } { ##1 } { ##4 } ##4 \__keythms_thm_prefoot_code:n { #1 } \end{keythms_orig_#1} \__keythms_thm_postfoot_code:n { #1 } } {} \DeclareDocumentEnvironment { keythms_beamer_grabreversed_#1 } { m m m +b } { % ##1 = keys, ##2 = note, ##3 = action spec, ##4 = theorem body \tl_if_exist:cTF { c__keythms_storeatbegin_ \l__keythms_thmuse_storereversed_tl _restatecounters_tl } { \bool_set_true:N \l__keythms_thmuse_restating_bool \prop_set_from_keyval:Ne \l__keythms_restate_counters_prop { \tl_use:c { c__keythms_storeatbegin_ \l__keythms_thmuse_storereversed_tl _restatecounters_tl } } \prop_map_inline:Nn \l__keythms_restate_counters_prop { \tl_set:ce { l_keythms_restate_current_####1_tl } { \the\value{####1} } \setcounter { ####1 } { ####2 } % ^ FIX: what if eq's numbered by section, theorem, etc.? The % thmtools code is opaque.... Or maybe should be up to the % user to say "restate-counters={section,chapter,...}". \cs_set:cpn { theH ####1 } { \use:c { the ####1 } . \theHkeythms_restate_dummyctr } } \tl_if_empty:cTF { c__keythms_storeatbegin_ \l__keythms_thmuse_storereversed_tl _label_tl } { \refstepcounter{keythms_restate_dummyctr} } % for unnumbered theorems { \cs_set:cpn { the #1 } { \tl_use:c { c__keythms_storeatbegin_ \l__keythms_thmuse_storereversed_tl _label_tl } } \cs_set_eq:cN { c@ #1 } \c@keythms_restate_dummyctr \cs_set_eq:cN { theH #1 } \theHkeythms_restate_dummyctr % ^ why are the last two lines here? We shouldn't be referencing % restated theorems. Think it's a remnant of thmtools % WRONG: needed to make numbering correct after restated theorem. % not sure about theH. <- this is needed to prevent duplicate anchors } } { \msg_warning:nnV { keytheorems } { store-reversed-not-got } \l__keythms_thmuse_storereversed_tl } \__keythms_thm_prehead_code:n { #1 } \hook_use:n { keytheorems/#1/restated } \hook_use:n { keytheorems/allthms/restated } \tl_if_empty:nTF { ##3 } { \begin{keythms_orig_#1}[{##2}] } { \begin{keythms_orig_#1}[{##2}]<##3> } \__keythms_thm_posthead_code:n { #1 } % below needs to come after posthead so that correct \@currentHref % is stored for tcolorbox theorems \__keythms_thm_addstoredreverseddata:nnn { #1 } { ##1 } { ##4 } \__keythms_thm_tempstorerestatedatareversed:nnn { #1 } { ##1 } { ##4 } ##4 \__keythms_thm_prefoot_code:n { #1 } \end{keythms_orig_#1} \__keythms_thm_postfoot_code:n { #1 } \prop_map_inline:Nn \l__keythms_restate_counters_prop { \exp_args:Nnc \setcounter { ####1 } { l_keythms_restate_current_####1_tl } } } { } % NOTE: have to do a lot of shenanigans to make sure the begin/end of grabbed % theorem env captures only the body and no package code. % This is the price of on-the-fly redefining the env to grab body \RenewDocumentEnvironment { #1 } { D<>{} ={note} O{} D<>{} } { \tl_set:Nn \l_keythms_thmuse_envname_tl { #1 } \keys_set:nn { keytheorems/thmuse } { ##2 } \tl_if_empty:NTF \l__keythms_thmuse_store_tl { \tl_if_empty:NTF \l__keythms_thmuse_storereversed_tl { \__keythms_thm_prehead_code:n { #1 } } { % \bool_gset_true:N \g__keythms_listof_writefile_bool % disable writing to file \cs_set_eq:NN \__keythms_beamer_withhooks_begin:nnnn \__keythms_beamer_grabreversed_begin:nnnn \cs_set_eq:NN \__keythms_beamer_withhooks_end:n \__keythms_beamer_grabreversed_end:n } } { % \bool_gset_true:N \g__keythms_listof_writefile_bool % disable writing to file \cs_set_eq:NN \__keythms_beamer_withhooks_begin:nnnn \__keythms_beamer_grab_begin:nnnn \cs_set_eq:NN \__keythms_beamer_withhooks_end:n \__keythms_beamer_grab_end:n } \tl_if_empty:nTF { ##3 } { % if ##3 empty, just pass ##1 and withhooks_begin will check if empty \__keythms_beamer_withhooks_begin:nnVn { #1 } { ##2 } \l__keythms_thmuse_note_tl { ##1 } } { % if ##3 nonempty, always use it (beamer defaults to second <> if both given) \__keythms_beamer_withhooks_begin:nnVn { #1 } { ##2 } \l__keythms_thmuse_note_tl { ##3 } } } { \__keythms_beamer_withhooks_end:n { #1 } \tl_if_empty:NF \l__keythms_thmuse_store_tl { \cs_if_exist:cF { __keythms_getthm_ \l__keythms_thmuse_store_tl _theorem } { \cs_new:cpe { __keythms_getthm_ \l__keythms_thmuse_store_tl _theorem } { \exp_not:N \__keythms_getthm_theorem:nnnnn \exp_not:o { \g__keythms_thmuse_temprestatedata_tl } } \cs_new:cpe { __keythms_getthm_ \l__keythms_thmuse_store_tl _body } { \exp_not:N \__keythms_getthm_body:nn \exp_args:No \exp_not:o { \exp_after:wN \__keythms_use_iii_v_braced:nnnnn \g__keythms_thmuse_temprestatedata_tl } } } } \tl_if_empty:NF \l__keythms_thmuse_storereversed_tl { \cs_if_exist:cF { __keythms_getthm_ \l__keythms_thmuse_storereversed_tl _theorem } { \cs_new:cpe { __keythms_getthm_ \l__keythms_thmuse_storereversed_tl _theorem } { \exp_not:N \__keythms_getthmreversed_theorem:nnn \exp_not:o { \g__keythms_thmuse_temprestatedatareversed_tl } } \cs_new:cpn { __keythms_getthm_ \l__keythms_thmuse_storereversed_tl _body } { \textbf{??} \msg_warning:nnn { keytheorems } { restate-body-never-got } { #1 } } } } } } \cs_new_protected:Npn \__keythms_beamer_withhooks_begin:nnnn #1#2#3#4 { % #1 = theorem name, #2 = keys, #3 = note, #4 = action spec \tl_if_empty:nTF { #4 } { \begin{keythms_orig_#1}[{#3}] } { \begin{keythms_orig_#1}[{#3}]<#4> } \__keythms_thm_posthead_code:n { #1 } \__keythms_thm_addcontentsdata:nnnn { #1 } { } { #2 } { } \ignorespaces % I hope this is alright } \cs_generate_variant:Nn \__keythms_beamer_withhooks_begin:nnnn { nnV } \cs_new_eq:NN \__keythms_beamer_withhooks_end:n \__keythms_withhooks_end:n \cs_new_protected:Npn \__keythms_beamer_grab_begin:nnnn #1#2#3#4 { % #1 = theorem name, #2 = keys, #3 = note \begin{keythms_beamer_grab_#1}{#2}{#3}{#4} } \cs_generate_variant:Nn \__keythms_beamer_grab_begin:nnnn { nnV } \cs_new_protected:Npn \__keythms_beamer_grab_end:n #1 { \end{keythms_beamer_grab_#1} } \cs_new_protected:Npn \__keythms_beamer_grabreversed_begin:nnnn #1#2#3#4 { % #1 = theorem name, #2 = keys, #3 = note \begin{keythms_beamer_grabreversed_#1}{#2}{#3}{#4} } \cs_generate_variant:Nn \__keythms_beamer_grabreversed_begin:nnnn { nnV } \cs_new_protected:Npn \__keythms_beamer_grabreversed_end:n #1 { \end{keythms_beamer_grabreversed_#1} } % for now, just disable writing to file \cs_set_eq:NN \__keythms_thm_addcontentsdata:nnnn \use_none:nnnn \cs_set_eq:NN \__keythms_thm_addstoredreverseddata:nnn \use_none:nnn \cs_new_protected:Npn \__keythms_beamer_reversedauxdata:nnnn #1#2#3#4 { \iow_shipout:Ne \@auxout { \token_to_str:N \KeyThmsBeamerReversedData { \l__keythms_thmuse_storereversed_tl } { \@currentlabel } { #2 } } } \cs_new_protected:Npn \KeyThmsBeamerReversedData #1#2#3 { \tl_if_exist:cF { c__keythms_storeatbegin_#1_label_tl } { \tl_const:cn { c__keythms_storeatbegin_#1_label_tl } { #2 } } \tl_if_exist:cF { c__keythms_storeatbegin_#1_restatecounters_tl } { \tl_const:cn { c__keythms_storeatbegin_#1_restatecounters_tl } { #3 } } \bool_if_exist:cF { g__keythms_restate_#1_called_bool } { \bool_new:c { g__keythms_restate_#1_called_bool } } } \cs_new_eq:NN \__keythms_ORIGgetthmreversed_theorem:nnn \__keythms_getthmreversed_theorem:nnn \cs_set_protected:Npn \__keythms_getthmreversed_theorem:nnn #1#2#3 { \group_begin: \cs_set_eq:NN \__keythms_thm_addcontentsdata:nnnn \__keythms_beamer_reversedauxdata:nnnn \__keythms_ORIGgetthmreversed_theorem:nnn { #1 } { #2 } { #3 } \group_end: } % restatable and restatable* environments need redefinition \bool_if:NT \g__keythms_thmtoolscompat_bool { \RenewDocumentEnvironment { restatable } { O{} m m } { % set store outside [] so keyless note is recognized \keys_set:nn { keytheorems/thmuse } { store=#3 } \begin{#2}[#1] } { \end{#2} \cs_gset_protected:cpn { #3 } { % make \foo and \foo* identical \peek_meaning_remove:NTF * { \getkeytheorem{ #3 } } { \getkeytheorem{ #3 } } } } \RenewDocumentEnvironment { restatable* } { O{} m m } { \cs_set_protected:Npn \__keythms_thm_tempstorerestatedatareversed:nnn ##1##2##3 { \tl_gset:Ne \g__keythms_thmuse_temprestatedatareversed_tl % needs to be global to get out of env { { ##1 } { store*=\l__keythms_thmuse_storereversed_tl,\exp_not:n { ##2 } } { \exp_not:n { ##3 } } } } % set store* outside [] so keyless note is recognized \keys_set:nn { keytheorems/thmuse } { store*=#3 } \begin{#2}[#1] } { \end{#2} \cs_gset_protected:cpn { #3 } { % make \foo and \foo* identical \peek_meaning_remove:NTF * { \getkeytheorem{ #3 } } { \getkeytheorem{ #3 } } } } } \file_input_stop: