键值参数与非键参数冲突

键值参数与非键参数冲突

许多类别提供\part、、\chapter甚至\section更深层次的嵌套分段级别。

它们都允许三种使用形式(为了简单起见,我限制为\section,它只是代表任何部分级命令的缩写):

  • \section{fooooooo} -> 简短的部分标题也将如此fooooooo
  • \section[foo]{fooooooo} -> 短节标题将仅为foo,而节标题将为fooooooo
  • \section*{foo} -> 没有目录条目并且章节计数器没有增加。

我遇到过(不仅仅是由于 TeX.SX 的问题)以下问题,有时需要重新定义的行为section,在页面上打印章节标题之前添加一些要执行的起始代码,并在之后直接添加一些代码,或者进行一些配置,否则会影响未来的代码。

其中一些任务可以通过包提供的钩子来完成,或者至少真正重写viaetoolbox的顶层代码等。section\@ifstar\@ifnextchar[

我想使用另一种方法,通过在不改变完整语法的情况下在部分的第一个可选参数中添加键值\section,比如(假设某些键已经定义......)

\section[foo,AnyKey={AnyKeyValue},AnotherKey=true]{foooooo}

这意味着将第一个论点的非关键部分和同一论点的(许多)关键部分混合在一起。

这意味着,传统的短目录条目被作为第一部分抓取,其余部分由键值包命令处理,比如说xkeyval

但是,至少在的情况下xkeyval,说法\setkeys{FamilyA}{#1}会失败,因为它会找到一个未定义的名为“foo”的“键”,并停止并显示错误消息。

一个参数中的关键值和非关键部分(无论是否可选)可以和平共处吗?

这是一个不起作用的例子,我使用虚拟命令而不是重新定义\section

\documentclass[paper=a4,12pt]{article}

\usepackage{etoolbox}
\usepackage{xkeyval}
\usepackage{xstring}% Possibly needed




\makeatletter
\define@key{FamilyA}{AnyKey}{%
\typeout{Yes!!!}
\def\AnyKeyMacro{#1}%
}%

\define@key{FamilyA}{FirstArgKey}[]{%
\def\FirstArgKeyMacro{#1}%
}%

\define@boolkey{FamilyA}{AnotherKey}[false]{%
%% not completely setup so far
}%

\makeatother



\newrobustcmd{\SomeCommand}[2][]{%
% Grabbing the non-key-argument and process it, then fill
% setkeys with the rest of it. 

%  \setkeys{FamilyA}{#1}% Fails, since xkeyval complains about a possible non-key argument part of #1
%%%%
% Rest of code, with usage of key macros etc. and #2...

}% 

\begin{document}

\SomeCommand[foo,AnyKey={This Is A Key Value},AnotherKey=true]{Another sophisticated argument}%

\end{document}

一些说明:

  • 如果没有给出键值,则重新定义的\section命令应该作为未重新定义的版本工作,除了添加的且不需要通过键进行配置的代码部分。
  • 重新定义\section语法本身不是一个选择,因为这会破坏基本上任何包/文档
  • 一个小的解决方案可能是\section[ShortSectionTitle=foo,AnyKey={...}]{foooopoo},但这也属于改变语法的范畴。也许可以捕捉这些情况
  • ,尽管如此,字符在键值环境中的特殊作用应该允许制作包含, 字符的短章节标题,如\section[{This is a short, but effective title},AnyKey={...}]

答案1

下面提供了带星号和可选参数的混合,\section并要求用于toc=<ToC entry>章节的 ToC 级条目。

在此处输入图片描述

\documentclass{article}
\usepackage[margin=1in]{geometry}% Just for this example
\usepackage{xkeyval,xparse}

\let\oldsection\section

\makeatletter
\define@cmdkey{section}[section@]{toc}[\relax]{}
\define@cmdkey{section}[section@]{AnyKey}[\relax]{}
\define@cmdkey{section}[section@]{AnotherKey}[\relax]{}

\RenewDocumentCommand{\section}{s o m}{%
  \setkeys{section}{toc,AnyKey,AnotherKey}% Set default keys
  \IfNoValueF{#2}{\setkeys{section}{#2}}% Set user-supplied keys
  \IfBooleanTF{#1}{% \section*
    \oldsection*{#3}%
    \expandafter\ifx\section@toc\relax\else\addcontentsline{toc}{section}{\protect\numberline{}\section@toc}\fi%
  }{% \section
    \expandafter\ifx\section@toc\relax
      \oldsection{#3}%
    \else
      \oldsection[\section@toc]{#3}%
    \fi    
  }%
  \expandafter\ifx\section@toc\relax\else \noindent toc: \section@toc \par\fi%
  \expandafter\ifx\section@AnyKey\relax\else \noindent AnyKey: \section@AnyKey \par\fi%
  \expandafter\ifx\section@AnotherKey\relax\else \noindent AnotherKey: \section@AnotherKey \par\fi%
}
\makeatother

\begin{document}

{\let\section\oldsection% Just for this example
\tableofcontents
}

\section[
  AnyKey     = {This Is A Key Value},
  toc        = {foo},
  AnotherKey = {true}]
  {A title}

\section*[
  AnyKey     = {Something}]
  {Another title}

\section*[
  toc        = {bar},
  AnotherKey = {Something else}]
  {A title again}

\section{Short}

\section*{Title}

\section[
  AnyKey     = {foobar},
  AnotherKey = {barfoo}]
  {Final title}

\end{document}

正如评论中提到的,使用键值方法提供 ToC 条目的优点是,您可以根据需要更改规范的顺序。但是,如果需要,\section可以更新新定义以使用类似(例如)的接口

\section*[<options>]{<title>}[<toc title>]

答案2

不是一个真正的答案,但评论太长了。KOMA 类已经在分段命令的选项参数中为键提供了语法。它通过以下之一激活headings=optiontoXXX。您可以扩展键(但您自然也必须添加 toc 和 head 的键,以避免副作用):

\documentclass[headings=optiontoheadandtoc]{scrartcl}

\makeatletter
\define@key{KOMAarg.section}{prefix}{\noindent\llap{\sectfont\size@section#1}}
\makeatother
\begin{document}
\tableofcontents

\section[tocentry=blub,head=blabla,prefix=*]{abc}

\end{document}

相关内容