% 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 \NeedsTeXFormat{LaTeX2e}[2023-06-01] \def\@keythms@date{2024-11-11} \def\@keythms@version{0.2.2} \ProvidesExplPackage{keytheorems}{\@keythms@date}{\@keythms@version} {l3keys interface to amsthm} \IfFormatAtLeastTF { 2024-06-01 } { } { \RequirePackage{nameref} % to avoid ltproperties in code below \cs_generate_variant:Nn \cs_set:Npn { Npe } \cs_generate_variant:Nn \iow_shipout:Nn { Ne } \cs_generate_variant:Nn \keys_set:nn { ne } \cs_generate_variant:Nn \msg_warning:nnn { nne } \cs_generate_variant:Nn \tl_put_right:Nn { Ne } \cs_generate_variant:Nn \tl_gput_right:Nn { ce } \ProvideDocumentCommand \IfPackageLoadedT { m +m } { \IfPackageLoadedTF{#1}{#2}{ } } \ProvideDocumentCommand \IfPackageLoadedF { m +m } { \IfPackageLoadedTF{#1}{ }{#2} } \ProvideDocumentCommand \IfClassLoadedT { m +m } { \IfClassLoadedTF{#1}{#2}{ } } \ProvideDocumentCommand \IfClassLoadedWithOptionsT { m m +m } { \IfClassLoadedWithOptionsTF{#1}{#2}{#3}{ } } \ProvideDocumentCommand \IfPackageLoadedWithOptionsT { m m +m } { \IfPackageLoadedWithOptionsTF{#1}{#2}{#3}{ } } } \RequirePackage{aliascnt} \RequirePackage{amsthm} % ams classes have way of ignoring this \RequirePackage{refcount} \RequirePackage{translations} %%%%%%%%%%%%%%%%%%%%%% %%% Error Messages %%% %%%%%%%%%%%%%%%%%%%%%% \msg_new:nnn { keytheorems } { thmtools-before } { keytheorems~is~not~compatible~with~thmtools.~ Try~replacing~\protect\usepackage{thmtools}~with~ \protect\usepackage[thmtools-compat]{keytheorems}. } \msg_new:nnn { keytheorems } { thmtools-after } { keytheorems~is~not~compatible~with~thmtools.~ This~will~not~work~as~you~think!~ Try~replacing~\protect\usepackage{thmtools}~with~ \protect\usepackage[thmtools-compat]{keytheorems}. } \msg_new:nnn { keytheorems } { no-stored-theorem } { No~stored~theorem~'#1'~found!~ Try~compiling~again.~If~that~doesn't~work,~ check~the~spelling~of~'#1'. } \msg_new:nnn { keytheorems } { no-prop-for-stored-theorem } { No~property~'#1'~found~for~stored~theorem~'#2'. } \msg_new:nnn { keytheorems } { store-reversed-not-got } { 'store*=#1'~only~makes~sense~if~you've~called~\protect\getkeytheorem{#1}.~ Check~that~\protect\getkeytheorem{#1}~is~called~and~compile~again. } \msg_new:nnn { keytheorems } { restate-body-never-got } { With~'store*=#1',~\protect\getkeytheorem[body]{#1}~only~makes~sense~if~ \protect\getkeytheorem{#1}~has~been~called.~ Check~that~\protect\getkeytheorem{#1}~is~called~and~compile~again. } \msg_new:nnn { keytheorems } { store-reversed-called-twice } { With~'store*=#1',~\protect\getkeytheorem{#1}~can~be~called~only~once. } \msg_new:nnn { keytheorems } { undefined-thm-hook } { No~theorem~hook~'#1'.~Check~the~spelling.~ Should~be~one~of~'prehead',~'posthead',~'prefoot',~'postfoot',~or'restated'. } \msg_new:nnn { keytheorems } { hyperref-Autoref } { You~have~not~loaded~hyperref.~The~\protect\Autoref\space command~needs~ hyperref~to~work. } \msg_new:nnn { keytheorems } { no-Autorefname } { No~Autoref~name~for~'#1'.~ Please~define~\c_backslash_str #1Autorefname. } \msg_new:nnn { keytheorems } { thmstyle-undefined } { Theorem~style~'#1'~undefined.~ Use~\protect\newkeytheoremstyle\space instead. } \msg_new:nnn { keytheorems } { thmstyle-defined } { Theorem~style~'#1'~already~defined.~ Use~\protect\renewkeytheoremstyle\space instead. } \msg_new:nnn { keytheorems } { inherit-thmstyle-undefined } { Theorem~style~'#1'~undefined. } \msg_new:nnn { keytheorems } { thm-undefined } { Command~\c_backslash_str #1~undefined.~ Use~\protect\newkeytheorem\space instead. } \msg_new:nnn { keytheorems } { title-code-with-AMS } { The~'title-code'~key~has~no~effect~with~an~AMS~class. } % Error if thmtools loaded since compilation hangs. % If thmtools loaded after, produce warning. \IfPackageLoadedTF { thmtools } { \msg_fatal:nn { keytheorems } { thmtools-before } } { \hook_gput_code:nnn { package/thmtools/before } { . } { \msg_warning:nn { keytheorems } { thmtools-after } } } %%%%%%%%%%%%%%%%%%%%%%%%% %%% Declare Variables %%% %%%%%%%%%%%%%%%%%%%%%%%%% \dim_new:N \l__keythms_tmpa_dim \iow_new:N \g__keythms_tmpa_iow \tl_new:N \l__keythms_tmpa_tl \bool_new:N \g__keythms_listof_writefile_bool \bool_gset_false:N \g__keythms_listof_writefile_bool \bool_new:N \g__keythms_thmtoolscompat_bool \bool_gset_false:N \g__keythms_thmtoolscompat_bool \bool_new:N \l__keythms_listofheading_storereversed_bool \bool_new:N \l__keythms_thm_numbered_bool \bool_new:N \l__keythms_thm_unlessunique_bool \bool_new:N \l__keythms_thmuse_listhack_bool \bool_new:N \l__keythms_thmuse_restating_bool \clist_new:N \g__keythms_restatecounters_clist \clist_new:N \l__keythms_thmstyle_savedkeys_clist \dim_new:N \l__keythms_thm_currparindent_dim \dim_new:N \l__keythms_thm_currparskip_dim \int_new:N \l__keythms_thm_tcbstate_int \prop_new:N \g__keythms_thmnames_prop \prop_new:N \g__keythms_thmstyle_defaultkeys_prop \prop_new:N \g__keythms_thmuse_othercounters_prop \prop_new:N \l__keythms_restate_counters_prop \tl_new:N \l__keythms_thm_currentthmstyle_tl \tl_new:N \l__keythms_thm_defaultkeys_tl \tl_new:N \l__keythms_thm_envname_tl \tl_new:N \l__keythms_thm_tcbkeys_tl \tl_new:N \l__keythms_thm_tempstyle_tl \tl_new:N \l__keythms_thmstyle_defaultkeys_tl \tl_new:N \l__keythms_thmstyle_lnotebrace_tl \tl_new:N \l__keythms_thmstyle_rnotebrace_tl \tl_new:N \l_keythms_thmuse_envname_tl \tl_new:N \g__keythms_thmuse_temprestatedata_tl \tl_new:N \g__keythms_thmuse_temprestatedatareversed_tl \newcounter{keythms_restate_dummyctr} \cs_gset:Npn \theHkeythms_restate_dummyctr { restate.\arabic{keythms_restate_dummyctr} } \cs_gset:Npn \thekeythms_restate_dummyctr { } \newcounter{keythms_continues_dummyctr} \cs_gset:Npn \theHkeythms_continues_dummyctr { continues.\arabic{keythms_continues_dummyctr} } \cs_gset:Npn \thekeythms_continues_dummyctr { } \newcounter{keythms_unnumbered_dummyctr} \cs_gset:Npn \theHkeythms_unnumbered_dummyctr { unnumbered.\arabic{keythms_unnumbered_dummyctr} } \cs_gset:Npn \thekeythms_unnumbered_dummyctr { } \cs_generate_variant:Nn \hook_gput_code:nnn { nnv } \cs_generate_variant:Nn \keys_precompile:nnN { ne, nVc } \cs_generate_variant:Nn \prop_set_from_keyval:Nn { Ne } %%%%%%%%%%%%%% %%% Styles %%% %%%%%%%%%%%%%% \cs_new_protected:Npn \__keythms_thmstyle_setbraces:nn #1#2 { % #1 = left brace, #2 = right brace \tl_set:Nn \l__keythms_thmstyle_lnotebrace_tl { #1 } \tl_set:Nn \l__keythms_thmstyle_rnotebrace_tl { #2 } } \cs_new_protected:Npn \keythms_thmstyle_savethmkey_reqval:n #1 { % #1 = key value \clist_put_right:No \l__keythms_thmstyle_savedkeys_clist { \l_keys_key_str = { #1 } } } \cs_new_protected:Npn \keythms_thmstyle_savethmkey_optval:n #1 { % #1 = key value \tl_if_empty:NTF \l_keys_value_tl { \clist_put_right:No \l__keythms_thmstyle_savedkeys_clist { \l_keys_key_str } } { \clist_put_right:No \l__keythms_thmstyle_savedkeys_clist { \l_keys_key_str = { #1 } } } } \keys_define:nn { keytheorems/thmstyle } { bodyfont .tl_set:N = \l__keythms_thmstyle_bodyfont_tl, break .meta:n = { postheadspace = \newline }, % add error if postheadspace set break .value_forbidden:n = true, headfont .tl_set:N = \l__keythms_thmstyle_headfont_tl, headformat .meta:n = { headstyle = {#1} }, % extra braces are necessary! Otherwise breaks if #1 contains comma headindent .tl_set:N = \l__keythms_thmstyle_headindent_tl, headpunct .tl_set:N = \l__keythms_thmstyle_headpunct_tl, headstyle .choice:, headstyle / margin .code:n = { \cs_set:Nn \keythms_thmstyle_headcmd:nnn { \makebox[0pt][r]{ \keythms_thmstyle_thmnumber:n { \group_begin: \exp_not:V \l__keythms_thmstyle_numberfont_tl ##2 ~ \group_end: } } \NAME\NOTE } }, headstyle / swapnumber .code:n = { \cs_set:Nn \keythms_thmstyle_headcmd:nnn { \keythms_thmstyle_thmnumber:n { \group_begin: \exp_not:V \l__keythms_thmstyle_numberfont_tl ##2 ~ \group_end: } \NAME\NOTE } }, headstyle / unknown .cs_set:Np = \keythms_thmstyle_headcmd:nnn #1#2#3, inherit-style .code:n = { \tl_if_exist:cTF { g__keythms_thmstyle_#1_metakeys_tl } { \keys_set:nv { keytheorems/thmstyle } { g__keythms_thmstyle_#1_metakeys_tl } } { \msg_error:nnn { keytheorems } { inherit-thmstyle-undefined } { #1 } } }, notebraces .code:n = \exp_after:wN \__keythms_thmstyle_setbraces:nn #1, notefont .tl_set:N = \l__keythms_thmstyle_notefont_tl, noteseparator .tl_set:N = \l__keythms_thmstyle_noteseparator_tl, numberfont .tl_set:N = \l__keythms_thmstyle_numberfont_tl, postheadspace .tl_set:N = \l__keythms_thmstyle_postheadspace_tl, spaceabove .tl_set:N = \l__keythms_thmstyle_spaceabove_tl, spacebelow .tl_set:N = \l__keythms_thmstyle_spacebelow_tl, % thm keys that are saved for later leftmargin .code:n = \keythms_thmstyle_savethmkey_reqval:n { #1 }, numbered .code:n = \keythms_thmstyle_savethmkey_optval:n { #1 }, numberlike .code:n = \keythms_thmstyle_savethmkey_reqval:n { #1 }, numberwithin .code:n = \keythms_thmstyle_savethmkey_reqval:n { #1 }, parent .code:n = \keythms_thmstyle_savethmkey_reqval:n { #1 }, postfoothook .code:n = \keythms_thmstyle_savethmkey_reqval:n { #1 }, postheadhook .code:n = \keythms_thmstyle_savethmkey_reqval:n { #1 }, prefoothook .code:n = \keythms_thmstyle_savethmkey_reqval:n { #1 }, preheadhook .code:n = \keythms_thmstyle_savethmkey_reqval:n { #1 }, qed .code:n = { % qed needs special treatment to distinguish qed from qed={} \tl_if_novalue:nTF { #1 } { \clist_put_right:No \l__keythms_thmstyle_savedkeys_clist { \l_keys_key_str } } { \clist_put_right:No \l__keythms_thmstyle_savedkeys_clist { \l_keys_key_str = { #1 } } } }, qed .default:o = \c_novalue_tl, rightmargin .code:n = \keythms_thmstyle_savethmkey_reqval:n { #1 }, sharenumber .code:n = \keythms_thmstyle_savethmkey_reqval:n { #1 }, sibling .code:n = \keythms_thmstyle_savethmkey_reqval:n { #1 }, tcolorbox .code:n = \keythms_thmstyle_savethmkey_optval:n { #1 }, tcolorbox-no-titlebar .code:n = \keythms_thmstyle_savethmkey_optval:n { #1 }, within .code:n = \keythms_thmstyle_savethmkey_reqval:n { #1 }, } \cs_new_protected:Nn \keythms_thmstyle_thmname:n { \thmname{#1} } \cs_new_protected:Nn \keythms_thmstyle_thmnumber:n { \thmnumber{#1} } \cs_new_protected:Nn \keythms_thmstyle_thmnote:n { \thmnote{#1} } \cs_new:Npn \keythms_thmstyle_headcmd_default:nnn #1#2#3 { \keythms_thmstyle_thmname:n { #1 } \keythms_thmstyle_thmnumber:n { ~ \group_begin: \exp_not:V \l__keythms_thmstyle_numberfont_tl #2 \group_end: } \keythms_thmstyle_thmnote:n { \exp_not:V \l__keythms_thmstyle_noteseparator_tl \group_begin: % group so notefont doesn't affect headpunct \exp_not:V \l__keythms_thmstyle_notefont_tl \l__keythms_thmstyle_lnotebrace_tl #3 \l__keythms_thmstyle_rnotebrace_tl \group_end: } } \prop_gset_from_keyval:Nn \g__keythms_thmstyle_defaultkeys_prop { % support files may overwrite these defaults bodyfont = \itshape, headfont = \bfseries, headindent = 0pt, headpunct = {.}, headstyle = \keythms_thmstyle_headcmd_default:nnn{#1}{#2}{#3}, notebraces = {(}{)}, notefont = \fontseries\mddefault\upshape, noteseparator = {~}, numberfont = \upshape, postheadspace = 5pt plus 1pt minus 1pt, spaceabove = {}, % empty means default (works for AMS classes too) spacebelow = {}, % empty means default (works for AMS classes too) } \hook_gput_code:nnn { package/keytheorems/after } { . } { % need to defer to wait for support files \keys_precompile:neN { keytheorems/thmstyle } { \prop_to_keyval:N \g__keythms_thmstyle_defaultkeys_prop } \l__keythms_thmstyle_defaultkeys_tl } \NewDocumentCommand \newkeytheoremstyle { m +m } { \cs_if_free:cTF { th@ #1 } { \keythms_thmstyle_declarestyle:nn { #1 } { #2 } } { \msg_error:nnn { keytheorems } { thmstyle-defined } { #1 } } } \NewDocumentCommand \renewkeytheoremstyle { m +m } { \cs_if_free:cTF { th@ #1 } { \msg_error:nnn { keytheorems } { thmstyle-undefined } { #1 } } { \keythms_thmstyle_declarestyle:nn { #1 } { #2 } } } \NewDocumentCommand \providekeytheoremstyle { m +m } { \cs_if_free:cT { th@ #1 } { \keythms_thmstyle_declarestyle:nn { #1 } { #2 } } } \NewDocumentCommand \declarekeytheoremstyle { m +m } { \keythms_thmstyle_declarestyle:nn { #1 } { #2 } } \@onlypreamble \newkeytheoremstyle \@onlypreamble \renewkeytheoremstyle \@onlypreamble \providekeytheoremstyle \@onlypreamble \declarekeytheoremstyle \cs_new_eq:NN \keythms_thmstyle_new:nnnnnnnnn \newtheoremstyle \cs_generate_variant:Nn \keythms_thmstyle_new:nnnnnnnnn { nVVVVVVVe } \tl_put_right:Nn \l_text_expand_exclude_tl { \thmnote \thmnumber \thmname } % ^ allows \thmnote, etc. to work in headstyle; hope no bad side effects! \cs_new_protected:Npn \keythms_thmstyle_declarestyle:nn #1#2 { % user is in charge of spacing with \NAME and \NUMBER (thmtools compat...) \cs_set:Npn \NAME { \keythms_thmstyle_thmname:n { ####1 } } \cs_set:Npn \NUMBER { \keythms_thmstyle_thmnumber:n { \group_begin: \exp_not:V \l__keythms_thmstyle_numberfont_tl ####2 \group_end: } } \cs_set:Npn \NOTE { \keythms_thmstyle_thmnote:n { \exp_not:V \l__keythms_thmstyle_noteseparator_tl \group_begin: % group so notefont doesn't affect headpunct \exp_not:V \l__keythms_thmstyle_notefont_tl \l__keythms_thmstyle_lnotebrace_tl ####3 \l__keythms_thmstyle_rnotebrace_tl \group_end: } } \clist_clear:N \l__keythms_thmstyle_savedkeys_clist \tl_use:N \l__keythms_thmstyle_defaultkeys_tl \keys_set:nn { keytheorems/thmstyle } { #2 } \keythms_thmstyle_new:nVVVVVVVe { #1 } \l__keythms_thmstyle_spaceabove_tl \l__keythms_thmstyle_spacebelow_tl \l__keythms_thmstyle_bodyfont_tl \l__keythms_thmstyle_headindent_tl \l__keythms_thmstyle_headfont_tl \l__keythms_thmstyle_headpunct_tl \l__keythms_thmstyle_postheadspace_tl { \text_expand:n { \keythms_thmstyle_headcmd:nnn{##1}{##2}{##3} } } % Define inherit-style key \tl_gclear_new:c { g__keythms_thmstyle_#1_metakeys_tl } \tl_gset:cn { g__keythms_thmstyle_#1_metakeys_tl } { #2 } \tl_clear_new:c { l__keythms_thmstyle_#1_savedthmkeys_tl } \keys_precompile:nVc { keytheorems/thm } \l__keythms_thmstyle_savedkeys_clist { l__keythms_thmstyle_#1_savedthmkeys_tl } \tl_if_empty:NF \l__keythms_thmstyle_spaceabove_tl { \skip_zero_new:c { g__keythms_thmstyle_#1_tcbspaceabove_skip } \skip_set_eq:cN { g__keythms_thmstyle_#1_tcbspaceabove_skip } \l__keythms_thmstyle_spaceabove_tl } \tl_if_empty:NF \l__keythms_thmstyle_spacebelow_tl { \skip_zero_new:c { g__keythms_thmstyle_#1_tcbspacebelow_skip } \skip_set_eq:cN { g__keythms_thmstyle_#1_tcbspacebelow_skip } \l__keythms_thmstyle_spacebelow_tl } \cs_undefine:N \NAME % undefine to prevent conflicts \cs_undefine:N \NUMBER \cs_undefine:N \NOTE } % set up plain, definition, and remark for inherit-style \tl_new:N \g__keythms_thmstyle_plain_metakeys_tl \tl_new:N \g__keythms_thmstyle_definition_metakeys_tl \tl_new:N \g__keythms_thmstyle_remark_metakeys_tl \tl_gset:Nn \g__keythms_thmstyle_definition_metakeys_tl { bodyfont=\normalfont } \tl_gset:Nn \g__keythms_thmstyle_remark_metakeys_tl { bodyfont = \normalfont, headfont = \itshape, spaceabove = 0.5\topsep, spacebelow = 0.5\topsep, } %%%%%%%%%%%%%%%%%%%%%%%%% %%% Defining Theorems %%% %%%%%%%%%%%%%%%%%%%%%%%%% % FIX: reimplement these without \NewDocumentCommand and \SplitArgument \NewDocumentCommand \keythms_thm_setrefnames:nn { m >{\SplitArgument{1}{,}} m } % #1 = envname, #2 = or { \__keythms_thm_setrefnames_aux:nnn{#1}#2 } \cs_new_protected:Npn \__keythms_thm_setrefnames_aux:nnn #1#2#3 { \cs_set:cpn { #1 autorefname } { #2 } \IfPackageLoadedT { cleveref } { \tl_if_novalue:nTF { #3 } { \crefname{#1}{#2}{\textbf{??~(pl.~#2)}} } { \crefname{#1}{#2}{#3} } } \IfPackageLoadedT { zref-clever } { \tl_if_novalue:nTF { #3 } { \zcRefTypeSetup{#1}{ name-sg=#2 } } { \zcRefTypeSetup{#1}{ name-sg=#2, name-pl=#3 } } } } \cs_generate_variant:Nn \keythms_thm_setrefnames:nn { nV } \NewDocumentCommand \keythms_thm_setRefnames:nn { m >{\SplitArgument{1}{,}} m } % #1 = envname, #2 = or { \__keythms_thm_setRefnames_aux:nnn{#1}#2 } \cs_new_protected:Npn \__keythms_thm_setRefnames_aux:nnn #1#2#3 { \cs_set:cpn { #1 Autorefname } { #2 } \IfPackageLoadedT { cleveref } { \tl_if_novalue:nTF { #3 } { \Crefname{#1}{#2}{\textbf{??~(pl.~#2)}} } { \Crefname{#1}{#2}{#3} } } \IfPackageLoadedT { zref-clever } { \tl_if_novalue:nTF { #3 } { \zcRefTypeSetup{#1}{ Name-sg=#2 } } { \zcRefTypeSetup{#1}{ Name-sg=#2, Name-pl=#3 } } } } \cs_generate_variant:Nn \keythms_thm_setRefnames:nn { nV } \keys_define:nn { keytheorems/thm } { heading .meta:n = { name = {#1} }, leftmargin .dim_set:N = \l__keythms_thm_leftmargin_dim, name .tl_set:N = \l__keythms_thm_name_tl, numbered .choice:, numbered .default:n = true, numbered / false .code:n = \bool_set_false:N \l__keythms_thm_numbered_bool, numbered / no .meta:n = { numbered = false }, numbered / true .code:n = \bool_set_true:N \l__keythms_thm_numbered_bool, numbered / unless-unique .code:n = { \bool_set_true:N \l__keythms_thm_unlessunique_bool }, numbered / unless~unique .meta:n = { numbered = unless-unique }, numbered / yes .meta:n = { numbered = true }, numberlike .meta:n = { sibling = {#1} }, numberwithin .meta:n = { parent = {#1} }, parent .tl_set:N = \l__keythms_thm_parent_tl, postfoothook .tl_set:N = \l__keythms_thm_postfoothook_tl, postheadhook .tl_set:N = \l__keythms_thm_postheadhook_tl, prefoothook .tl_set:N = \l__keythms_thm_prefoothook_tl, preheadhook .tl_set:N = \l__keythms_thm_preheadhook_tl, qed .tl_set:N = \l__keythms_thm_qed_tl, qed .default:o = \c_novalue_tl, % ^ distinguish between 'qed' and 'qed={}' refname .tl_set:N = \l__keythms_thm_refname_tl, Refname .tl_set:N = \l__keythms_thm_Refname_tl, rightmargin .dim_set:N = \l__keythms_thm_rightmargin_dim, sharenumber .meta:n = { sibling = {#1} }, sibling .tl_set:N = \l__keythms_thm_sibling_tl, style .tl_set:N = \l__keythms_thm_style_tl, style .groups:n = { style-comes-first }, tcolorbox .code:n = { \int_set:Nn \l__keythms_thm_tcbstate_int { 1 } \tl_set:Nn \l__keythms_thm_tcbkeys_tl { #1 } }, tcolorbox .default:n = {}, tcolorbox-no-titlebar .code:n = { \int_set:Nn \l__keythms_thm_tcbstate_int { 2 } \tl_set:Nn \l__keythms_thm_tcbkeys_tl { #1 } }, tcolorbox-no-titlebar .default:n = {}, title .meta:n = { name = {#1} }, within .meta:n = { parent = {#1} }, } \keys_precompile:nnN { keytheorems/thm } { leftmargin = 0pt, name = \q_no_value, numbered = true, parent = {}, postfoothook = {}, postheadhook = {}, prefoothook = {}, preheadhook = {}, qed = \q_no_value, refname = \q_no_value, Refname = \q_no_value, rightmargin = 0pt, sibling = {}, style = {}, } \l__keythms_thm_defaultkeys_tl \cs_new_protected:Npn \__keythms_thm_makethmhooks:n #1 { \hook_new_pair:nn { keytheorems/#1/prehead } { keytheorems/#1/postfoot } \hook_new_pair:nn { keytheorems/#1/posthead } { keytheorems/#1/prefoot } \hook_new:n { keytheorems/#1/restated } } % Make generic theorem hooks \__keythms_thm_makethmhooks:n { allthms } \NewDocumentCommand \newkeytheorem { m +O{} } { % #1 = name, #2 = keys \clist_map_inline:nn { #1 } % define multiple theorems at once { \keythms_thm_newkeythm:nn { ##1 } { #2 } } } \NewDocumentCommand \renewkeytheorem { m +O{} } { % #1 = name, #2 = keys \clist_map_inline:nn { #1 } { \keythms_thm_renewkeythm:nn { ##1 } { #2 } } } \NewDocumentCommand \providekeytheorem { m +O{} } { % #1 = name, #2 = keys \clist_map_inline:nn { #1 } { \keythms_thm_providekeythm:nn { ##1 } { #2 } } } \NewDocumentCommand \declarekeytheorem { m +O{} } { % #1 = name, #2 = keys \clist_map_inline:nn { #1 } { \keythms_thm_declarekeythm:nn { ##1 } { #2 } } } \@onlypreamble \newkeytheorem \@onlypreamble \renewkeytheorem \@onlypreamble \providekeytheorem \@onlypreamble \declarekeytheorem % to prevent error when plain, remark, or definition style used \tl_new:N \l__keythms_thmstyle_plain_savedthmkeys_tl \tl_new:N \l__keythms_thmstyle_remark_savedthmkeys_tl \tl_new:N \l__keythms_thmstyle_definition_savedthmkeys_tl \cs_new_protected:Npn \keythms_thm_newkeythm:nn #1#2 { % #1 = name, #2 = keys % Store envname \tl_set:Nn \l__keythms_thm_envname_tl { #1 } % Set up tl's for hooks; hooks will be created and added to at begindocument \tl_gclear_new:c { g__keythms_thm_preheadfromkeys_#1_tl } \tl_gclear_new:c { g__keythms_thm_postheadfromkeys_#1_tl } \tl_gclear_new:c { g__keythms_thm_prefootfromkeys_#1_tl } \tl_gclear_new:c { g__keythms_thm_postfootfromkeys_#1_tl } % Make unless-unique false by default (can't precompile this) \bool_set_false:N \l__keythms_thm_unlessunique_bool % Set default keys \tl_use:N \l__keythms_thm_defaultkeys_tl % Initialize tcb state to zero (1 is with title bar, 2 is without title bar) \int_zero:N \l__keythms_thm_tcbstate_int % First set style so we can pick up additional thm keys, then overwrite if necessary \keys_set_groups:nnn { keytheorems/thm } { style-comes-first } { #2 } % Store theorem style \tl_set:Ne \l__keythms_thm_currentthmstyle_tl { \the\thm@style } \tl_if_empty:NTF \l__keythms_thm_style_tl { % if \theoremstyle set, also use saved thm keys \tl_if_exist:cT {l__keythms_thmstyle_ \l__keythms_thm_currentthmstyle_tl _savedthmkeys_tl} { \tl_use:c {l__keythms_thmstyle_ \l__keythms_thm_currentthmstyle_tl _savedthmkeys_tl} } } { % Temporarily set theorem style \__keythms_theoremstyle:n { \l__keythms_thm_style_tl } % If thm keys given in style, call now (possibly overwritten in next step) % but don't error if user uses a style defined with just \newtheoremstyle \tl_if_exist:cT { l__keythms_thmstyle_ \l__keythms_thm_style_tl _savedthmkeys_tl } { \tl_use:c { l__keythms_thmstyle_ \l__keythms_thm_style_tl _savedthmkeys_tl } } } % Set env-specific keys \keys_set:nn { keytheorems/thm } { #2 } % Build tl for env-specific hooks; will be added to hooks at begindocument \tl_gput_right:cV { g__keythms_thm_preheadfromkeys_#1_tl } \l__keythms_thm_preheadhook_tl \tl_gput_right:cV { g__keythms_thm_postheadfromkeys_#1_tl } \l__keythms_thm_postheadhook_tl \tl_gput_right:cV { g__keythms_thm_prefootfromkeys_#1_tl } \l__keythms_thm_prefoothook_tl \tl_gput_right:cV { g__keythms_thm_postfootfromkeys_#1_tl } \l__keythms_thm_postfoothook_tl % Set name if none given \quark_if_no_value:NT \l__keythms_thm_name_tl % use quark so name={} is valid { % use e so \text_titlecase called only once per theorem definition, % not each time the theorem is used \tl_set:Ne \l__keythms_thm_name_tl { \text_titlecase_first:n { #1 } } } % associate formatted name with envname in prop list \prop_gput:NnV \g__keythms_thmnames_prop { #1 } \l__keythms_thm_name_tl % Call correct \newtheorem variant \bool_if:NTF \l__keythms_thm_unlessunique_bool { % [unq] is required since aux is read at begindocument % (technically right before) which is after theorem is defined \RequirePackage[unq]{unique} \tl_if_empty:NTF \l__keythms_thm_parent_tl { \tl_gput_right:cn { g__keythms_thm_preheadfromkeys_#1_tl } { \setuniqmark { #1 } } \ifuniq{ #1 } { \bool_set_false:N \l__keythms_thm_numbered_bool } { \bool_set_true:N \l__keythms_thm_numbered_bool } \bool_if:NTF \l__keythms_thm_numbered_bool { \tl_if_empty:NTF \l__keythms_thm_sibling_tl { \__keythms_thm_new_numbered:nV { #1 } \l__keythms_thm_name_tl } { \exp_args:NnV \newaliascnt { #1 } \l__keythms_thm_sibling_tl \__keythms_thm_new_sibling:nVn { #1 } \l__keythms_thm_name_tl { #1 } \aliascntresetthe { #1 } } } { \__keythms_thm_new_unnumbered:nV { #1 } \l__keythms_thm_name_tl \tl_gput_right:cn { g__keythms_thm_preheadfromkeys_#1_tl } { \keythms_if_restating:F { \refstepcounter{ keythms_unnumbered_dummyctr } } } } } { \__keythms_thm_new_uuwithparent:nVV { #1 } \l__keythms_thm_name_tl \l__keythms_thm_parent_tl } } { \bool_if:NTF \l__keythms_thm_numbered_bool { \tl_if_empty:NTF \l__keythms_thm_parent_tl { \tl_if_empty:NTF \l__keythms_thm_sibling_tl { \__keythms_thm_new_numbered:nV { #1 } \l__keythms_thm_name_tl } { \exp_args:NnV \newaliascnt { #1 } \l__keythms_thm_sibling_tl \__keythms_thm_new_sibling:nVn { #1 } \l__keythms_thm_name_tl { #1 } \aliascntresetthe { #1 } } } { \__keythms_thm_new_parent:nVV { #1 } \l__keythms_thm_name_tl \l__keythms_thm_parent_tl } } { \__keythms_thm_new_unnumbered:nV { #1 } \l__keythms_thm_name_tl \tl_gput_right:cn { g__keythms_thm_preheadfromkeys_#1_tl } { \keythms_if_restating:F { \refstepcounter{ keythms_unnumbered_dummyctr } } } } } % Store theorem def and redefine it with keys \keythms_keyify_theorem:n { #1 } % define \autorefname and \Autorefname, might be redefined next \exp_args:NnV \cs_set:cpn { #1 autorefname } \l__keythms_thm_name_tl \exp_args:NnV \cs_set:cpn { #1 Autorefname } \l__keythms_thm_name_tl % Set ref names \quark_if_no_value:NF \l__keythms_thm_refname_tl { \keythms_thm_setrefnames:nV { #1 } \l__keythms_thm_refname_tl } \quark_if_no_value:NF \l__keythms_thm_Refname_tl { \keythms_thm_setRefnames:nV { #1 } \l__keythms_thm_Refname_tl } % Set margins if needed \bool_lazy_or:nnT { ! \dim_compare_p:nNn { \l__keythms_thm_leftmargin_dim } = { 0pt } } { ! \dim_compare_p:nNn { \l__keythms_thm_rightmargin_dim } = { 0pt } } { \exp_args:NnVV \__keythms_thm_margincode:nnn { #1 } \l__keythms_thm_leftmargin_dim \l__keythms_thm_rightmargin_dim } % Set up qed if needed \quark_if_no_value:NF \l__keythms_thm_qed_tl { \exp_args:Nno \__keythms_thm_qedcode:nn { #1 } { \l__keythms_thm_qed_tl } } % Set up tcolorbox if needed \int_compare:nNnTF { \l__keythms_thm_tcbstate_int } = { 1 } { \exp_args:Nno \__keythms_thm_tcbcode:nn { #1 } { \l__keythms_thm_tcbkeys_tl } } { \int_compare:nNnT { \l__keythms_thm_tcbstate_int } = { 2 } { \exp_args:Nno \__keythms_thm_tcbnotitlebarcode:nn { #1 } { \l__keythms_thm_tcbkeys_tl } } } % Set up list-of definition \cs_set_eq:cN { l@ #1 } \keythms_listof_tocline: % Set default list-of display command \__keythms_listof_show_aux:n { #1 } % Set theorem style back to original state if needed \tl_if_empty:NF \l__keythms_thm_style_tl { \__keythms_theoremstyle:V \l__keythms_thm_currentthmstyle_tl } } \hook_gput_code:nnn { begindocument } { . } { \prop_map_inline:Nn \g__keythms_thmnames_prop { \__keythms_thm_makethmhooks:n { #1 } \clist_map_inline:nn { prehead, posthead, prefoot, postfoot } { \tl_if_empty:cF { g__keythms_thm_##1fromkeys_#1_tl } { \hook_gput_code:nnv { keytheorems/#1/##1 } { keythms_hook_keys } { g__keythms_thm_##1fromkeys_#1_tl } } } \use:c { g__keythms_thm_tcbpatch_#1_tl } } \cs_set_eq:NN \__keythms_thm_origtrivlist: \trivlist % for margin code below } \cs_new_protected:Npn \__keythms_thm_margincode:nnn #1#2#3 { \tl_gput_right:cn { g__keythms_thm_preheadfromkeys_#1_tl } { \dim_set_eq:NN \l__keythms_thm_currparindent_dim \parindent \dim_set_eq:NN \l__keythms_thm_currparskip_dim \parskip \cs_set_protected:Npn \trivlist { \list{ } { \dim_set:Nn \leftmargin { #2 } \dim_set:Nn \rightmargin { #3 } \dim_zero:N \labelwidth % trivlist does this; important for tcb-no-title % need to revert some adjustments \list makes (any more?) \int_gdecr:N \@listdepth % avoid changing format of inner lists \dim_set_eq:NN \listparindent \l__keythms_thm_currparindent_dim \dim_set_eq:NN \parsep \l__keythms_thm_currparskip_dim } } } \tl_gput_right:cn { g__keythms_thm_postheadfromkeys_#1_tl } { \cs_set_eq:NN \trivlist \__keythms_thm_origtrivlist: } } \cs_new_protected:Npn \__keythms_thm_tcbcode:nn #1#2 { % #1 = name, #2 = tcolorbox keys \tl_gput_right:cn { g__keythms_thm_preheadfromkeys_#1_tl } { \cs_set_eq:NN \deferred@thm@head \__keythms_thm_storedeferred@thm@head:n \cs_set_eq:NN \Hy@theorem@makelinktarget \use_none:n % % ^ don't like playing with hyperref internals... but don't see around % % it because hyperref tries to add to para hook which doesn't work % % when title set up the way we do it } \__keythms_thm_tcbshared:nn { #1 } { title={ \__keythms_thm_tcbtemphead: }, #2 } \bool_if:NT \l__keythms_thm_numbered_bool { \tl_gclear_new:c { g__keythms_thm_tcbpatch_#1_tl } \tl_gset:cn { g__keythms_thm_tcbpatch_#1_tl } { \IfPackageLoadedF { cleveref } { % hyperref doesn't patch \@thm if cleveref loaded \tcbset { keythms_tcb_#1/.append~style = % fix hyperlinking { phantom={ \MakeLinkTarget*{\@currentHref} } } } } } } \tl_gput_left:cn { g__keythms_thm_postheadfromkeys_#1_tl } { \begin{tcolorbox}[keythms_tcb_#1] } \tl_gput_right:cn { g__keythms_thm_prefootfromkeys_#1_tl } { \end{tcolorbox} } } \cs_new_protected:Npn \__keythms_thm_tcbnotitlebarcode:nn #1#2 { % #1 = name, #2 = tcolorbox keys \__keythms_thm_tcbshared:nn { #1 } { #2 } \tl_gclear_new:c { g__keythms_thm_#1_tcbprehead_tl } \tl_gset:cn { g__keythms_thm_#1_tcbprehead_tl } { \begin{tcolorbox}[keythms_tcb_#1] } \tl_gclear_new:c { g__keythms_thm_#1_tcbpostfoot_tl } \tl_gset:cn { g__keythms_thm_#1_tcbpostfoot_tl } { \end{tcolorbox} } } \cs_new_protected:Npn \__keythms_thm_tcbshared:nn #1#2 { \RequirePackage{tcolorbox} \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 } } } } } % what below is unnecessary? I really don't understand this code. \cs_new_protected:Npn \__keythms_thm_storedeferred@thm@head:n #1 { \if@inlabel \indent \par \fi % eject a section head if one is pending \if@nobreak \adjust@parskip@nobreak \else \addpenalty\@beginparpenalty \addvspace\@topsep \addvspace{-\parskip} \fi % \global\@inlabeltrue % MB: if this is uncommented then spacing after sections is wrong \everypar\dth@everypar \cs_set:Npn \__keythms_thm_tcbtemphead: { \normalfont #1 } \ignorespaces } \cs_new_protected:Npn \__keythms_thm_qedcode:nn #1#2 { % #1 = name, #2 = symbol \tl_gput_right:cn { g__keythms_thm_postheadfromkeys_#1_tl } { \tl_if_novalue:nF { #2 } { \protected@edef\qedsymbol{#2} } \pushQED{\qed} } \tl_gput_left:cn { g__keythms_thm_prefootfromkeys_#1_tl } { \tl_if_novalue:nF { #2 } { \protected@edef\qedsymbol{#2} } \popQED } } \cs_new_protected:Npn \__keythms_nocheck_removefromreset:nn #1#2 { % need to fake @ckpt counter \group_begin: \cs_if_exist:cF { c@#2 } { \cs_set:cpn { c@#2 } { } } \@removefromreset{#1}{#2} \group_end: } \cs_new_protected:Npn \keythms_thm_renewkeythm:nn #1#2 { % #1 = name, #2 = keys \cs_if_exist:cTF { #1 } { \cs_undefine:c { #1 } \cs_undefine:c { c@ #1 } \cs_undefine:c { the #1 } \tl_if_exist:cT { g__keythms_thm_#1_parent_tl } { % remove parent counter binding \exp_args:Nnv \@removefromreset { #1 } { g__keythms_thm_#1_parent_tl } } \__keythms_nocheck_removefromreset:nn { #1 } { @ckpt } \keythms_thm_newkeythm:nn { #1 } { #2 } } { \msg_error:nnn { keytheorems } { thm-undefined} { #1 } } } \cs_new_protected:Npn \keythms_thm_providekeythm:nn #1#2 { % #1 = name, #2 = keys \cs_if_free:cT { #1 } { \keythms_thm_newkeythm:nn { #1 } { #2 } } } \cs_new_protected:Npn \keythms_thm_declarekeythm:nn #1#2 { % #1 = name, #2 = keys \cs_undefine:c { #1 } \cs_undefine:c { c@ #1 } \cs_undefine:c { the #1 } \tl_if_exist:cT { g__keythms_thm_#1_parent_tl } { % remove parent counter binding \exp_args:Nnv \@removefromreset { #1 } { g__keythms_thm_#1_parent_tl } } \__keythms_nocheck_removefromreset:nn { #1 } { @ckpt } \keythms_thm_newkeythm:nn { #1 } { #2 } } \cs_new_eq:NN \__keythms_theoremstyle:n \theoremstyle \cs_generate_variant:Nn \__keythms_theoremstyle:n { V } \cs_new_eq:NN \__keythms_thm_new:w \newtheorem \cs_new_protected:Npn \__keythms_thm_new_numbered:nn #1#2 { \__keythms_thm_new:w { #1 } { #2 } } \cs_generate_variant:Nn \__keythms_thm_new_numbered:nn { nV } \cs_new_protected:Npn \__keythms_thm_new_unnumbered:nn #1#2 { \__keythms_thm_new:w* { #1 } { #2 } } \cs_generate_variant:Nn \__keythms_thm_new_unnumbered:nn { nV } \cs_new_protected:Npn \__keythms_thm_new_parent:nnn #1#2#3 { % for \renewkeytheorem need to know parent key if set \tl_gclear_new:c { g__keythms_thm_#1_parent_tl } \tl_gset:cn { g__keythms_thm_#1_parent_tl } { #3 } \__keythms_thm_new:w { #1 } { #2 } [ #3 ] } \cs_generate_variant:Nn \__keythms_thm_new_parent:nnn { nVV } \cs_new_protected:Npn \__keythms_thm_new_sibling:nnn #1#2#3 { \__keythms_thm_new:w { #1 } [ #3 ] { #2 } } \cs_generate_variant:Nn \__keythms_thm_new_sibling:nnn { nV } \cs_new_protected:Npn \__keythms_thm_new_uuwithparent:nnn #1#2#3 { \cs_undefine:c { keythms_orig_nonumber_#1 } % for renew, declare \__keythms_thm_new_unnumbered:nn { keythms_orig_nonumber_#1 } { #2 } \__keythms_thm_new_parent:nnn { #1 } { #2 } { #3 } \DeclareEnvironmentCopy { keythms_orig_withparent_#1 } { #1 } \renewenvironment { #1 } % opt arg is implicit { \setuniqmark{ #1. \use:c {the #3} } \ifuniq{ #1. \use:c {the #3} } { \keythms_if_restating:F { \refstepcounter{ keythms_unnumbered_dummyctr } } \IfPackageLoadedT { tcolorbox } { \tcbset{keythms_tcb_#1/.append~style=nophantom} } % ^ otherwise we try to set two identical anchors \begin{keythms_orig_nonumber_#1} } { \begin{keythms_orig_withparent_#1} } } { \ifuniq{ #1. \use:c {the #3} } { \end{keythms_orig_nonumber_#1} } { \end{keythms_orig_withparent_#1} } } } \cs_generate_variant:Nn \__keythms_thm_new_uuwithparent:nnn { nVV } % for getting notes with continues*, use nameref if available, otherwise ltproperties \hook_gput_code:nnn { begindocument } { . } { \IfPackageLoadedTF { nameref } { \cs_new:Npn \__keythms_thmuse_recordnote: { } % nameref takes care of this \cs_new:Npn \__keythms_getrecordednote:n #1 { \getrefbykeydefault{ #1 }{ name }{ } } } { \property_new:nnnn { keytheorems/recordednote } { now } { } { \l__keythms_thmuse_note_tl } \cs_new:Npn \__keythms_thmuse_recordnote: { \tl_if_empty:NF \l__keythms_thmuse_note_tl { \RecordProperties { keythms_recordednote_\l__keythms_thmuse_label_tl } { keytheorems/recordednote } } } \cs_new:Npn \__keythms_getrecordednote:n #1 { \property_ref:nn { keythms_recordednote_#1 } { keytheorems/recordednote } } } } \keys_define:nn { keytheorems/thmuse } { continues .tl_set:N = \l__keythms_thmuse_contlabel_tl, continues* .code:n = { \keys_set:nn { keytheorems/thmuse } { continues = #1 } \protected@edef \l__keythms_tmpa_tl { \__keythms_getrecordednote:n{#1} } \tl_if_empty:NF \l__keythms_tmpa_tl { \keys_set:nn { keytheorems/thmuse } { note = \l__keythms_tmpa_tl } } }, label .tl_set:N = \l__keythms_thmuse_label_tl, listhack .choice:, % needs equals sign listhack / true .code:n = \bool_set_true:N \l__keythms_thmuse_listhack_bool, listhack / false .code:n = \bool_set_false:N \l__keythms_thmuse_listhack_bool, listhack .initial:n = false, name .meta:n = { note = {#1} }, % ^ for compatibility. "name" is ambiguous and doesn't match amsthm language note .tl_set:N = \l__keythms_thmuse_note_tl, note .initial:n = {}, restate .meta:n = { store = {#1} }, % thmtools compatibility restate* .meta:n = { store* = {#1} }, restate-keys .clist_set:N = \l__keythms_thmuse_restatekeys_clist, seq .code:n = {}, short-note .code:n = {}, % these do nothing at point of use short-name .code:n = {}, store .tl_set:N = \l__keythms_thmuse_store_tl, % should this be .tl_set_e:N ? store* .tl_set:N = \l__keythms_thmuse_storereversed_tl, } \cs_new_protected:Npn \keythms_keyify_theorem:n #1 { % #1 = theorem name \DeclareEnvironmentCopy { keythms_orig_#1 } { #1 } \DeclareDocumentEnvironment { keythms_grab_#1 } { m m +b } { % ##1 = keys, ##2 = note, ##3 = theorem body \__keythms_thm_prehead_code:n { #1 } \begin{keythms_orig_#1}[{##2}] \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 } { ##3 } \__keythms_thm_tempstorerestatedata:nnn { #1 } { ##1 } { ##3 } ##3 \__keythms_thm_prefoot_code:n { #1 } \end{keythms_orig_#1} \__keythms_thm_postfoot_code:n { #1 } } {} \DeclareDocumentEnvironment { keythms_grabreversed_#1 } { m m +b } { % ##1 = keys, ##2 = note, ##3 = 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 } \begin{keythms_orig_#1}[{##2}] \__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 } { ##3 } \__keythms_thm_tempstorerestatedatareversed:nnn { #1 } { ##1 } { ##3 } ##3 \__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 } { ={note} O{} } { \tl_set:Nn \l_keythms_thmuse_envname_tl { #1 } \keys_set:nn { keytheorems/thmuse } { ##1 } \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 \cs_set_eq:NN \__keythms_withhooks_begin:nnn \__keythms_grabreversed_begin:nnn \cs_set_eq:NN \__keythms_withhooks_end:n \__keythms_grabreversed_end:n } } { \bool_gset_true:N \g__keythms_listof_writefile_bool \cs_set_eq:NN \__keythms_withhooks_begin:nnn \__keythms_grab_begin:nnn \cs_set_eq:NN \__keythms_withhooks_end:n \__keythms_grab_end:n } \__keythms_withhooks_begin:nnV { #1 } { ##1 } \l__keythms_thmuse_note_tl } { \__keythms_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:Npn \__keythms_use_iii_v_braced:nnnnn #1#2#3#4#5 { {#3}{#5} } % withhooks_begin does not include prehead hook because we want to be able to access note \cs_new_protected:Npn \__keythms_withhooks_begin:nnn #1#2#3 { % #1 = theorem name, #2 = keys, #3 = note \begin{keythms_orig_#1}[{#3}] \__keythms_thm_posthead_code:n { #1 } \__keythms_thm_addcontentsdata:nnnn { #1 } { } { #2 } { } \ignorespaces % I hope this is alright } \cs_generate_variant:Nn \__keythms_withhooks_begin:nnn { nnV } \cs_new_protected:Npn \__keythms_withhooks_end:n #1 { \__keythms_thm_prefoot_code:n { #1 } \end{keythms_orig_#1} \__keythms_thm_postfoot_code:n { #1 } } \cs_new_protected:Npn \__keythms_grab_begin:nnn #1#2#3 { % #1 = theorem name, #2 = keys, #3 = note \begin{keythms_grab_#1}{#2}{#3} } \cs_generate_variant:Nn \__keythms_grab_begin:nnn { nnV } \cs_new_protected:Npn \__keythms_grab_end:n #1 { \end{keythms_grab_#1} } \cs_new_protected:Npn \__keythms_grabreversed_begin:nnn #1#2#3 { % #1 = theorem name, #2 = keys, #3 = note \begin{keythms_grabreversed_#1}{#2}{#3} } \cs_generate_variant:Nn \__keythms_grabreversed_begin:nnn { nnV } \cs_new_protected:Npn \__keythms_grabreversed_end:n #1 { \end{keythms_grabreversed_#1} } \cs_new_protected:Npn \__keythms_orig_begin:nn #1#2 { \begin{keythms_orig_#1}[{#2}] } \cs_generate_variant:Nn \__keythms_orig_begin:nn { nV } \cs_new_protected:Npn \__keythms_orig_end:n #1 { \end{keythms_orig_#1} } %% this below has to be separate from withhooks_begin above since we need to add %% continues-code to note before retrieving it in \__keythms_withhooks_begin:nnV \cs_new_protected:Npn \__keythms_thm_prehead_code:n #1 { % #1 = theorem name \tl_if_empty:NF \l__keythms_thmuse_contlabel_tl { \tl_if_empty:NF \l__keythms_thmuse_note_tl { \tl_put_right:Nn \l__keythms_thmuse_note_tl { , ~ } } \tl_put_right:Ne \l__keythms_thmuse_note_tl { \__keythms_thmuse_continues:V \l__keythms_thmuse_contlabel_tl } \cs_set:cpn { the #1 } { \getrefnumber { \l__keythms_thmuse_contlabel_tl } } \cs_set_eq:cN { c@ #1 } \c@keythms_continues_dummyctr \cs_set_eq:cN { theH #1 } \theHkeythms_continues_dummyctr %\cs_set_eq:NN \setuniqmark \use_none:n % not the right fix } \hook_use:n { keytheorems/#1/prehead } \hook_use:n { keytheorems/allthms/prehead } % \use:c instead of \tl_use:c so doesn't error if tl doesn't exist \use:c { g__keythms_thm_#1_tcbprehead_tl } } \cs_new_protected:Npn \__keythms_thm_posthead_code:n #1 { % #1 = theorem name \hook_use:n { keytheorems/#1/posthead } \hook_use:n { keytheorems/allthms/posthead } \tl_if_empty:NF \l__keythms_thmuse_label_tl { \label{ \l__keythms_thmuse_label_tl } \__keythms_thmuse_recordnote: } \bool_if:NT \l__keythms_thmuse_listhack_bool { % straight from thm-amsthm.sty \leavevmode \vspace{-\baselineskip}% \par \everypar{\setbox\z@\lastbox\everypar{}}% } } \cs_new_protected:Npn \__keythms_thm_prefoot_code:n #1 { % #1 = theorem name \hook_use:n { keytheorems/allthms/prefoot } \hook_use:n { keytheorems/#1/prefoot } } \cs_new_protected:Npn \__keythms_thm_postfoot_code:n #1 { % #1 = theorem name \use:c { g__keythms_thm_#1_tcbpostfoot_tl } \hook_use:n { keytheorems/allthms/postfoot } \hook_use:n { keytheorems/#1/postfoot } } \cs_new_protected:Npn \__keythms_thm_addcontentsdata:nnnn #1#2#3#4 { % #1 = theorem name, #2 = stored counters, #3 = keys, #4 = body \keythms_listof_chaptervspacehack: \iow_shipout:Ne \@auxout { \token_to_str:N \@writefile { thlist } { \token_to_str:N \KeyThmsSavedTheorem{ #1 } { \@currentlabel } { \@currentHref } { \thepage } { #2 } { \exp_not:n { #3 } } % do we want any expansion here, perhaps { \exp_not:n { #4 } } % with \text_expand:n ? } } } \cs_new_protected:Npn \__keythms_thm_addstoredreverseddata:nnn #1#2#3 { % #1 = theorem name, #2 = keys, #3 = body \iow_shipout:Ne \@auxout { \token_to_str:N \@writefile { thlist } { \token_to_str:N \KeyThmsSavedTheoremReversed { \l__keythms_thmuse_storereversed_tl } { #1 } { \exp_not:n { #2 } } { \exp_not:n { #3 } } } } } \cs_new_protected:Npn \__keythms_thm_tempstorerestatedata:nnn #1#2#3 { % #1 = theorem name, #2 = keys, #3 = body \tl_gset:Ne \g__keythms_thmuse_temprestatedata_tl % needs to be global to get out of env { { #1 } { \@currentlabel } { \prop_to_keyval:N \g__keythms_thmuse_othercounters_prop } { \exp_not:n { #2 } } % do we want any expansion here, perhaps { \exp_not:n { #3 } } % with \text_expand:n ? } } \cs_new_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 } { \exp_not:n { #2 } } { \exp_not:n { #3 } } } } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Retrieving Theorem Data %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \cs_new_protected:Npn \KeyThmsSavedTheorem #1#2#3#4#5#6#7 % 7th arg is body { \use:c { __keythms_thmitem_#1:nnnnnn } {#2}{#3}{#4}{#5}{#6}{#7} } \cs_new_protected:Npn \KeyThmsSavedTheoremReversed #1#2#3#4 { } % gobble by default \keys_define:nn { keytheorems/storeatbegin } { restate .meta:n = { store = {#1} }, restate* .meta:n = { store* = {#1} }, store .tl_set:N = \l__keythms_storeatbegin_store_tl, store* .tl_set:N = \l__keythms_storeatbegin_storereversed_tl, unknown .code:n = { } % do nothing with unknown keys } \cs_new_protected:Npn \KeyThmsContentsLine #1 { } % ^ initially a no-op, redefined where needed; important it's protected! \NewDocumentCommand \addtheoremcontentsline { m +m } { \addtocontents { thlist } { \KeyThmsContentsLine { % copied from def of \addcontentsline \protect\contentsline{#1}{#2}{\thepage}{} \protected@file@percent } } } \NewDocumentCommand \addtotheoremcontents { +m } { \addtocontents { thlist } { \KeyThmsContentsLine { #1 } } } \hook_gput_code:nnn { begindocument } { . } { \group_begin: \cs_set_protected:Npn \KeyThmsSavedTheorem #1#2#3#4#5#6#7 { \group_begin: \keys_set:nn { keytheorems/storeatbegin } { #6 } \tl_if_empty:NF \l__keythms_storeatbegin_store_tl { \cs_new_protected:cpn { __keythms_getthm_ \l__keythms_storeatbegin_store_tl _theorem } { \__keythms_getthm_theorem:nnnnn {#1}{#2}{#5}{#6}{#7} } \cs_new_protected:cpn { __keythms_getthm_ \l__keythms_storeatbegin_store_tl _body } { \__keythms_getthm_body:nn {#5}{#7} } } \tl_if_empty:NF \l__keythms_storeatbegin_storereversed_tl { \tl_const:cn { c__keythms_storeatbegin_ \l__keythms_storeatbegin_storereversed_tl _label_tl } { #2 } \tl_const:cn { c__keythms_storeatbegin_ \l__keythms_storeatbegin_storereversed_tl _restatecounters_tl } { #5 } \cs_new_protected:cpn { __keythms_getthm_ \l__keythms_storeatbegin_storereversed_tl _body } { \__keythms_getthm_body:nn {#5}{#7} } } \group_end: } \cs_set_protected:Npn \KeyThmsSavedTheoremReversed #1#2#3#4 { \bool_new:c { g__keythms_restate_#1_called_bool } \cs_gset:cpn { __keythms_getthm_#1_theorem } { \__keythms_getthmreversed_theorem:nnn { #2 } { #3 } { #4 } } \hook_gput_code:nnn { begindocument/end } { . } { \cs_if_exist:cF { __keythms_getthm_#1_body } { \cs_new_protected:cpn { __keythms_getthm_#1_body } { \textbf{??} \msg_warning:nnn { keytheorems } { restate-body-never-got } { #1 } } } } } \file_if_exist_input:n { \c_sys_jobname_str.thlist } \group_end: } \prg_new_conditional:Npnn \keythms_if_restating: { T, F, TF } { \bool_if:NTF \l__keythms_thmuse_restating_bool { \prg_return_true: } { \prg_return_false: } } \NewDocumentCommand \IfRestatingTF { } { \keythms_if_restating:TF } \NewDocumentCommand \IfRestatingT { } { \keythms_if_restating:T } \NewDocumentCommand \IfRestatingF { } { \keythms_if_restating:F } \hook_gput_code:nnn { keytheorems/allthms/restated } { . } { % code to disable things in restated theorems \renewcommand\label[2][]{} % opt arg in case cleveref loaded \cs_set_eq:NN \ltx@label \use_none:n % thmtools does this; why? \cs_set_eq:NN \property_record:nn \use_none:nn \cs_set_eq:NN \setuniqmark \use_none:n % work with numbered=unless-unique % QUESTION: also disable \hyper@@anchor? \MakeLinkTarget? } \cs_new_protected:Npn \__keythms_getthm_theorem:nnnnn #1#2#3#4#5 { % #1 = name, #2 = number, #3 = restate counters, #4 = keys, #5 = theorem body \group_begin: \bool_set_true:N \l__keythms_thmuse_restating_bool \prop_set_from_keyval:Nn \l__keythms_restate_counters_prop { #3 } \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:nTF { #2 } { \refstepcounter{keythms_restate_dummyctr} } % for unnumbered theorems { \cs_set:cpn { the #1 } { #2 } \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 } \tl_set:Nn \l_keythms_thmuse_envname_tl { #1 } \keys_set:nn { keytheorems/thmuse } { #4 } \keys_set:no { keytheorems/thmuse } { \l__keythms_thmuse_restatekeys_clist } \__keythms_thm_prehead_code:n { #1 } \hook_use:n { keytheorems/#1/restated } \hook_use:n { keytheorems/allthms/restated } \__keythms_orig_begin:nV { #1 } \l__keythms_thmuse_note_tl \__keythms_thm_posthead_code:n { #1 } #5 \__keythms_thm_prefoot_code:n { #1 } \__keythms_orig_end:n { #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 } } \group_end: } \cs_new_protected:Npn \__keythms_getthm_body:nn #1#2 { % #1 = restate counters, #2 = theorem body \group_begin: \bool_set_true:N \l__keythms_thmuse_restating_bool \prop_set_from_keyval:Nn \l__keythms_restate_counters_prop { #1 } \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 } } \refstepcounter{keythms_restate_dummyctr} % \hook_use:n { keytheorems/#1/restated } % FIX! \hook_use:n { keytheorems/allthms/restated } #2 \prop_map_inline:Nn \l__keythms_restate_counters_prop { \exp_args:Nnc \setcounter { ##1 } { l_keythms_restate_current_##1_tl } } \group_end: } \cs_new_protected:Npn \__keythms_getthmreversed_theorem:nnn #1#2#3 { % #1 = envname, #2 = keys, #3 = theorem body \group_begin: \bool_set_false:N \l__keythms_thmuse_restating_bool \tl_set:Nn \l_keythms_thmuse_envname_tl { #1 } \keys_set:nn { keytheorems/thmuse } { #2 } \keys_set:no { keytheorems/thmuse } { \l__keythms_thmuse_restatekeys_clist } \__keythms_thm_prehead_code:n { #1 } \__keythms_orig_begin:nV { #1 } \l__keythms_thmuse_note_tl \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 } \__keythms_thm_addcontentsdata:nnnn { #1 } { \prop_to_keyval:N \g__keythms_thmuse_othercounters_prop } { #2 } { #3 } \__keythms_thm_tempstorerestatedata:nnn { #1 } { #2 } { #3 } % for defining getthm_body #3 \__keythms_thm_prefoot_code:n { #1 } \__keythms_orig_end:n { #1 } \__keythms_thm_postfoot_code:n { #1 } % While we're here, define getthm_body \cs_if_exist:cF { __keythms_getthm_ \l__keythms_thmuse_storereversed_tl _body } { \cs_new:cpe { __keythms_getthm_ \l__keythms_thmuse_storereversed_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 } } } \bool_gset_true:c { g__keythms_restate_ \l__keythms_thmuse_storereversed_tl _called_bool } \group_end: } \NewDocumentCommand \getkeytheorem { O{theorem} m } { % #1 = property, #2 = tag \cs_if_exist:cTF { __keythms_getthm_#2_#1 } { \bool_if_exist:cTF { g__keythms_restate_#2_called_bool } { \str_if_eq:nnTF { #1 } { theorem } { \bool_if:cTF { g__keythms_restate_#2_called_bool } { \msg_error:nnn { keytheorems } { store-reversed-called-twice } { #2 } } { \use:c { __keythms_getthm_#2_#1 } } } { \use:c { __keythms_getthm_#2_#1 } } } { \use:c { __keythms_getthm_#2_#1 } } } { \textbf{??} \cs_if_exist:cTF { __keythms_getthm_#2_theorem } { \msg_warning:nnnn { keytheorems } { no-prop-for-stored-theorem } { #1 } { #2 } % should this be an error? } { \msg_warning:nnn { keytheorems } { no-stored-theorem } { #2 } } } } %%%%%%%%%%%%%%%%%%%%% %%% Theorem Hooks %%% %%%%%%%%%%%%%%%%%%%%% \NewDocumentCommand \addtotheoremhook { O{allthms} m +m } { % #1 = envname, #2 = hook, #3 = code \__hook_if_declared:nTF { keytheorems/allthms/#2 } { \hook_gput_code:nnn { keytheorems/#1/#2 } { . } { #3 } } { \msg_error:nnn { keytheorems } { undefined-thm-hook } { #2 } } } % NOTE: I think it's OK we use the internal \__hook_if_declared:nTF above % since we don't need to worry about the user creating new theorem hooks % so, as we're only checking the existence of hooks created by us, it's OK. %%%%%%%%%%%%%%%%%%%%%%%% %%% List of Theorems %%% %%%%%%%%%%%%%%%%%%%%%%%% \keys_define:nn { keytheorems/listof } { chapter-skip-length .dim_set:N = \keythms@listof@chaptervspace@dim, chapter-skip-length .initial:n = 10pt, format-code .cs_set:Np = \__keythms_listof_misdirect:nnn #1#2#3, format-code .initial:n = \numberline{#2}#1#3, ignore .code:n = { \hook_gput_code:nnn { begindocument/before } { keytheorems } { \keythms_listof_ignore:n { #1 } } }, ignoreall .code:n = { % in case called before theorem defined \hook_gput_code:nnn { begindocument/before } { keytheorems } { \prop_map_inline:Nn \g__keythms_thmnames_prop { \__keythms_listof_ignore_aux:n { ##1 } } } }, indent .dim_set:N = \l__keythms_listof_indent_dim, indent .initial:n = 1.5em, no-chapter-skip .bool_set:N = \l__keythms_listof_nochapskip_bool, no-chapter-skip .initial:n = false, no-continues .bool_set:N = \l__keythms_listof_nocont_bool, no-continues .initial:n = false, no-title .bool_set:N = \l__keythms_listof_notitle_bool, no-title .initial:n = false, no-toc .bool_set:N = \l__keythms_listof_notoc_bool, no-toc .initial:n = false, % false does not mean "to-toc" for standard classes note-code .cs_set:Np = \__keythms_listof_notecmd:n #1, note-code .initial:n = { ~ (#1) }, numwidth .dim_set:N = \l__keythms_listof_numwidth_dim, numwidth .initial:n = 2.3em, onlynamed .code:n = { \hook_gput_code:nnn { begindocument/before } { keytheorems } { \keythms_listof_onlynamed:n { #1 } } }, onlynamed .default:n = \q_no_value, onlynumbered .code:n = { \hook_gput_code:nnn { begindocument/before } { keytheorems } { \keythms_listof_onlynumbered:n { #1 } } }, onlynumbered .default:n = \q_no_value, print-body .code:n = { \cs_set_protected:Nn \keythms_listof_listcmd:nnnnnnn { \tl_if_empty:nF { ##7 } { \__keythms_getthm_theorem:nnnnn {##1}{##2}{##5}{##6}{##7} } } }, seq .code:n = { \hook_gput_code:nnn { begindocument/before } { keytheorems } { \keythms_listof_showseq:n { #1 } } }, show .code:n = { \hook_gput_code:nnn { begindocument/before } { keytheorems } { \keythms_listof_show:n { #1 } } }, showall .code:n = { % in case called before theorem defined \hook_gput_code:nnn { begindocument/before } { keytheorems } { \prop_map_inline:Nn \g__keythms_thmnames_prop { \__keythms_listof_show_aux:n { ##1 } } } }, swapnumber .bool_set:N = \l__keythms_listof_swapnumber_bool, swapnumber .initial:n = false, title .tl_set:N = \l__keythms_listof_title_tl, title .initial:n = \GetTranslation{keythms_listof_title}, title-code .cs_set:Np = \__keythms_listof_titlecmd:n #1, } \hook_gput_code:nnn { begindocument } { . } { % redefine these keys at begindocument \keys_define:nn { keytheorems/listof } { ignore .code:n = \keythms_listof_ignore:n { #1 }, ignoreall .code:n = { \prop_map_inline:Nn \g__keythms_thmnames_prop { \__keythms_listof_ignore_aux:n { ##1 } } }, onlynamed .code:n = \keythms_listof_onlynamed:n { #1 }, onlynamed .default:n = \q_no_value, onlynumbered .code:n = \keythms_listof_onlynumbered:n { #1 }, onlynumbered .default:n = \q_no_value, seq .code:n = \keythms_listof_showseq:n { #1 }, show .code:n = \keythms_listof_show:n { #1 }, showall .code:n = { \prop_map_inline:Nn \g__keythms_thmnames_prop { \__keythms_listof_show_aux:n { ##1 } } }, } } \NewDocumentCommand \keytheoremlistset { +m } { \keys_set:nn { keytheorems/listof } { #1 } } \cs_new_protected:Npn \keythms_listof_ignore:n #1 { \clist_map_inline:nn { #1 } { \__keythms_listof_ignore_aux:n { ##1 } } } \cs_new_protected:Npn \__keythms_listof_ignore_aux:n #1 { \cs_set_protected:cpn { __keythms_thmitem_#1:nnnnnn } ##1##2##3##4##5##6 { } } \cs_new_protected:Npn \keythms_listof_show:n #1 { \clist_map_inline:nn { #1 } { \__keythms_listof_show_aux:n { ##1 } } } \cs_new_protected:Npn \__keythms_listof_show_aux:n #1 { \cs_set_protected:cpn { __keythms_thmitem_#1:nnnnnn } ##1##2##3##4##5##6 { \__keythms_listof_listcmd_setup:nn { ##5 } { \keythms_listof_listcmd:nnnnnnn {#1}{##1}{##2}{##3}{##4}{##5}{##6} } } } \cs_new_protected:Npn \keythms_listof_onlynamed:n #1 { \quark_if_no_value:nTF { #1 } { \prop_map_inline:Nn \g__keythms_thmnames_prop { \__keythms_listof_onlynamed_aux:n { ##1 } } } { \clist_map_inline:nn { #1 } { \__keythms_listof_onlynamed_aux:n { ##1 } } } } \cs_new_protected:Npn \__keythms_listof_onlynamed_aux:n #1 { \cs_set_protected:cpn { __keythms_thmitem_#1:nnnnnn } ##1##2##3##4##5##6 { \__keythms_listof_listcmd_setup:nn { ##5 } { \tl_if_empty:NF \l__keythms_listofheading_note_tl { \keythms_listof_listcmd:nnnnnnn {#1}{##1}{##2}{##3}{##4}{##5}{##6} } } } } \cs_new_protected:Npn \keythms_listof_onlynumbered:n #1 { \quark_if_no_value:nTF { #1 } { \prop_map_inline:Nn \g__keythms_thmnames_prop { \__keythms_listof_onlynumbered_aux:n { ##1 } } } { \clist_map_inline:nn { #1 } { \__keythms_listof_onlynumbered_aux:n { ##1 } } } } \cs_new_protected:Npn \__keythms_listof_onlynumbered_aux:n #1 { \cs_set_protected:cpn { __keythms_thmitem_#1:nnnnnn } ##1##2##3##4##5##6 { \__keythms_listof_listcmd_setup:nn { ##5 } { \tl_if_empty:nF { ##1 } { \keythms_listof_listcmd:nnnnnnn {#1}{##1}{##2}{##3}{##4}{##5}{##6} } } } } \cs_new_protected:Npn \keythms_listof_showseq:n #1 { \prop_map_inline:Nn \g__keythms_thmnames_prop { \__keythms_listof_showseq_aux:nn { #1 } { ##1 } } } \cs_new_protected:Npn \__keythms_listof_showseq_aux:nn #1#2 { % #1 = seq name, #2 = theorem name \cs_set_protected:cpn { __keythms_thmitem_#2:nnnnnn } ##1##2##3##4##5##6 { \__keythms_listof_listcmd_setup:nn { ##5 } { \tl_if_eq:NnT \l__keythms_listofheading_seq_tl { #1 } { \keythms_listof_listcmd:nnnnnnn {#2}{##1}{##2}{##3}{##4}{##5}{##6} } } } } % Seems unnecessary to repeat all this for reading the keyvals from file. % In thmtools they just hook the "thmitem" definition into the theorem declaration. %% NOTE ON ABOVE: this gives more flexibility to define different kinds of lists. %% See acro.sty for template idea. \keys_define:nn { keytheorems/listofheading } { continues .tl_set:N = \l__keythms_listofheading_contlabel_tl, continues* .code:n = { \keys_set:nn { keytheorems/listofheading } { continues = #1 } \protected@edef \l__keythms_tmpa_tl { \__keythms_getrecordednote:n{#1} } \tl_if_empty:NF \l__keythms_tmpa_tl { \keys_set:nn { keytheorems/listofheading } { note = \l__keythms_tmpa_tl } } }, name .meta:n = { note = {#1} }, note .tl_set:N = \l__keythms_listofheading_note_tl, restate* .meta:n = { store* = {#1} }, restate-keys .clist_set:N = \l__keythms_listofheading_restatekeys_clist, seq .tl_set:N = \l__keythms_listofheading_seq_tl, short-note .tl_set:N = \l__keythms_listofheading_shortnote_tl, short-name .meta:n = { short-note = {#1} }, store* .code:n = { \bool_set_true:N \l__keythms_listofheading_storereversed_bool }, unknown .code:n = { } % do nothing with unknown keys } \cs_new:Npn \__keythms_listof_printnote: { \tl_if_empty:NTF \l__keythms_listofheading_shortnote_tl { \tl_if_empty:NF \l__keythms_listofheading_note_tl { \__keythms_listof_notecmd:n { \l__keythms_listofheading_note_tl } } } { \__keythms_listof_notecmd:n { \l__keythms_listofheading_shortnote_tl } } } \cs_new:Npn \keythms_listof_listcmd:nnnnnnn #1#2#3#4#5#6#7 { % #1=name, #2=number, #3=Href, #4=page, #5=restate counters, #6=keys, #7=body \contentsline{ #1 } { \__keythms_listof_misdirect:nnn { \prop_item:Nn \g__keythms_thmnames_prop { #1 } } { #2 } { \__keythms_listof_printnote: } } { #4 }{ #3 } } \NewDocumentCommand \__keythms_listof_pagerefnolink:w { s m } { \getpagerefnumber{#2} } % tagging does not like links within link % NOTE: We still need to do this setup for [print-body] so that onlynamed works \cs_new_protected:Npn \__keythms_listof_listcmd_setup:nn #1#2 { % #1 = keys, #2 = list command \group_begin: \keys_set:nn { keytheorems/listofheading } { #1 } \bool_if:NT \l__keythms_listofheading_storereversed_bool { \keys_set:no { keytheorems/listofheading } { \l__keythms_listofheading_restatekeys_clist } } \tl_if_empty:NTF \l__keythms_listofheading_contlabel_tl { #2 } { \bool_if:NF \l__keythms_listof_nocont_bool { \tl_if_empty:NF \l__keythms_listofheading_note_tl { \tl_put_right:Nn \l__keythms_listofheading_note_tl { , ~ } } \tl_put_right:Nn \l__keythms_listofheading_note_tl { \__keythms_thmuse_continues:V \l__keythms_listofheading_contlabel_tl } \cs_set_eq:NN \pageref \__keythms_listof_pagerefnolink:w % always no link #2 } } \group_end: } \cs_if_exist:NTF \chapter { \cs_set_protected:Npn \__keythms_listof_titlecmd:n #1 { \chapter*{#1} } } { \cs_set_protected:Npn \__keythms_listof_titlecmd:n #1 { \section*{#1} } } \cs_new_protected:Npn \__keythms_listof_default_tocline: { \@dottedtocline{ 1 }{ \l__keythms_listof_indent_dim } { \l__keythms_listof_numwidth_dim } } \cs_new_eq:NN \keythms_listof_tocline: \__keythms_listof_default_tocline: \NewDocumentCommand \listofkeytheorems { +O{} } { \bool_gset_true:N \g__keythms_listof_writefile_bool \group_begin: \keys_set:nn { keytheorems/listof } { #1 } \cs_set_protected:Npn \KeyThmsContentsLine ##1 { ##1 } \bool_if:NF \l__keythms_listof_nochapskip_bool { \cs_set_protected:Npn \KeyThmsAddvspace { \addvspace } } \bool_if:NF \l__keythms_listof_notitle_bool { \__keythms_listof_titlecmd:n { \l__keythms_listof_title_tl } \@mkboth % QUESTION: should this go in titlecmd ? { \MakeUppercase \l__keythms_listof_title_tl } { \MakeUppercase \l__keythms_listof_title_tl } } \bool_if:NT \l__keythms_listof_swapnumber_bool { \cs_set:Npn \__keythms_listof_misdirect:nnn ##1##2##3 { ##1 ~ ##2##3 } } \legacy_if_set_false:n { @filesw } \@starttoc{ thlist } \group_end: } % ^ unlike thmtools we don't use the class's style of \listoffigures because % we want control over title-code, no-title, etc. But this means we have to guess % things like marks, sectioning command, etc. \hook_gput_code:nnn { enddocument } { . } { \bool_if:NTF \g__keythms_listof_writefile_bool { \legacy_if:nT { @filesw } { \iow_new:N \tf@thlist \iow_open:Nn \tf@thlist { \c_sys_jobname_str.thlist } } } { % if .thlist file left over from previous run but not needed, clear it \file_if_exist:nT { \c_sys_jobname_str.thlist } { \iow_open:Nn \g__keythms_tmpa_iow { \c_sys_jobname_str.thlist } \iow_close:N \g__keythms_tmpa_iow } } } % chaptervspacehack (code translated from thmtools) \cs_new_protected:Npn \KeyThmsAddvspace #1 { } % initially no-op, redefined where needed \int_new:N \g_keythms_listof_prevchapter_int \int_gset:Nn \g_keythms_listof_prevchapter_int { 1 } % ^ if this is zero, bad things happen if title-code is changed; % anyways don't need addvspace at top \cs_new_protected:Npn \keythms_listof_chaptervspacehack: { } \cs_if_exist:cT { c@chapter } { \cs_set_protected:Npn \keythms_listof_chaptervspacehack: { \int_compare:nNnF { \value{chapter} } = { \g_keythms_listof_prevchapter_int } { \addtocontents{ thlist } { \KeyThmsAddvspace { \keythms@listof@chaptervspace@dim } } \int_gset:Nn \g_keythms_listof_prevchapter_int { \value{chapter} } } } } %%%%%%%%%%%%%%%% %%% \Autoref %%% %%%%%%%%%%%%%%%% \ProvideDocumentCommand { \Autoref } { s m } { \IfPackageLoadedTF { hyperref } { \group_begin: \cs_set_eq:NN \HyRef@testreftype \__keythms_Autoref_testreftype:w \IfBooleanTF { #1 } { \autoref*{#2} } { \autoref{#2} } \group_end: } { \msg_error:nn { keytheorems } { hyperref-Autoref } } } \cs_new_protected:Npn \__keythms_Autoref_testreftype:w #1.#2\\ { \cs_if_exist:cTF { #1 Autorefname } { \cs_set:Npe \HyRef@currentHtag { \exp_not:N \use:c { #1 Autorefname } \exp_not:N \c_space_token } } { \msg_warning:nnn { keytheorems } { no-Autorefname } { #1 } } } %%%%%%%%%%%%%%%%%%% %%% Global Keys %%% %%%%%%%%%%%%%%%%%%% \keys_define:nn { keytheorems } { auto-translate .bool_gset:N = \g__keythms_autotranslate_bool, auto-translate .initial:n = true, continues-code .cs_set:Np = \__keythms_thmuse_continues:n #1, continues-code .initial:n = { % not sure how best to handle this translation \GetTranslation{keythms_continues}\pageref{#1} }, overload .code:n = \__keythms_overload_code:, overload .value_forbidden:n = true, overload .usage:n = preamble, qed-symbol .cs_set_protected:Np = \qedsymbol, restate-counters .code:n = { \clist_map_inline:nn { #1 } { \tl_new:c { l_keythms_restate_current_##1_tl } } \clist_gput_right:Nn \g__keythms_restatecounters_clist { #1 } }, restate-counters .initial:n = equation, store-all .code:n = \__keythms_storeall_code:, store-all .value_forbidden:n = true, store-all .usage:n = preamble, store-sets-label .code:n = { \keys_define:nn { keytheorems/thmuse } { store .code:n = { \tl_set:Nn \l__keythms_thmuse_label_tl { ##1 } \tl_set:Nn \l__keythms_thmuse_store_tl { ##1 } }, store* .code:n = { \tl_set:Nn \l__keythms_thmuse_label_tl { ##1 } \tl_set:Nn \l__keythms_thmuse_storereversed_tl { ##1 } }, } }, thmtools-compat .code:n = { % prevent loading the code again if key called twice \bool_if:NF \g__keythms_thmtoolscompat_bool { \__keythms_thmtoolscompat_code: } }, thmtools-compat .value_forbidden:n = true, thmtools-compat .usage:n = preamble, } \cs_generate_variant:Nn \__keythms_thmuse_continues:n { V } \NewDocumentCommand \keytheoremset { +m } { % #1 = keys \keys_set:nn { keytheorems } { #1 } } \cs_new_protected:Npn \__keythms_overload_code: { \RenewDocumentCommand { \newtheorem } { s m o m o } { \IfBooleanTF { ##1 } { \keythms_thm_newkeythm:nn { ##2 } { name=##4, numbered=no } } { \IfNoValueTF { ##3 } { \IfNoValueTF { ##5 } { \keythms_thm_newkeythm:nn { ##2 } { name=##4 } } { \keythms_thm_newkeythm:nn { ##2 } { name=##4, parent=##5 } } } { \keythms_thm_newkeythm:nn { ##2 } { name=##4, sibling=##3 } } } } } \cs_new_protected:Npn \__keythms_thmtoolscompat_code: { \bool_gset_true:N \g__keythms_thmtoolscompat_bool \__keythms_overload_code: % since thmtools overwrites \newtheorem \ProvideDocumentCommand { \declaretheoremstyle } { +O{} m } { \declarekeytheoremstyle { ##2 } { ##1 } } \ProvideDocumentCommand { \declaretheorem } { +O{} m } { \newkeytheorem { ##2 } [ ##1 ] } \ProvideDocumentEnvironment { restatable } { O{} m m } { % need to redefine this to add store to thlist since we set it outside env \cs_set_protected:Npn \__keythms_thm_addcontentsdata:nnnn ####1####2####3####4 { % ####1 = theorem name, ####2 = stored counters, ####3 = keys, ####4 = body \keythms_listof_chaptervspacehack: \iow_shipout:Ne \@auxout { \token_to_str:N \@writefile { thlist } { \token_to_str:N \KeyThmsSavedTheorem{ ####1 } { \@currentlabel } { \@currentHref } { \thepage } { ####2 } { store=\l__keythms_thmuse_store_tl,\exp_not:n { ####3 } } % this line is changed { \exp_not:n { ####4 } } } } } % set store outside [] so keyless note is recognized \keys_set:nn { keytheorems/thmuse } { store=##3 } \begin{##2}[##1] } { \end{##2} \cs_new_protected:cpn { ##3 } { % make \foo and \foo* identical \peek_meaning_remove:NTF * { \getkeytheorem{ ##3 } } { \getkeytheorem{ ##3 } } } } \ProvideDocumentEnvironment { restatable* } { O{} m m } { % need to redefine this to add store* to thlist since we set it outside env \cs_set_protected:Npn \__keythms_thm_addstoredreverseddata:nnn ####1####2####3 { % ####1 = theorem name, ####2 = keys, ####3 = body \iow_shipout:Ne \@auxout { \token_to_str:N \@writefile { thlist } { \token_to_str:N \KeyThmsSavedTheoremReversed { \l__keythms_thmuse_storereversed_tl } { ####1 } { store*=\l__keythms_thmuse_storereversed_tl,\exp_not:n { ####2 } } % this line is changed { \exp_not:n { ####3 } } } } } % and this because otherwise adds an extra run; not needed for unstarred \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_new_protected:cpn { ##3 } { % make \foo and \foo* identical \peek_meaning_remove:NTF * { \getkeytheorem{ ##3 } } { \getkeytheorem{ ##3 } } } } \ProvideDocumentCommand { \listoftheorems } { } { \listofkeytheorems } \ProvideDocumentCommand { \listtheoremname } { } { \GetTranslation{keythms_listof_title} } \keys_define:nn { keytheorems/listof } { % redefine since thmtools way is \renewcommand\listtheoremname{...} title .initial:n = \listtheoremname } \ProvideDocumentCommand { \addtotheorempreheadhook } { O{allthms} +m } { \addtotheoremhook [ ##1 ] { prehead } { ##2 } } \ProvideDocumentCommand { \addtotheorempostheadhook } { O{allthms} +m } { \addtotheoremhook [ ##1 ] { posthead } { ##2 } } \ProvideDocumentCommand { \addtotheoremprefoothook } { O{allthms} +m } { \addtotheoremhook [ ##1 ] { prefoot } { ##2 } } \ProvideDocumentCommand { \addtotheorempostfoothook } { O{allthms} +m } { \addtotheoremhook [ ##1 ] { postfoot } { ##2 } } \clist_new:N \l__keythms_tcbshaded_keys_clist \clist_new:N \l__keythms_tcbthmbox_keys_clist \keys_define:nn { keytheorems/thm/shaded } { textwidth .code:n = \clist_put_right:Nn \l__keythms_tcbshaded_keys_clist { width=##1 }, bgcolor .code:n = \clist_put_right:Nn \l__keythms_tcbshaded_keys_clist { colback=##1 }, rulewidth .code:n = \clist_put_right:Nn \l__keythms_tcbshaded_keys_clist { boxrule=##1 }, rulecolor .code:n = \clist_put_right:Nn \l__keythms_tcbshaded_keys_clist { colframe=##1 }, margin .code:n = \clist_put_right:Nn \l__keythms_tcbshaded_keys_clist { boxsep=##1 }, padding .meta:n = { margin=##1 }, leftmargin .code:n = \clist_put_right:Nn \l__keythms_tcbshaded_keys_clist { left~skip=##1 }, rightmargin .code:n = \clist_put_right:Nn \l__keythms_tcbshaded_keys_clist { right~skip=##1 }, } \keys_define:nn { keytheorems/thm/thmbox } { L .code:n = { \clist_put_right:Nn \l__keythms_tcbthmbox_keys_clist { keythms_tcbthmbox_L } }, M .code:n = { \clist_put_right:Nn \l__keythms_tcbthmbox_keys_clist { keythms_tcbthmbox_M } }, S .code:n = { \clist_put_right:Nn \l__keythms_tcbthmbox_keys_clist { keythms_tcbthmbox_S } }, underline .choice:, underline / true .code:n = {}, underline / false .code:n = { \clist_put_right:Nn \l__keythms_tcbthmbox_keys_clist { boxed~title~style={bottomrule=0pt} } }, underline .default:n = true, nounderline .meta:n = { underline=false }, cut .choice:, cut / true .code:n = {}, cut / false .code:n = { \clist_put_right:Nn \l__keythms_tcbthmbox_keys_clist { unbreakable } }, cut .default:n = true, nocut .meta:n = { cut=false }, thickness .code:n = { % could also add keys to clist with changed dimens; which is better? \tl_gput_right:cn { g__keythms_thm_preheadfromkeys_ \l__keythms_thm_envname_tl _tl } { \dim_set:Nn \l_keythms_tcbthmbox_thickness_dim { ##1 } } }, leftmargin .code:n = { \tl_gput_right:cn { g__keythms_thm_preheadfromkeys_ \l__keythms_thm_envname_tl _tl } { \dim_set:Nn \l_keythms_tcbthmbox_leftmargin_dim { ##1 } } }, rightmargin .code:n = { \tl_gput_right:cn { g__keythms_thm_preheadfromkeys_ \l__keythms_thm_envname_tl _tl } { \dim_set:Nn \l_keythms_tcbthmbox_rightmargin_dim { ##1 } } }, hskip .code:n = { \tl_gput_right:cn { g__keythms_thm_preheadfromkeys_ \l__keythms_thm_envname_tl _tl } { \dim_set:Nn \l_keythms_tcbthmbox_hskip_dim { ##1 } } }, vskip .code:n = { \tl_gput_right:cn { g__keythms_thm_preheadfromkeys_ \l__keythms_thm_envname_tl _tl } { \dim_set:Nn \l_keythms_tcbthmbox_vskip_dim { ##1 } } }, } \dim_new:N \l_keythms_tcbthmbox_thickness_dim \dim_set:Nn \l_keythms_tcbthmbox_thickness_dim { 0.6pt } \dim_new:N \l_keythms_tcbthmbox_leftmargin_dim \dim_set:Nn \l_keythms_tcbthmbox_leftmargin_dim { 0.7\parindent } % use \parindent? thmbox does \dim_new:N \l_keythms_tcbthmbox_rightmargin_dim \dim_set:Nn \l_keythms_tcbthmbox_rightmargin_dim { 0pt } \dim_new:N \l_keythms_tcbthmbox_hskip_dim \dim_set:Nn \l_keythms_tcbthmbox_hskip_dim { 0.2em } \dim_new:N \l_keythms_tcbthmbox_vskip_dim \dim_set:Nn \l_keythms_tcbthmbox_vskip_dim { 0.2em } \msg_new:nnn { keytheorems } { mdframed-undefined } { keytheorems~does~not~define~the~'mdframed'~key.~ Consider~using~the~'tcolorbox'~key~instead. } \keys_define:nn { keytheorems/thm } { shaded .code:n = { \clist_clear:N \l__keythms_tcbshaded_keys_clist \keys_set:nn { keytheorems/thm/shaded } { ##1 } % FIX: surely a better way to do this \RequirePackage{tcolorbox} \pgfkeysifdefined{/tcb/keythms_tcbshaded_default/.@cmd} % even worth it? {} { \tcbset % wish I could do this outside of key but can't assume tcb loaded { keythms_tcbshaded_default/.style= { sharp~corners = all, boxrule = 0pt, left = 0pt, right = 0pt, top = 0pt, bottom = 0pt, parbox = false, } } } \keys_set:ne { keytheorems/thm } { tcolorbox-no-titlebar = { keythms_tcbshaded_default, \l__keythms_tcbshaded_keys_clist } } }, thmbox .code:n = % adapted from https://tex.stackexchange.com/a/236230/208544 { \clist_clear:N \l__keythms_tcbthmbox_keys_clist \keys_set:nn { keytheorems/thm/thmbox } { ##1 } % FIX: surely a better way to do this \RequirePackage{tcolorbox} \tcbuselibrary{skins,breakable} \pgfkeysifdefined{/tcb/keythms_tcbthmbox_default/.@cmd} % even worth it? {} { \tcbset{ keythms_tcbthmbox_default/.style={ enhanced, breakable, sharp~corners=all, right=\l_keythms_tcbthmbox_hskip_dim, left=\l_keythms_tcbthmbox_hskip_dim, top=\l_keythms_tcbthmbox_vskip_dim, bottom=\l_keythms_tcbthmbox_vskip_dim, coltitle=black, frame~engine=empty, interior~titled~engine=empty, interior~engine=empty, extras~broken={ frame~engine=empty, interior~titled~engine=empty, interior~engine=empty }, parbox=false, % even though frame isn't drawn, makes spacing correct boxrule=0.5\l_keythms_tcbthmbox_thickness_dim, attach~boxed~title~to~top~left={ xshift=-\l_keythms_tcbthmbox_leftmargin_dim, }, boxed~title~style={ empty, size=minimal, bottom=0.3ex, top=0ex, % ditto bottomrule=0.5\l_keythms_tcbthmbox_thickness_dim, }, left~skip=\l_keythms_tcbthmbox_leftmargin_dim, right~skip=\l_keythms_tcbthmbox_rightmargin_dim, overlay~unbroken={ \draw[line~width=\l_keythms_tcbthmbox_thickness_dim] (title.south~west) -- (title.south~east); \draw[line~width=\l_keythms_tcbthmbox_thickness_dim] (frame.north~west) |- ([xshift=10mm]frame.south~west); }, overlay~first={ \draw[line~width=\l_keythms_tcbthmbox_thickness_dim] (title.south~west) -- (title.south~east); \draw[line~width=\l_keythms_tcbthmbox_thickness_dim] (frame.north~west) -- (frame.south~west); }, overlay~middle={ \draw[line~width=\l_keythms_tcbthmbox_thickness_dim] (frame.north~west) -- (frame.south~west); }, overlay~last={ \draw[line~width=\l_keythms_tcbthmbox_thickness_dim] (frame.north~west) |- ([xshift=10mm]frame.south~west); } }, keythms_tcbthmbox_L/.style={ overlay~unbroken={ \draw[line~width=\l_keythms_tcbthmbox_thickness_dim] (title.south~west) -- (title.south~east); \draw[line~width=\l_keythms_tcbthmbox_thickness_dim] (frame.north~west) |- (frame.south~east) -| (frame.north~east); }, overlay~first={ \draw[line~width=\l_keythms_tcbthmbox_thickness_dim] (title.south~west) -- (title.south~east); \draw[line~width=\l_keythms_tcbthmbox_thickness_dim] (frame.north~west) -- (frame.south~west); \draw[line~width=\l_keythms_tcbthmbox_thickness_dim] (frame.north~east) -- (frame.south~east); }, overlay~middle={ \draw[line~width=\l_keythms_tcbthmbox_thickness_dim] (frame.north~west) -- (frame.south~west); \draw[line~width=\l_keythms_tcbthmbox_thickness_dim] (frame.north~east) -- (frame.south~east); }, overlay~last={ \draw[line~width=\l_keythms_tcbthmbox_thickness_dim] (frame.north~west) |- (frame.south~east) -| (frame.north~east); } }, keythms_tcbthmbox_M/.style={}, keythms_tcbthmbox_S/.style={ % first and middle same as M overlay~unbroken={ \draw[line~width=\l_keythms_tcbthmbox_thickness_dim] (title.south~west) -- (title.south~east); \draw[line~width=\l_keythms_tcbthmbox_thickness_dim] (frame.north~west) -- (frame.south~west); }, overlay~last={ \draw[line~width=\l_keythms_tcbthmbox_thickness_dim] (frame.north~west) -- (frame.south~west); } }, } } \keys_set:ne { keytheorems/thm } { tcolorbox = { keythms_tcbthmbox_default, \l__keythms_tcbthmbox_keys_clist } } }, thmbox .default:n = M, mdframed .code:n = \msg_error:nn { keytheorems } { mdframed-undefined }, } \keys_define:nn { keytheorems/thmstyle } { shaded .code:n = \keythms_thmstyle_savethmkey_optval:n { ##1 }, thmbox .code:n = \keythms_thmstyle_savethmkey_optval:n { ##1 }, mdframed .code:n = \msg_error:nn { keytheorems } { mdframed-undefined }, } } \cs_new_protected:Npn \__keythms_storeall_code: { \cs_set_eq:NN \__keythms_withhooks_begin:nnn \__keythms_grab_begin:nnn \cs_set_eq:NN \__keythms_withhooks_end:n \__keythms_grab_end:n } \hook_gput_code:nnn { begindocument/before } { . } { % use 'provide' in case user defines their own translation in preamble \ProvideTranslationFallback { keythms_listof_title } { List~of~Theorems } \ProvideTranslationFallback { keythms_continues } { continuing~from~p.\, } \bool_if:NT \g__keythms_autotranslate_bool { \ProvideTranslation { English } { keythms_listof_title } { List~of~Theorems } \ProvideTranslation { English } { keythms_continues } { continuing~from~p.\, } % from DeepL; I don't know these languages! \ProvideTranslation { French } { keythms_listof_title } { Liste~des~théorèmes } \ProvideTranslation { French } { keythms_continues } { suite~de~la~p.\, } \ProvideTranslation { German } { keythms_listof_title } { Liste~der~Theoreme } \ProvideTranslation { German } { keythms_continues } { weiter~von~Seite~ } \ProvideTranslation { Italian } { keythms_listof_title } { Elenco~dei~teoremi } \ProvideTranslation { Italian } { keythms_continues } { continua~da~p.\, } \ProvideTranslation { Spanish } { keythms_listof_title } { Lista~de~teoremas } \ProvideTranslation { Spanish } { keythms_continues } { continúa~de~la~p.\, } \ProvideTranslation { Portuguese } { keythms_listof_title } { Lista~de~teoremas } \ProvideTranslation { Portuguese } { keythms_continues } { continua~da~p.\, } } } \ProcessKeyOptions[keytheorems] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Support for non-default classes %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \cs_new_protected:Npn \__keythms_support_AMSshared_code: { \keys_define:nn { keytheorems/listof } % adjust to AMS classes { indent .initial:n = 0pt, numwidth .initial:n = 1.5pc, title-code .code:n = { % warn but set titlecmd just in case \msg_warning:nn { keytheorems } { title-code-with-AMS } \cs_set_protected:Npn \__keythms_listof_titlecmd:n ####1 { ##1 } }, } \RenewDocumentCommand \listofkeytheorems { +O{} } { % title command not customizable here \bool_gset_true:N \g__keythms_listof_writefile_bool \group_begin: \keys_set:nn { keytheorems/listof } { ##1 } \cs_set_protected:Npn \KeyThmsContentsLine ####1 { ####1 } \bool_if:NF \l__keythms_listof_nochapskip_bool { \cs_set_protected:Npn \KeyThmsAddvspace { \addvspace } } \legacy_if_set_false:n { @filesw } \bool_if:NTF \l__keythms_listof_notitle_bool { % hacky! \cs_set_eq:NN \@startsection \use_none:nnnnnnn \@starttoc{ thlist }{ } } { % ams classes don't expand title enough \protected@edef \l__keythms_tmpa_tl { \l__keythms_listof_title_tl } \bool_if:NT \l__keythms_listof_notoc_bool { \cs_set_eq:NN \addcontentsline \use_none:nnn } % hacky! \@starttoc{ thlist }{ \l__keythms_tmpa_tl } } \group_end: } \cs_new:Npn \__keythms_listof_ams_tocline: { \@tocline{ 0 }{ 3pt plus 2pt }{ \l__keythms_listof_indent_dim } { \l__keythms_listof_numwidth_dim }{ } } \cs_set_eq:NN \keythms_listof_tocline: \__keythms_listof_ams_tocline: } \prg_new_conditional:Npnn \__keythms_if_classloaded:n #1 { p } { \IfClassLoadedTF { #1 } { \prg_return_true: } { \prg_return_false: } } \cs_new_protected:Npn \__keythms_support_input:n #1 { \file_input:n { class-support/keythms-#1-support } } % acmart and aomart defaults also handled in amsart support file \bool_case:n { { \__keythms_if_classloaded_p:n { amsart } } { \__keythms_support_input:n { amsart } } { \__keythms_if_classloaded_p:n { amsbook } } { \__keythms_support_input:n { amsbook } } { \__keythms_if_classloaded_p:n { amsproc } } { \__keythms_support_input:n { amsproc } } { \__keythms_if_classloaded_p:n { beamer } } { \__keythms_support_input:n { beamer } } { \__keythms_if_classloaded_p:n { IEEEtran } } { \__keythms_support_input:n { IEEEtran } } { \__keythms_if_classloaded_p:n { jlreq } } { \__keythms_support_input:n { jlreq } } { \__keythms_if_classloaded_p:n { memoir } } { \__keythms_support_input:n { memoir } } } % now deal with font packages that change plain style \cs_new_protected:Npn \__keythms_support_fontpkg:nn #1#2 { \clist_map_inline:nn { #1 } { \hook_gput_code:nnn { package/##1/after } { . } { \IfPackageLoadedWithOptionsT { ##1 } { theoremfont } { \prop_gput_from_keyval:Nn \g__keythms_thmstyle_defaultkeys_prop { #2 } \keys_precompile:neN { keytheorems/thmstyle } { \prop_to_keyval:N \g__keythms_thmstyle_defaultkeys_prop } \l__keythms_thmstyle_defaultkeys_tl } } } } \__keythms_support_fontpkg:nn { baskervillef,cochineal } { bodyfont = \slshape } \__keythms_support_fontpkg:nn { libertinust1math,newpxtext,newtxtext,XCharter } { bodyfont = \thfamily, spaceabove = \medskipamount, spacebelow = \medskipamount, } \__keythms_support_fontpkg:nn { scholax } { bodyfont = \thfamily } %%%%%%%%%%%%%%%%%%%%%%% %%% Tagging Support %%% %%%%%%%%%%%%%%%%%%%%%%% \IfDocumentMetadataTF { \tag_if_active:T { \msg_new:nnn { keytheorems } { tag-incompat-key } { The~key~'#1'~does~not~currently~work~with~ tagging.~Ignoring~this~key. } \keys_define:nn { keytheorems/thm } { tcolorbox .code:n = { \msg_warning:nn { keytheorems } { tag-incompat-key } { tcolorbox } }, tcolorbox-no-titlebar .code:n = { \msg_warning:nn { keytheorems } { tag-incompat-key } { tcolorbox-no-titlebar } }, } \keys_define:nn { keytheorems/listof } { print-body .code:n = { \cs_set_protected:Nn \keythms_listof_listcmd:nnnnnnn { \tl_if_empty:nF { ##7 } { \__keythms_getthm_theorem:nnnnn {##1}{##2}{##5}{##6}{##7} } } % with tagging, make \@starttoc same as input \cs_set_protected:Npn \@starttoc ##1 { \makeatletter \@input { \jobname.##1 } } }, } \cs_set_protected:Npn \__keythms_thm_margincode:nnn #1#2#3 { % tagging code does not define theorems with lists \tl_gput_right:cn { g__keythms_thm_preheadfromkeys_#1_tl } { \SetTemplateKeys{ block }{ display } { leftmargin = #2, rightmargin = #3, } } } } } { } \file_input_stop: