我正在尝试使用 xparse 和 xkeyval 编写命令。目标是编写一个可以采用可选键值参数的命令,以便让那些刚刚被迫在几乎所有事情上都切换到 LaTeX 的用户更轻松、更易读。
作为示例,我将使用此命令来显示图像。请注意,图像的标题完全是可选的,图像的宽度也是可选的,但可以使用默认设置。
这是我目前的情况:
\documentclass{article}
\usepackage{graphicx}
\usepackage{xparse}
\usepackage{xkeyval}
\usepackage{mwe}
\makeatletter
\define@key{test}{caption}{\def\captiontext{#1}}
\define@key{test}{width}{\def\width{#1}}
\makeatother
\NewDocumentCommand{\displayImage}{o m}{
\begingroup
\setkeys{test}{caption={},width={0.5\textwidth}, #1}
\begin{figure}[h]
\displayImage[width=\width]{#2}
\IfValueT{\captiontext}{\caption{\captiontext}}
\end{figure}
\endgroup
}
\begin{document}
\displayImage{example-image}
\end{document}
这甚至无法编译。我不明白错误代码为什么无法编译。
尽管在互联网上进行了广泛的研究并阅读了这两个软件包的官方文档,但我并没有取得任何进展。
如能得到任何帮助来向我展示如何使其工作并解释近期使用的解决方案,我将非常感激。
注意:我愿意使用其他可以帮助我实现这一目标的软件包。
答案1
\IfValueT
仅与 指定的可选参数结合才有意义o
,不适用于测试某物是否有值。而且您显然希望\includegraphics
在定义文本中,而不是再次\displayImage
。
我不会使用xkeyval
:expl3
有更好的选择。我也不会使用这种方法,因为我看不出有什么真正的优势,但这是你的文档……
\documentclass{article}
\usepackage{graphicx}
%\usepackage{xparse} % not needed for LaTeX 2020-10-01 or later
\ExplSyntaxOn
\keys_define:nn { alexbits/figure }
{
width .dim_set:N = \l__alexbits_figure_width_dim,
caption .tl_set:N = \l__alexbits_figure_caption_tl,
}
\NewDocumentCommand{\displayImage}{O{} m}
{
\group_begin:
\keys_set:nn { alexbits/figure }
{
width=0.5\textwidth, #1
}
\begin{figure}[htp] % not just h
\centering
\includegraphics[width=\l__alexbits_figure_width_dim]{#2}
\tl_if_empty:NF \l__alexbits_figure_caption_tl
{
\caption{\l__alexbits_figure_caption_tl}
}
\end{figure}
\group_end:
}
\ExplSyntaxOff
\begin{document}
\displayImage{example-image}
\displayImage[width=3cm,caption={Some caption text}]{example-image}
\end{document}
答案2
下面使用包expkv-def
(免责声明:我是它的作者)。该包有(恕我直言)方便的密钥类型data
和dataT
。它们结合了测试密钥是否已被使用以及将值存储在单个宏中。例如,在
\ekvdefinekeys{foo}{data d=\foo@d, dataT t=\foo@t}
宏\foo@d
将被定义为接受参数\foo@d{<used>}{<not-used>}
,如果键d
已被使用,它将扩展为<used>{<data>}
(<data>
使用时获得的值),如果未使用,它将扩展为<not-used>
。 宏\foo@t
将被定义为接受参数\foo@t{<used>}
,如果使用,它将扩展为<used>{<data>}
,如果未使用,它将扩展为空。
下面将定义宏来\displayImage
识别键caption
、label
、loc
和width
。对于它不认识的每个键,它都会\includegraphics
假设它是该键的键。
\documentclass{article}
\usepackage{expkv-def}
\usepackage[]{graphicx}
\makeatletter
\newcommand*\dI@unknown{}
\ekvdefinekeys{displayImage}
{
dataT caption = \dI@caption
,data label = \dI@label
,data loc = \dI@loc
,store width = \dI@width
,initial width = .5\linewidth
% forward all unknown keys to \includegraphics
,protected unknown code =
{\edef\dI@unknown{\unexpanded\expandafter{\dI@unknown,#1= {#2}}}}
,protected unknown noval =
{\edef\dI@unknown{\unexpanded\expandafter{\dI@unknown,#1}}}
}
\newcommand\dI@figure[1]{\begin{figure}[{#1}]}
\newcommand\dI@capWlabel[2]{\caption{#2\label{#1}}}
\newcommand\displayImage[2][]
{%
\begingroup
\ekvset{displayImage}{#1}%
\dI@loc\dI@figure{\begin{figure}}%
\centering
\expanded
{%
\noexpand\includegraphics
[{width=\noexpand\dI@width,\unexpanded\expandafter{\dI@unknown}}]%
}%
{#2}%
\dI@caption{\dI@label\dI@capWlabel\caption}%
\end{figure}%
\endgroup
}
\makeatother
\begin{document}
Abc, but see also fig.~\ref{fig:ex}.
\displayImage[caption={An example},label=fig:ex]{example-image}
\displayImage[height=2cm,keepaspectratio,caption=A duck]{example-image-duck}
\displayImage[width=2cm,loc=bp]{example-image-duck-portrait}
\end{document}