我正在尝试为具有自定义名称的定理创建一个“一次性”定理环境,这些定理根本不应该被编号。目标是复制thmtools
\declaretheorem[thmbox=M]{theorem}
通过直接使用thmbox
环境并实现thmtools 的label
和name
选项,将未知键解释为键的值name
。由于定理没有编号,\ref
应该给出定理名称。没有太多可继续的内容clsguide
,我的目标是不使用 keyvals 的“编程”接口(等)来做到这一点\keys_define:nn
。这是我的尝试,似乎有效:
\documentclass{article}
\usepackage{kantlipsum,thmtools}
\makeatletter
\newif\if@hasname@
\DeclareKeys[oneoffthm]{
label .store = \oneoffthm@label,
storename .store = \oneoffthm@name,
hasname .if = @hasname@,
name .meta:n = {hasname,storename=#1},
}
\DeclareUnknownKeyHandler[oneoffthm]{\SetKeys[oneoffthm]{name=#1}}
\NewDocumentEnvironment{oneoffthm}{m o}{%
\vspace*{0.4\baselineskip}%
\begin{thmbox}[M]{%
\bfseries%
#1%
\IfValueT{#2}{%
\SetKeys[oneoffthm]{#2}%
\def\@currentlabel{#1}%
\label{\oneoffthm@label}%
\if@hasname@\;(\textit{\oneoffthm@name})\fi%
}%
}%
\noindent%
\ignorespaces%
}
{\end{thmbox}\vspace*{0.4\baselineskip}}
\makeatother
\declaretheorem[thmbox=M]{theorem}
\thmboxoptions{bodystyle=\normalfont\noindent}
\begin{document}
\begin{theorem}
\kant[1][1]
\end{theorem}
\begin{oneoffthm}{Custom Name A}
\kant[2][1]
\end{oneoffthm}
\begin{theorem}[a heading]
\kant[3][1]
\end{theorem}
\begin{oneoffthm}{Custom Name B}[a heading]
\kant[4][1]
\end{oneoffthm}
\begin{theorem}[label=abc]
\kant[5][1]
\end{theorem}
\begin{oneoffthm}{Custom Name C}[label=customC]
\kant[6][1]
\end{oneoffthm}
\begin{theorem}[name=a heading,label=def]
\kant[7][1]
\end{theorem}
\begin{oneoffthm}{Custom Name D}[name=a heading,label=customD]
\kant[8][1]
\end{oneoffthm}
\ref{abc}
\ref{customC}
\ref{def}
\ref{customD}
\end{document}
我的方法\DeclareKeys
似乎不太理想。有没有办法访问关键参数而不将它们存储在宏中?出于扩展原因,这在某些设置中似乎不太好。此外,有没有办法实现该name
键而不需要设置其他两个键?当然可以说
name .code = \@hasname@true\def\oneoffthm@name{#1}
但这似乎不符合 keyvals 的精神。
不幸的是我无法适应这个优秀的答案因为 thmbox 不允许无编号定理。
附言手动垂直间距oneoffthm
很糟糕,但我不知道有更好的选择。普通thmbox
环境的默认间距似乎不正确,但使用 thmbox 声明的定理的间距很好,直接使用 thmtools 或 thmbox 包即可。编辑:为了模仿 thmbox 声明定理的行为,将开头和结尾分别替换\vspace*{0.4\baselineskip}
为\medbreak
和\smallbreak\@endpetrue
。
答案1
您可以使用修饰符来表示不是 key=value 列表的参数应该被视为键的参数,而不是将其视为[a heading]
未知键。=
name
\documentclass{article}
\usepackage{kantlipsum,thmtools}
\makeatletter
\newif\if@hasname@
\DeclareKeys[oneoffthm]{
label .store = \oneoffthm@label,
storename .store = \oneoffthm@name,
hasname .if = @hasname@,
name .meta:n = {hasname,storename=#1},
}
\NewDocumentEnvironment{oneoffthm}{m ={name} o}{%
\vspace*{0.4\baselineskip}%
\begin{thmbox}[M]{%
\bfseries%
#1%
\IfValueT{#2}{%
\SetKeys[oneoffthm]{#2}%
\def\@currentlabel{#1}%
\label{\oneoffthm@label}%
\if@hasname@\;(\textit{\oneoffthm@name})\fi%
}%
}%
\noindent%
\ignorespaces%
}
{\end{thmbox}\vspace*{0.4\baselineskip}}
\makeatother
\declaretheorem[thmbox=M]{theorem}
\thmboxoptions{bodystyle=\normalfont\noindent}
\begin{document}
\begin{theorem}
\kant[1][1]
\end{theorem}
\begin{oneoffthm}{Custom Name A}
\kant[2][1]
\end{oneoffthm}
\begin{theorem}[a heading]
\kant[3][1]
\end{theorem}
\begin{oneoffthm}{Custom Name B}[a heading]
\kant[4][1]
\end{oneoffthm}
\begin{theorem}[label=abc]
\kant[5][1]
\end{theorem}
\begin{oneoffthm}{Custom Name C}[label=customC]
\kant[6][1]
\end{oneoffthm}
\begin{theorem}[name=a heading,label=def]
\kant[7][1]
\end{theorem}
\begin{oneoffthm}{Custom Name D}[name=a heading,label=customD]
\kant[8][1]
\end{oneoffthm}
\ref{abc}
\ref{customC}
\ref{def}
\ref{customD}
\end{document}
您可以简化键结构,删除元键和内部布尔值:
\makeatletter
\DeclareKeys[oneoffthm]{
label .store = \oneoffthm@label,
name .store = \oneoffthm@name,
}
\NewDocumentEnvironment{oneoffthm}{m ={name} o}{%
\vspace*{0.4\baselineskip}%
\begin{thmbox}[M]{%
\bfseries%
#1%
\IfValueT{#2}{%
\let\oneoffthm@name\relax
\SetKeys[oneoffthm]{#2}%
\def\@currentlabel{#1}%
\label{\oneoffthm@label}%
\ifx\oneoffthm@name\relax\else\;(\textit{\oneoffthm@name})\fi
}%
}%
\noindent%
\ignorespaces%
}
{\end{thmbox}\vspace*{0.4\baselineskip}}
\makeatother
答案2
expkv-cs
在我们可以的帮助下
- 访问未知的密钥名称而不对其进行解密
- 访问不同键的值,不存在任何扩展问题
下面使用内部键将带有格式指令的键值传递name
给底层宏(这样我们就不需要条件来检查它是否被使用,如果没有使用它就会是空的)。
\documentclass{article}
\usepackage{kantlipsum,thmtools}
\usepackage{expkv-cs}
\makeatletter
\ekvcSplit\oneoffthm@KV
{
label = {}
,name-internal = {}
}
{\label{#1}#2}
\ekvcSecondaryKeys\oneoffthm@KV{meta name = name-internal={\;(\textit{#1})}}
\ekvdefunknownNoVal{\string\oneoffthm@KV}{\ekvmorekv{name={#2}}}
\NewDocumentEnvironment{oneoffthm}{m o}{%
\vspace*{0.4\baselineskip}%
\begin{thmbox}[M]{%
\bfseries%
#1%
\IfValueT{#2}
{%
\def\@currentlabel{#1}%
\oneoffthm@KV{#2}%
}%
}%
\noindent%
\ignorespaces%
}
{\end{thmbox}\vspace*{0.4\baselineskip}}
\makeatother
\declaretheorem[thmbox=M]{theorem}
\thmboxoptions{bodystyle=\normalfont\noindent}
\begin{document}
\begin{theorem}
\kant[1][1]
\end{theorem}
\begin{oneoffthm}{Custom Name A}
\kant[2][1]
\end{oneoffthm}
\begin{theorem}[a heading]
\kant[3][1]
\end{theorem}
\begin{oneoffthm}{Custom Name B}[a heading]
\kant[4][1]
\end{oneoffthm}
\begin{theorem}[label=abc]
\kant[5][1]
\end{theorem}
\begin{oneoffthm}{Custom Name C}[label=customC]
\kant[6][1]
\end{oneoffthm}
\begin{theorem}[name=a heading,label=def]
\kant[7][1]
\end{theorem}
\begin{oneoffthm}{Custom Name D}[name=a heading,label=customD]
\kant[8][1]
\end{oneoffthm}
\ref{abc}
\ref{customC}
\ref{def}
\ref{customD}
\end{document}
一种使用expkv-def
而不是 的变体expkv-cs
。通过这种方式,我们仍然可以访问未知的键名而无需对其进行去标记化,但也可以使用更传统的 key=value 方法,即定义宏来存储键值。
此外,dataT
的键类型expkv-def
对于手头的任务来说似乎非常方便(\label
如果label
使用了键,则仅设置,如果name
使用了键,则仅格式化名称)。dataT
如果未使用键,则键将吞噬存储它的宏后面的标记或组(因此行为类似于\@gobble
),但如果使用了它,它将扩展为标记或组,后跟括号中的值(因此这里也没有扩展问题,和\label
都\oneoffthm@name@format
获取值而不是存储它的宏)。
\documentclass{article}
\usepackage{kantlipsum,thmtools}
\usepackage{expkv-def}
\makeatletter
\ekvdefinekeys{oneoffthm}
{
dataT label = \oneoffthm@label
,dataT name = \oneoffthm@name
,unknown noval = \ekvmorekv{name={#2}}
}
\newcommand\oneoffthm@name@format[1]{\;(\textit{#1})}
\NewDocumentEnvironment{oneoffthm}{m o}{%
\vspace*{0.4\baselineskip}%
\begin{thmbox}[M]{%
\bfseries%
#1%
\IfValueT{#2}
{%
\def\@currentlabel{#1}%
\ekvset{oneoffthm}{#2}%
\oneoffthm@label\label
\oneoffthm@name\oneoffthm@name@format
}%
}%
\noindent%
\ignorespaces%
}
{\end{thmbox}\vspace*{0.4\baselineskip}}
\makeatother
\declaretheorem[thmbox=M]{theorem}
\thmboxoptions{bodystyle=\normalfont\noindent}
\begin{document}
\begin{theorem}
\kant[1][1]
\end{theorem}
\begin{oneoffthm}{Custom Name A}
\kant[2][1]
\end{oneoffthm}
\begin{theorem}[a heading]
\kant[3][1]
\end{theorem}
\begin{oneoffthm}{Custom Name B}[a heading]
\kant[4][1]
\end{oneoffthm}
\begin{theorem}[label=abc]
\kant[5][1]
\end{theorem}
\begin{oneoffthm}{Custom Name C}[label=customC]
\kant[6][1]
\end{oneoffthm}
\begin{theorem}[name=a heading,label=def]
\kant[7][1]
\end{theorem}
\begin{oneoffthm}{Custom Name D}[name=a heading,label=customD]
\kant[8][1]
\end{oneoffthm}
\ref{abc}
\ref{customC}
\ref{def}
\ref{customD}
\end{document}