假设您正在align
为某些环境定义一个 key=value realign
,您将按以下方式使用:
\usepackage{xkeyval}% http://ctan.org/pkg/xkeyval
\newenvironment{realign}[1][]
{\setkeys{fam}{#1}\myalignment}% \begin{realign}
{}% \end{realign}
你定义align
选择通过使用键来设置\myalignment
(取自xkeyval
文档):
\define@choicekey*{fam}{align}[\val\nr]{left,center,right}{%
\ifcase\nr\relax
\def\myalignment{\raggedright}% align=left
\or
\def\myalignment{\centering}% align=center
\or
\def\myalignment{\raggedleft}% align=right
\fi
}
但是,现在你有了创建相应布尔值键left
,center
并且right
等同left|center|right=true
于align=left|center|right
。是否可以定义布尔值宏定义中的键,例如通过类似如下的方式\newboolkey{left}
:
\newcommand{\newboolkey}[1]{
\define@boolkey{fam}[@bool@]{#1}[true]{%
\csname if@bool@#1\endcsname%
\setkeys{fam}{align=#1}%
\fi%
}%
}
这是行不通的,因为#1
的参数\newboolkey
没有正确地转换成键的定义left
。
当然,\define@boolkey
从中删除\newboolkey
并明确说明键(而不是#1
)是可行的。但是,我对以这种方式(手动)创建布尔键不感兴趣。我想使用宏定义来执行此操作,因为它应该是自动化和灵活的。
这是一个不起作用的最小示例:
\documentclass{article}
\usepackage{lipsum}% http://ctan.org/pkg/lipsum
\usepackage{xkeyval}% http://ctan.org/pkg/xkeyval
\newenvironment{realign}[1][]
{\setkeys{fam}{#1}\myalignment}% \begin{realign}
{}% \end{realign}
\makeatletter
\define@choicekey*{fam}{align}[\val\nr]{left,center,right}{%
\ifcase\nr\relax
\def\myalignment{\raggedright}% align=left
\or
\def\myalignment{\centering}% align=center
\or
\def\myalignment{\raggedleft}% align=right
\fi
}
\newcommand{\newboolkey}[1]{
\define@boolkey{fam}[@bool@]{#1}[true]{%
\csname if@bool@#1\endcsname%
\setkeys{fam}{align=#1}%
\fi%
}%
}
\makeatother
\begin{document}
\begin{realign}[align=left]
\lipsum[1]
\end{realign}
\newboolkey{left}% Create a boolean equivalent for align=left
\makeatletter
\if@bool@left\else% Check if key is defined.
\texttt{left} key defined
\fi
\begin{realign}[left]% Doesn't work
\lipsum[1]
\end{realign}
\end{document}
答案1
Marco 已经发布了一个版本,但我认为这更接近您想要的版本,只是修复了#1
/##1
混淆。
\documentclass{article}
\usepackage{lipsum}% http://ctan.org/pkg/lipsum
\usepackage{xkeyval}% http://ctan.org/pkg/xkeyval
\newenvironment{realign}[1][]
{\let\myalignment\relax\setkeys{fam}{#1}\myalignment}% \begin{realign}
{}% \end{realign}
\makeatletter
\define@choicekey*{fam}{align}[\val\nr]{left,center,right}{%
\ifcase\nr\relax
\def\myalignment{\raggedright}% align=left
\or
\def\myalignment{\centering}% align=center
\or
\def\myalignment{\raggedleft}% align=right
\fi
}
\newcommand{\newboolkey}[1]{
\define@boolkey{fam}[@bool@]{#1}[true]{%
\csname if##1\endcsname
\setkeys{fam}{align=#1}%
\csname fi\endcsname
}%
}
\makeatother
\begin{document}
\begin{realign}[align=left]
\lipsum[1]
\end{realign}
\newboolkey{left}% Create a boolean equivalent for align=left
\makeatletter
\if@bool@left\else% Check if key is defined.
\texttt{left} key defined
\fi
\begin{realign}[left]% Doesn't work
\lipsum[1]
\end{realign}
\end{document}
答案2
您可以测试的参数define@boolkey
。它更容易处理:
\newcommand{\newboolkey}[1]{%
\define@boolkey{fam}[@bool@]{#1}[true]{%
\in@{true}{##1}
\ifin@
\setkeys{fam}{align=#1}%
\fi
}%
}
如果您想使用您的代码,您可以使用:
\newcommand{\newboolkey}[1]{
\define@boolkey{fam}[@bool@]{#1}[true]{%
\csname if@bool@#1\endcsname%
\setkeys{fam}{align=#1}%
\csname fi \endcsname%
}%
}
对我有用的完整代码:
\setcounter{errorcontextlines}{999}
\documentclass{article}
\usepackage{lipsum}% http://ctan.org/pkg/lipsum
\usepackage{xkeyval}% http://ctan.org/pkg/xkeyval
\newenvironment{realign}[1][]%
{\setkeys{fam}{#1}\myalignment}% \begin{realign}
{}% \end{realign}
\makeatletter
\let\myalignment\relax
\define@choicekey*{fam}{align}[\val\nr]{left,center,right}{%
\ifcase\nr\relax
\def\myalignment{\raggedright}% align=left
\or
\def\myalignment{\centering}% align=center
\or
\def\myalignment{\raggedleft}% align=right
\fi
}
\newcommand{\newboolkey}[1]{%
\define@boolkey{fam}[@bool@]{#1}[true]{%
\in@{true}{##1}
\ifin@
\setkeys{fam}{align=#1}%
\fi
}%
}
\makeatother
\begin{document}
\begin{realign}[align=center]
\lipsum[1]
\end{realign}
\hrulefill
\newboolkey{left}% Create a boolean equivalent for align=left
\begin{realign}[left]
\lipsum[1]
\end{realign}
\end{document}
答案3
我看到你想定义多个布尔键。我决定使用龙腾包。我本来会使用key environment
这个任务,但这是你想要的。我首先想到的也是命令\ltxkeys@declarekeys
。
\documentclass{article}
\usepackage{lipsum}
\usepackage{ltxkeys}
\makeatletter
\newenvironment{realign}[1][]{%
\let\myalignment\relax
\ltxkeys@setkeys[WN]{fam}{#1}\myalignment
}{}
% 1. The *-form of \ltxkeys@choicekey will convert the user input to lowercase
% before checking the value against the nominations and executing the callbacks.
% 2. The !-form will fully expand the user input before checking it against
% the nominations.
% 3. The +-form expects two callbacks (one for when the user input is valid,
% and the other for when the user input isn't in the nominations).
% \val and \mpcalign hold the same content.
\ltxkeys@choicekey*+![WN]{fam}[mpc]{align}[\val\nr]{%
center/.code=\let\myalignment\centering,
left/.code=\let\myalignment\raggedright,
right/.code=\let\myalignment\raggedleft
}[center]{%
% Callback for when value is correct, ie, in the list {left,right,center}.
}{%
\@latexerr{Invalid value for key 'align'}\@ehd
}
% I thought you meant to define more than one boolean key:
\ltxkeys@boolkeys[WN]{fam}[mpb]{left,right,center}[true]{%
\ifboolFT{mpb\ltxkeys@tkey}{}{%
\cptexpanded{\ltxkeys@setkeys[WN]{fam}{align=\ltxkeys@tkey}}%
}%
}
\let\ltxsetkeys\ltxkeys@setkeys
\makeatother
\begin{document}
\begin{realign}[align=left]
\lipsum[1]
\end{realign}
\begin{realign}[align=right]
\lipsum[1]
\end{realign}
\ltxsetkeys[WN]{fam}{right=true}
\ltxsetkeys[WN]{fam}{left=false}
\def\say#1{%
\cptdocommalist{#1}{%
\endgraf Key \texttt{##1} set
\ifboolTF{mpb##1}{true}{false}.
}%
}
\say{left,right,center}
\end{document}