% \iffalse meta-comment % % Copyright (C) 2008-2014 by Ulrich M. Schwarz % Copyright (C) 2019 by Frank Mittelbach % Copyright (C) 2020- by Yukai Chou % % This file may be distributed and/or modified under the conditions of % the LaTeX Project Public License, version 1.3c. % The license can be obtained from % http://www.latex-project.org/lppl/lppl-1-3c.txt % % \fi % %\iffalse (hide this from DocInput) %<*kv> %\fi % %\StopEventually{} % \begin{macrocode} \let\@xa\expandafter \let\@nx\noexpand \DeclareOption{lowercase}{% \PackageInfo{thm-kv}{Theorem names will be lowercased}% \global\def\thmt@modifycase{\protect\MakeLowercase}} \DeclareOption{uppercase}{% \PackageInfo{thm-kv}{Theorem names will be uppercased}% \global\def\thmt@modifycase{\protect\MakeUppercase}} \DeclareOption{anycase}{% \PackageInfo{thm-kv}{Theorem names will be unchanged}% \global\def\thmt@modifycase{}} \ExecuteOptions{uppercase} \ProcessOptions\relax \RequirePackage{keyval,kvsetkeys,thm-patch} \long\def\thmt@kv@processor@default#1#2#3{% \def\kvsu@fam{#1}% new \@onelevel@sanitize\kvsu@fam% new \def\kvsu@key{#2}% new \@onelevel@sanitize\kvsu@key% new \unless\ifcsname KV@#1@\kvsu@key\endcsname \unless\ifcsname KVS@#1@handler\endcsname \kv@error@unknownkey{#1}{\kvsu@key}% \else \csname KVS@#1@handler\endcsname{#2}{#3}% % still using #2 #3 here is intentional: handler might % be used for strange stuff like implementing key names % that contain strange characters or other strange things. \relax \fi \else \ifx\kv@value\relax \unless\ifcsname KV@#1@\kvsu@key @default\endcsname \kv@error@novalue{#1}{\kvsu@key}% \else \csname KV@#1@\kvsu@key @default\endcsname \relax \fi \else \csname KV@#1@\kvsu@key\endcsname{#3}% \fi \fi } \@ifpackagelater{kvsetkeys}{2012/04/23}{% \PackageInfo{thm-kv}{kvsetkeys patch (v1.16 or later)}% \long\def\tmp@KVS@PD#1#2#3{% \def \kv@fam {#1}% \unless \ifcsname KV@#1@#2\endcsname \unless \ifcsname KVS@#1@handler\endcsname \kv@error@unknownkey {#1}{#2}% \else \kv@handled@true \csname KVS@#1@handler\endcsname {#2}{#3}\relax \ifkv@handled@ \else \kv@error@unknownkey {#1}{#2}% \fi \fi \else \ifx \kv@value \relax \unless \ifcsname KV@#1@#2@default\endcsname \kv@error@novalue {#1}{#2}% \else \csname KV@#1@#2@default\endcsname \relax \fi \else \csname KV@#1@#2\endcsname {#3}% \fi \fi }% \ifx\tmp@KVS@PD\KVS@ProcessorDefault \let\KVS@ProcessorDefault\thmt@kv@processor@default \def\kv@processor@default#1#2{% \begingroup \csname @safe@activestrue\endcsname \@xa\let\csname ifincsname\@xa\endcsname\csname iftrue\endcsname \edef\KVS@temp{\endgroup % 2019/12/22 removed dependency on etexcmds package \noexpand\KVS@ProcessorDefault{#1}{\unexpanded{#2}}% }% \KVS@temp }% \else \PackageError{thm-kv}{kvsetkeys patch failed}{Try kvsetkeys v1.16 or earlier} \fi }{\@ifpackagelater{kvsetkeys}{2011/04/06}{% % Patch has disappeared somewhere... thanksalot. \PackageInfo{thm-kv}{kvsetkeys patch (v1.13 or later)} \long\def\tmp@KVS@PD#1#2#3{% no non-etex-support here... \unless\ifcsname KV@#1@#2\endcsname \unless\ifcsname KVS@#1@handler\endcsname \kv@error@unknownkey{#1}{#2}% \else \csname KVS@#1@handler\endcsname{#2}{#3}% \relax \fi \else \ifx\kv@value\relax \unless\ifcsname KV@#1@#2@default\endcsname \kv@error@novalue{#1}{#2}% \else \csname KV@#1@#2@default\endcsname \relax \fi \else \csname KV@#1@#2\endcsname{#3}% \fi \fi }% \ifx\tmp@KVS@PD\KVS@ProcessorDefault \let\KVS@ProcessorDefault\thmt@kv@processor@default \def\kv@processor@default#1#2{% \begingroup \csname @safe@activestrue\endcsname \let\ifincsname\iftrue \edef\KVS@temp{\endgroup \noexpand\KVS@ProcessorDefault{#1}{\unexpanded{#2}}% }% \KVS@temp } \else \PackageError{thm-kv}{kvsetkeys patch failed, try kvsetkeys v1.13 or earlier} \fi }{% \RequirePackage{etex} \PackageInfo{thm-kv}{kvsetkeys patch applied (pre-1.13)}% \let\kv@processor@default\thmt@kv@processor@default }} % useful key handler defaults. \newcommand\thmt@mkignoringkeyhandler[1]{% \kv@set@family@handler{#1}{% \thmt@debug{Key `##1' with value `##2' ignored by #1.}% }% } \newcommand\thmt@mkextendingkeyhandler[3]{% % #1: family % #2: prefix for file % #3: key hint for error \kv@set@family@handler{#1}{% \thmt@selfextendingkeyhandler{#1}{#2}{#3}% {##1}{##2}% }% } \newcommand\thmt@selfextendingkeyhandler[5]{% % #1: family % #2: prefix for file % #3: key hint for error % #4: actual key % #5: actual value \IfFileExists{#2-#4.sty}{% \PackageInfo{thmtools}% {Automatically pulling in `#2-#4'}% \RequirePackage{#2-#4}% \ifcsname KV@#1@#4\endcsname \csname KV@#1@#4\endcsname{#5}% \else \PackageError{thmtools}% {#3 `#4' not known} {I don't know what that key does.\MessageBreak I've even loaded the file `#2-#4.sty', but that didn't help. }% \fi }{% \PackageError{thmtools}% {#3 `#4' not known} {I don't know what that key does by myself,\MessageBreak and no file `#2-#4.sty' to tell me seems to exist. }% }% } \newif\if@thmt@firstkeyset % many keys are evaluated twice, because we don't know % if they make sense before or after, or both. \def\thmt@trytwice{% \if@thmt@firstkeyset \@xa\@firstoftwo \else \@xa\@secondoftwo \fi } \@for\tmp@keyname:=parent,numberwithin,within\do{% \define@key{thmdef}{\tmp@keyname}{% \thmt@trytwice{% \thmt@setparent{#1} \thmt@setsibling{}% }{}% }% } \newcommand\thmt@setparent{% \def\thmt@parent } \@for\tmp@keyname:=sibling,numberlike,sharenumber\do{% \define@key{thmdef}{\tmp@keyname}{% \thmt@trytwice{% \thmt@setsibling{#1}% \thmt@setparent{}% }{}% }% } \newcommand\thmt@setsibling{% \def\thmt@sibling } \@for\tmp@keyname:=title,name,heading\do{% \define@key{thmdef}{\tmp@keyname}{\thmt@trytwice{\thmt@setthmname{#1}}{}}% } \newcommand\thmt@setthmname{% \def\thmt@thmname } \@for\tmp@keyname:=unnumbered,starred\do{% \define@key{thmdef}{\tmp@keyname}[]{\thmt@trytwice{\thmt@isnumberedfalse}{}}% } \def\thmt@YES{yes} \def\thmt@NO{no} \def\thmt@UNIQUE{unless unique} \newif\ifthmt@isnumbered \newif\ifthmt@isunlessunique \define@key{thmdef}{numbered}[yes]{ \def\thmt@tmp{#1}% \thmt@trytwice{% \ifx\thmt@tmp\thmt@YES \thmt@isnumberedtrue \else\ifx\thmt@tmp\thmt@NO \thmt@isnumberedfalse \else\ifx\thmt@tmp\thmt@UNIQUE \RequirePackage[unq]{unique} \thmt@isunlessuniquetrue \else \PackageError{thmtools}{Unknown value `#1' to key numbered}{}% \fi\fi\fi }{% trytwice: after definition \ifx\thmt@tmp\thmt@UNIQUE \ifx\thmt@parent\@empty \addtotheorempreheadhook[\thmt@envname]{\setuniqmark{\thmt@envname}}% \else \protected@edef\thmt@tmp{% % expand \thmt@envname and \thmt@parent \@nx\addtotheorempreheadhook[\thmt@envname @unique]{% \@nx\setuniqmark{\thmt@envname.\@nx\@nameuse{the\thmt@parent}}}% \@nx\addtotheorempreheadhook[\thmt@envname @numbered]{% \@nx\setuniqmark{\thmt@envname.\@nx\@nameuse{the\thmt@parent}}}% \@nx\addtotheorempreheadhook[\thmt@envname @unique]{% \def\@nx\thmt@dummyctrautorefname{\thmt@thmname\@nx\@gobble}}% \@nx\addtotheorempreheadhook[\thmt@envname @numbered]{% \def\@nx\thmt@dummyctrautorefname{\thmt@thmname\@nx\@gobble}}% }% \thmt@tmp \fi % \addtotheorempreheadhook[\thmt@envname]{% % \def\thmt@dummyctrautorefname{\thmt@thmname\@gobble}}% \fi }% } \define@key{thmdef}{preheadhook}{% \thmt@trytwice{}{\addtotheorempreheadhook[\thmt@envname]{#1}}} \define@key{thmdef}{postheadhook}{% \thmt@trytwice{}{\addtotheorempostheadhook[\thmt@envname]{#1}}} \define@key{thmdef}{prefoothook}{% \thmt@trytwice{}{\addtotheoremprefoothook[\thmt@envname]{#1}}} \define@key{thmdef}{postfoothook}{% \thmt@trytwice{}{\addtotheorempostfoothook[\thmt@envname]{#1}}} \define@key{thmdef}{style}{\thmt@trytwice{\thmt@setstyle{#1}}{}} % ugly hack: style needs to be evaluated first so its keys % are not overridden by explicit other settings \define@key{thmdef0}{style}{% \ifcsname thmt@style #1@defaultkeys\endcsname \thmt@toks{\kvsetkeys{thmdef}}% \@xa\@xa\@xa\the\@xa\@xa\@xa\thmt@toks\@xa\@xa\@xa{% \csname thmt@style #1@defaultkeys\endcsname}% \fi } \thmt@mkignoringkeyhandler{thmdef0} % fallback definition. % actually, only the kernel does not provide \theoremstyle. % is this one worth having glue code for the theorem package? \def\thmt@setstyle#1{% \PackageWarning{thm-kv}{% Your backend doesn't have a `\string\theoremstyle' command. }% } \ifcsname theoremstyle\endcsname \let\thmt@originalthmstyle\theoremstyle \def\thmt@outerstyle{plain} \renewcommand\theoremstyle[1]{% \def\thmt@outerstyle{#1}% \thmt@originalthmstyle{#1}% } \def\thmt@setstyle#1{% \thmt@originalthmstyle{#1}% } \g@addto@macro\thmt@newtheorem@postdefinition{% \thmt@originalthmstyle{\thmt@outerstyle}% } \fi \thmt@mkextendingkeyhandler{thmdef}{thmdef}{\string\declaretheorem\space key} \let\thmt@newtheorem\newtheorem % \declaretheorem[option list 1]{thmname list}[option list 1] % #1 = option list 1 % #2 = thmname list \newcommand\declaretheorem[2][]{% % TODO: use \NewDocumentCommand from xparse? % xparse will be part of latex2e format from latex2e 2020 Oct. \@ifnextchar[% {\declaretheorem@i{#1}{#2}} {\declaretheorem@i{#1}{#2}[]}% } \@onlypreamble\declaretheorem % #1 = option list 1 % #2 = thmname list % #3 = option list 2 \def\declaretheorem@i#1#2[#3]{% \@for\thmt@tmp:=#2\do{% % strip spaces, \KV@@sp@def is defined in keyval.sty \@xa\KV@@sp@def\@xa\thmt@tmp\@xa{\thmt@tmp}% \@xa\declaretheorem@ii\@xa{\thmt@tmp}{#1,#3}% }% } % #1 = single thmname (#1 and #2 are exchanged) % #2 = option list \def\declaretheorem@ii#1#2{% % why was that here? %\let\thmt@theoremdefiner\thmt@original@newtheorem % init options \thmt@setparent{}% \thmt@setsibling{}% \thmt@isnumberedtrue \thmt@isunlessuniquefalse \def\thmt@envname{#1}% \thmt@setthmname{\thmt@modifycase #1}% % use true code in \thmt@trytwice{}{} \@thmt@firstkeysettrue % parse options \kvsetkeys{thmdef0}{#2}% parse option "style" first \kvsetkeys{thmdef}{#2}% % call patched \newtheorem \ifthmt@isunlessunique \ifx\thmt@parent\@empty % define normal "unless unique" thm env \ifuniq{#1}{\thmt@isnumberedfalse}{\thmt@isnumberedtrue}% \declaretheorem@iii{#1}% \else % define special "unless unique" thm env, % when "numbered=unless unique" and "numberwithin=" are both used \declaretheorem@iv{#1}% \thmt@isnumberedtrue \declaretheorem@iii{#1@numbered}% \thmt@isnumberedfalse \declaretheorem@iii{#1@unique}% \fi \else % define normal thm env \declaretheorem@iii{#1}% \fi % use false code in \thmt@trytwice{}{} \def\thmt@envname{#1}% \@thmt@firstkeysetfalse % uniquely ugly kludge: some keys make only sense afterwards. % and it gets kludgier: again, the default-inherited % keys need to have a go at it. \kvsetkeys{thmdef0}{#2}% \kvsetkeys{thmdef}{#2}% } % define normal thm env, call \thmt@newtheorem \def\declaretheorem@iii#1{% \protected@edef\thmt@tmp{% \@nx\thmt@newtheorem \ifthmt@isnumbered {#1}% \ifx\thmt@sibling\@empty\else [\thmt@sibling]\fi {\thmt@thmname}% \ifx\thmt@parent\@empty\else [\thmt@parent]\fi \else *{#1}{\thmt@thmname}% \fi \relax% added so we can delimited-read everything later }% \thmt@debug{Define theorem `#1' by ^^J\meaning\thmt@tmp}% \thmt@tmp } % define special thm env \def\declaretheorem@iv#1{% \protected@edef\thmt@tmp{% % expand \thmt@envname and \thmt@parent \@nx\newenvironment{#1}{% \@nx\ifuniq{\thmt@envname.\@nx\@nameuse{the\thmt@parent}}{% \def\@nx\thmt@rawenvname{#1@unique}% }{% \def\@nx\thmt@rawenvname{#1@numbered}% }% \begin{\@nx\thmt@rawenvname}% }{% \end{\@nx\thmt@rawenvname}% }% }% \thmt@debug{Define special theorem `#1' by ^^J\meaning\thmt@tmp}% \thmt@tmp } \providecommand\thmt@quark{\thmt@quark} % in-document keyval, i.e. \begin{theorem}[key=val,key=val] \thmt@mkextendingkeyhandler{thmuse}{thmuse}{\thmt@envname\space optarg key} \addtotheorempreheadhook{% \ifx\thmt@optarg\@empty\else \@xa\thmt@garbleoptarg\@xa{\thmt@optarg}\fi }% \newif\ifthmt@thmuse@iskv \providecommand\thmt@garbleoptarg[1]{% \thmt@thmuse@iskvfalse \def\thmt@newoptarg{\@gobble}% \def\thmt@newoptargextra{}% \let\thmt@shortoptarg\@empty \def\thmt@warn@unusedkeys{}% \@for\thmt@fam:=\thmt@thmuse@families\do{% \kvsetkeys{\thmt@fam}{#1}% }% \ifthmt@thmuse@iskv \protected@edef\thmt@optarg{% \@xa\thmt@newoptarg \thmt@newoptargextra\@empty }% \ifx\thmt@shortoptarg\@empty \protected@edef\thmt@shortoptarg{\thmt@newoptarg\@empty}% \fi \thmt@warn@unusedkeys \else \def\thmt@optarg{#1}% \def\thmt@shortoptarg{#1}% \fi } % FIXME: not used? % \def\thmt@splitopt#1=#2\thmt@quark{% % \def\thmt@tmpkey{#1}% % \ifx\thmt@tmpkey\@empty % \def\thmt@tmpkey{\thmt@quark}% % \fi % \@onelevel@sanitize\thmt@tmpkey % } \def\thmt@thmuse@families{thm@track@keys} \kv@set@family@handler{thm@track@keys}{% \@onelevel@sanitize\kv@key \@namedef{thmt@unusedkey@\kv@key}{% \PackageWarning{thmtools}{Unused key `#1'}% }% \@xa\g@addto@macro\@xa\thmt@warn@unusedkeys\@xa{% \csname thmt@unusedkey@\kv@key\endcsname } } % key, code. \def\thmt@define@thmuse@key#1#2{% \g@addto@macro\thmt@thmuse@families{,#1}% \define@key{#1}{#1}{\thmt@thmuse@iskvtrue \@namedef{thmt@unusedkey@#1}{}% #2}% \thmt@mkignoringkeyhandler{#1}% } \thmt@define@thmuse@key{label}{% \addtotheorempostheadhook[local]{\label{#1}}% } \thmt@define@thmuse@key{name}{% \thmt@setnewoptarg #1\@iden% } \newcommand\thmt@setnewoptarg[1][]{% \def\thmt@shortoptarg{#1}\thmt@setnewlongoptarg } \def\thmt@setnewlongoptarg #1\@iden{% \def\thmt@newoptarg{#1\@iden}} \providecommand\thmt@suspendcounter[2]{% \@xa\protected@edef\csname the#1\endcsname{#2}% \@xa\let\csname c@#1\endcsname\c@thmt@dummyctr } \providecommand\thmcontinues[1]{% \ifcsname hyperref\endcsname \hyperref[#1]{continuing} \else continuing \fi from p.\,\pageref{#1}% } \thmt@define@thmuse@key{continues}{% \thmt@suspendcounter{\thmt@envname}{\thmt@trivialref{#1}{??}}% \g@addto@macro\thmt@newoptarg{{, }% \thmcontinues{#1}% \@iden}% } % \end{macrocode} % % Defining new theorem styles; keys are in opt-arg % even though not having any doesn't make much sense. % It doesn't do anything exciting here, it's up to % the glue layer to provide keys. % % \begin{macrocode} \def\thmt@declaretheoremstyle@setup{} \def\thmt@declaretheoremstyle#1{% \PackageWarning{thmtools}{Your backend doesn't allow styling theorems}{} } \newcommand\declaretheoremstyle[2][]{% \def\thmt@style{#2}% \@xa\def\csname thmt@style \thmt@style @defaultkeys\endcsname{}% \thmt@declaretheoremstyle@setup \kvsetkeys{thmstyle}{#1}% \thmt@declaretheoremstyle{#2}% } \@onlypreamble\declaretheoremstyle \kv@set@family@handler{thmstyle}{% \@onelevel@sanitize\kv@value \@onelevel@sanitize\kv@key \PackageInfo{thmtools}{% Key `\kv@key' (with value `\kv@value')\MessageBreak is not a known style key.\MessageBreak Will pass this to every \string\declaretheorem\MessageBreak that uses `style=\thmt@style'% }% \ifx\kv@value\relax% no value given, don't pass on {}! \@xa\g@addto@macro\csname thmt@style \thmt@style @defaultkeys\endcsname{% #1,% }% \else \@xa\g@addto@macro\csname thmt@style \thmt@style @defaultkeys\endcsname{% #1={#2},% }% \fi } % \end{macrocode} % %\iffalse % %\fi