summaryrefslogtreecommitdiff
path: root/macros
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2020-01-23 03:01:31 +0000
committerNorbert Preining <norbert@preining.info>2020-01-23 03:01:31 +0000
commitf7e5d81fe9880913485f7f8c541eeca7adf4c195 (patch)
tree0b41345ec70871a9cc8b6641f360f2c85ca0af22 /macros
parentbe88ab29c165e6b16091443c3e8f36c4febf8a27 (diff)
CTAN sync 202001230301
Diffstat (limited to 'macros')
-rw-r--r--macros/generic/expkv/README.md31
-rw-r--r--macros/generic/expkv/expkv.dtx1451
-rw-r--r--macros/generic/expkv/expkv.pdfbin0 -> 333595 bytes
-rw-r--r--macros/latex/contrib/caption/README2
-rw-r--r--macros/latex/contrib/caption/subcaption.dtx45
-rw-r--r--macros/latex/contrib/dashundergaps/README.md4
-rw-r--r--macros/latex/contrib/dashundergaps/changes.txt13
-rw-r--r--macros/latex/contrib/dashundergaps/dashundergaps-code.pdfbin567877 -> 597014 bytes
-rw-r--r--macros/latex/contrib/dashundergaps/dashundergaps-doc.pdfbin438978 -> 466392 bytes
-rw-r--r--macros/latex/contrib/dashundergaps/dashundergaps.dtx41
-rw-r--r--macros/latex/contrib/dashundergaps/dashundergaps.ins6
-rw-r--r--macros/latex/contrib/dashundergaps/l3doc-TUB.cls6
-rw-r--r--macros/latex/contrib/nicematrix/nicematrix-french.pdfbin317090 -> 311089 bytes
-rw-r--r--macros/latex/contrib/nicematrix/nicematrix-french.tex140
-rw-r--r--macros/latex/contrib/nicematrix/nicematrix.dtx694
-rw-r--r--macros/latex/contrib/nicematrix/nicematrix.pdfbin699309 -> 690785 bytes
-rw-r--r--macros/latex/contrib/parskip/changes.txt6
-rw-r--r--macros/latex/contrib/parskip/parskip-code.pdfbin224255 -> 223578 bytes
-rw-r--r--macros/latex/contrib/parskip/parskip.dtx6
-rw-r--r--macros/latex/contrib/parskip/parskip.ins4
-rw-r--r--macros/latex/contrib/parskip/parskip.pdfbin175252 -> 174740 bytes
-rw-r--r--macros/latex/contrib/widows-and-orphans/README.md4
-rw-r--r--macros/latex/contrib/widows-and-orphans/changes.txt6
-rw-r--r--macros/latex/contrib/widows-and-orphans/widows-and-orphans-code.pdfbin535372 -> 556802 bytes
-rw-r--r--macros/latex/contrib/widows-and-orphans/widows-and-orphans-doc.pdfbin264666 -> 292468 bytes
-rw-r--r--macros/latex/contrib/widows-and-orphans/widows-and-orphans.dtx4
-rw-r--r--macros/latex/contrib/widows-and-orphans/widows-and-orphans.ins4
27 files changed, 2102 insertions, 365 deletions
diff --git a/macros/generic/expkv/README.md b/macros/generic/expkv/README.md
new file mode 100644
index 0000000000..4401986b55
--- /dev/null
+++ b/macros/generic/expkv/README.md
@@ -0,0 +1,31 @@
+-------------------------------------------------------------------------------
+# expkv -- an expandable key=val implementation
+
+Version 2020-01-22 v0.3
+
+Released under the LaTeX Project Public License v1.3c or later
+See http://www.latex-project.org/lppl.txt
+
+Hosted at https://github.com/Skillmon/tex_expkv
+
+-------------------------------------------------------------------------------
+
+Copyright (C) 2020 Jonathan P. Spratte
+
+This work may be distributed and/or modified under the conditions of the
+LaTeX Project Public License (LPPL), either version 1.3c of this license or
+(at your option) any later version. The latest version of this license is in
+the file:
+
+ http://www.latex-project.org/lppl.txt
+
+This work is "maintained" (as per LPPL maintenance status) by
+ Jonathan P. Spratte.
+
+-------------------------------------------------------------------------------
+
+This provides an expandable key=val implementation that is somewhat fast, but
+not the fastest key=val implementation available. It is generic code and
+completely self-contained. There is a LaTeX package `expkv.sty` included to play
+nice on LaTeX's package loading system, but that package is not needed and does
+not provide more functionality than the generic code in `expkv.tex`.
diff --git a/macros/generic/expkv/expkv.dtx b/macros/generic/expkv/expkv.dtx
new file mode 100644
index 0000000000..58f8c192db
--- /dev/null
+++ b/macros/generic/expkv/expkv.dtx
@@ -0,0 +1,1451 @@
+% \iffalse meta-comment
+%
+% File: expkv.dtx Copyright (C) 2020 Jonathan P. Spratte
+%
+% This work may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this license or
+% (at your option) any later version. The latest version of this license is in
+% the file:
+%
+% http://www.latex-project.org/lppl.txt
+%
+% ------------------------------------------------------------------------------
+%
+%<*driver>^^A>>=
+\def\nameofplainTeX{plain}
+\ifx\fmtname\nameofplainTeX\else
+ \expandafter\begingroup
+\fi
+\input l3docstrip.tex
+\askforoverwritefalse
+\preamble
+
+--------------------------------------------------------------
+expkv -- an expandable key=val implementation
+E-mail: jspratte@yahoo.de
+Released under the LaTeX Project Public License v1.3c or later
+See http://www.latex-project.org/lppl.txt
+--------------------------------------------------------------
+
+Copyright (C) 2020 Jonathan P. Spratte
+
+This work may be distributed and/or modified under the conditions of the
+LaTeX Project Public License (LPPL), either version 1.3c of this license or
+(at your option) any later version. The latest version of this license is in
+the file:
+
+ http://www.latex-project.org/lppl.txt
+
+This work is "maintained" (as per LPPL maintenance status) by
+ Jonathan P. Spratte.
+
+This work consists of the file expkv.dtx
+and the derived files expkv.pdf
+ expkv.sty
+ expkv.tex
+
+\endpreamble
+% stop docstrip adding \endinput
+\postamble
+\endpostamble
+\generate{\file{expkv.sty}{\from{expkv.dtx}{pkg}}}
+\generate{\file{expkv.tex}{\from{expkv.dtx}{tex}}}
+\ifx\fmtname\nameofplainTeX
+ \expandafter\endbatchfile
+\else
+ \expandafter\endgroup
+\fi
+%
+\IfFileExists{expkv.tex}{\input{expkv.tex}}{}
+\ProvidesFile{expkv.dtx}
+ [\csname ekvDate\endcsname\ an expandable key=val implementation]
+\PassOptionsToPackage{full}{textcomp}
+\documentclass{l3doc}
+\RequirePackage[oldstylenums,nott]{kpfonts}
+\input{glyphtounicode}
+\pdfgentounicode=1
+\RequirePackage{xfp} ^^A required for an example
+\RequirePackage{listings}
+\RequirePackage{booktabs}
+\RequirePackage{siunitx}
+\RequirePackage{xcolor}
+\RequirePackage{caption}
+\RequirePackage{microtype}
+\RequirePackage{accsupp}
+\lstset
+ {
+ ,flexiblecolumns=false
+ ,basewidth=.53em
+ ,gobble=2
+ ,basicstyle=\fontfamily{jkp}\itshape
+ ,morekeywords=^^A
+ {^^A
+ \ekvdef,\ekvdefNoVal,\ekvlet,\ekvletNoVal,\ekvletkv,\ekvletkvNoVal,^^A
+ \ekvset,\ekvparse,\ekvVersion,\ekvDate,\ekvifdefined,^^A
+ \ekvifdefinedNoVal,\ekvbreak,\ekvbreakPreSneak,\ekvbreakPostSneak,^^A
+ \ekvsneak,\ekvsneakPre
+ }
+ ,morecomment=[l]\%
+ ,commentstyle=\color[gray]{0.4}
+ ,literate={\{}{{\CodeSymbol\{}}{1}
+ {\}}{{\CodeSymbol\}}}{1}
+ ^^A,literate=*{<key>}{\key}{4}{<set>}{\set}{4}
+ }
+\newcommand*\CodeSymbol[1]{\textbf{#1}}
+\RequirePackage{randtext}
+\let\metaORIG\meta
+\protected\def\meta #1{\texttt{\metaORIG{#1}}}
+\renewcommand*\thefootnote{\fnsymbol{footnote}}
+\definecolor{expkvred}{HTML}{9F393D}
+\colorlet{expkvgrey}{black!75}
+\makeatletter
+\newcommand*\expkv
+ {^^A
+ \texorpdfstring
+ {^^A
+ \mbox
+ {^^A
+ \BeginAccSupp{ActualText=expkv}^^A
+ \bfseries
+ {\color{expkvgrey}e\kern-.05em x\kern-.05em}^^A
+ \lower.493ex
+ \hbox{{\color{expkvgrey}P}\kern-.1em{\color{expkvred}k}}^^A
+ \kern-.18em{\color{expkvred}v}^^A
+ \EndAccSupp{}^^A
+ }^^A
+ }
+ {expkv}^^A
+ }
+\newcommand\kv{\meta{key}=\meta{value}}
+\newcommand\key{\meta{key}}
+\newcommand\val{\meta{value}}
+\newcommand\set{\meta{set}}
+\hypersetup{linkcolor=red!80!black,urlcolor=purple!80!black}
+\DoNotIndex{\def,\edef,\,,\=,\begingroup,\catcode,\chardef,\csname,\endcsname}
+\DoNotIndex{\endgroup,\endinput,\errmessage,\expandafter,\input,\let,\long}
+\DoNotIndex{\noexpand,\protected,\ProvidesFile,\ProvidesPackage,\relax,\space}
+\DoNotIndex{\@,\unexpanded,\string,\expanded}
+\DoNotIndex{\ifcsname}
+\DoNotIndex{\ifx}
+\DoNotIndex{\else}
+\DoNotIndex{\fi}
+\@gobble\fi ^^A ignoring \ifx and \ifcsname, but only one \fi
+\@ifdefinable\gobbledocstriptag{\def\gobbledocstriptag#1>{}}
+\newcommand*\pmso[1] ^^A poor man's strike out
+ {^^A
+ \leavevmode
+ \begingroup
+ \sbox0{#1}^^A
+ \rlap{\vrule height .6ex depth -.5ex width \wd0\relax}^^A
+ \usebox0\relax
+ \endgroup
+ }
+\makeatother
+\begin{document}
+ \title
+ {^^A
+ \texorpdfstring
+ {^^A
+ \huge
+ \href{https://github.com/Skillmon/tex_expkv}
+ {\expkv}^^A
+ \\[\medskipamount]
+ \Large an expandable \kv\ implementation^^A
+ }{expkv - an expandable <key>=<value> implementation}^^A
+ }
+ \date{\ekvDate\space v\ekvVersion}
+ \author{Jonathan P. Spratte\thanks{\protect\randomize{jspratte@yahoo.de}}}
+ \DocInput{expkv.dtx}
+\end{document}
+%</driver>^^A=<<
+% \fi
+%
+% \maketitle
+%
+% \begin{abstract}
+% \noindent\parfillskip=0pt
+% \expkv\ provides a small interface for \kv\ parsing. The parsing macro is
+% fully expandable, the \meta{code} of your keys might be not. \expkv\ is pretty
+% fast, but not the fastest available \kv\ solution (\pkg{keyval} for instance
+% is thrice as fast, but not expandable and it might strip braces it shouldn't
+% have stripped).
+% \end{abstract}
+%
+% \tableofcontents
+%
+% \begin{documentation}^^A>>=
+%
+% \section{Documentation}
+%
+% \expkv\ provides an expandable \kv\ parser. The \kv\ pairs should be given as
+% a comma separated list and the separator between a \key\ and the associated
+% \val\ should be an equal sign. Both, the commas and the equal signs, might be
+% of category 12 (other) or 13 (active). To support this is necessary as for
+% example \pkg{babel} turns characters active for some languages, for instance
+% the equal sign is turned active for Turkish.
+%
+% \expkv\ is usable as generic code or as a \LaTeX\ package. To use it, just
+% use one of:
+% \begin{lstlisting}
+% \usepackage{expkv} % LaTeX
+% \input expkv % plainTeX
+% \end{lstlisting}
+% The \LaTeX\ package doesn't do more than \file{expkv.tex}, except calling
+% |\ProvidesPackage| and setting things up such that \file{expkv.tex} will use
+% |\ProvidesFile|.
+%
+% \subsection{Setting up Keys}\label{sec:define}
+%
+% Keys in \expkv\ (as in almost all other \kv\ implementations) belong to a
+% \emph{set} such that different sets can contain keys of the same name. Unlike
+% many other implementations \expkv\ doesn't provide means to set a default
+% value, instead we have keys that take values and keys that don't (the latter
+% are called |NoVal| keys by \expkv), but both can have the same name (on the
+% user level).
+%
+% The following macros are available to define new keys. Those macros containing
+% ``|def|'' in their name can be prefixed by anything allowed to prefix |\def|,
+% prefixes allowed for |\let| can prefix those with ``|let|'' in their name,
+% accordingly. Neither \set\ nor \key\ are allowed to be empty for new keys and
+% must not contain a |\par| or tokens that expand to it -- they must be legal
+% inside of |\csname ...\endcsname|.
+%
+% \begin{function}{\ekvdef}
+% \begin{syntax}
+% \cs{ekvdef}\marg{set}\marg{key}\marg{code}
+% \end{syntax}
+% Defines a \key\ taking a value in a \set\ to expand to \meta{code}. In
+% \meta{code} you can use |#1| to refer to the given value.
+% \end{function}
+%
+% \begin{function}{\ekvdefNoVal}
+% \begin{syntax}
+% \cs{ekvdefNoVal}\marg{set}\marg{key}\marg{code}
+% \end{syntax}
+% Defines a no value taking \key\ in a \set\ to expand to \meta{code}.
+% \end{function}
+%
+% \begin{function}{\ekvlet}
+% \begin{syntax}
+% \cs{ekvlet}\marg{set}\marg{key}\meta{cs}
+% \end{syntax}
+% Let the value taking \key\ in \set\ to \meta{cs}, there are no checks on
+% \meta{cs} enforced.
+% \end{function}
+%
+% \begin{function}{\ekvletNoVal}
+% \begin{syntax}
+% \cs{ekvletNoVal}\marg{set}\marg{key}\meta{cs}
+% \end{syntax}
+% Let the no value taking \key\ in \set\ to \meta{cs}, it is not checked
+% whether \meta{cs} exists or that it takes no parameter.
+% \end{function}
+%
+% \begin{function}{\ekvletkv}
+% \begin{syntax}
+% \cs{ekvletkv}\marg{set}\marg{key}\marg{set2}\marg{key2}
+% \end{syntax}
+% Let the \key\ in \set\ to \meta{key2} in \meta{set2}, it is not checked
+% whether that second key exists.
+% \end{function}
+%
+% \begin{function}{\ekvletkvNoVal}
+% \begin{syntax}
+% \cs{ekvletkvNoVal}\marg{set}\marg{key}\marg{set2}\marg{key2}
+% \end{syntax}
+% Let the \key\ in \set\ to \meta{key2} in \meta{set2}, it is not checked
+% whether that second key exists.
+% \end{function}
+%
+% \subsection{Parsing Keys}
+%
+% \begin{function}{\ekvset}
+% \begin{syntax}
+% \cs{ekvset}\marg{set}\{\kv,\ldots\}
+% \end{syntax}
+% Splits \kv\ pairs on commas. From both \key\ and \val\ up to one space is
+% stripped from both ends, if then only a braced group remains the braces are
+% stripped as well. So |\ekvset{foo}{bar=baz}| and
+% |\ekvset{foo}{ {bar}= {baz} }| will both do
+% \texttt{\cs[no-index]{\meta{foobarcode}}\{baz\}}, so you can hide commas,
+% equal signs and spaces at the ends of either \key\ or \val\ by putting
+% braces around them. If you omit the equal sign the code of the key created
+% with the |NoVal| variants described in \autoref{sec:define} will be
+% executed. If \kv\ contains more than a single unhidden equal sign, it will
+% be split at the first one and the others are considered part of the value.
+% |\ekvset| should be nestable.
+% \end{function}
+%
+% \begin{function}{\ekvparse}
+% \begin{syntax}
+% \cs{ekvparse}\meta{cs1}\meta{cs2}\{\kv,\ldots\}
+% \end{syntax}
+% This macro parses the \kv\ pairs and provides those list elements which are
+% only keys as the argument to \meta{cs1}, and those which are a \kv\ pair to
+% \meta{cs2} as two arguments. It expands in exactly two steps of expansion.
+% |\ekvbreak| and |\ekvsneak| and their relatives don't work in |\ekvparse|.
+% It is analogue to \pkg{expl3}'s |\keyval_parse:NNn|.
+%
+% As a small example:
+% \begin{lstlisting}
+% \ekvparse\handlekey\handlekeyval{foo = bar, key, baz={zzz}}
+% \end{lstlisting}
+% would expand in exactly two steps to
+% \begin{lstlisting}
+% \handlekeyval{foo}{bar}\handlekey{key}\handlekeyval{baz}{zzz}
+% \end{lstlisting}
+% and afterwards |\handlekey| and |\handlekeyval| would have to further handle
+% the \key. There are no macros like these two contained in \expkv, you have
+% to set them up yourself if you want to use |\ekvparse| (of course the names
+% might differ).
+% \end{function}
+%
+% \subsection{Miscellaneous}
+%
+% \subsubsection{Other Macros}
+%
+% \expkv\ provides some other macros which might be of interest.
+%
+% \begin{function}{\ekvVersion,\ekvDate}
+% These two macros store the version and date of the package.
+% \end{function}
+% \begin{function}{\ekvifdefined,\ekvifdefinedNoVal}
+% \begin{syntax}
+% \cs{ekvifdefined}\marg{set}\marg{key}\marg{true}\marg{false}
+% \cs{ekvifdefinedNoVal}\marg{set}\marg{key}\marg{true}\marg{false}
+% \end{syntax}
+% These two macros test whether there is a \key\ in \set. It is false if
+% either a hash table entry doesn't exist for that key or its meaning is
+% |\relax|.
+% \end{function}
+%
+% \begin{function}{\ekvbreak,\ekvbreakPreSneak,\ekvbreakPostSneak}
+% \begin{syntax}
+% \cs{ekvbreak}\marg{after}
+% \end{syntax}
+% Gobbles the remainder of the current |\ekvset| macro and its argument list
+% and reinserts \meta{after}. So this can be used to break out of |\ekvset|.
+% The first variant will also gobble anything that has been sneaked out using
+% |\ekvsneak| or |\ekvsneakPre|, while |\ekvbreakPreSneak| will put
+% \meta{after} before anything that has been smuggled and |\ekvbreakPostSneak|
+% will put \meta{after} after the stuff that has been sneaked out.
+% \end{function}
+%
+% \begin{function}{\ekvsneak,\ekvsneakPre}
+% \begin{syntax}
+% \cs{ekvsneak}\marg{after}
+% \end{syntax}
+% Puts \meta{after} after the effects of |\ekvset|. The first variant will put
+% \meta{after} after any other tokens which might have been sneaked before,
+% while |\ekvsneakPre| will put \meta{after} before other smuggled stuff.
+% This reads and reinserts the remainder of the current |\ekvset| macro and
+% its argument list to do its job. A small usage example is shown in
+% \autoref{sec:sneakex}.
+% \end{function}
+%
+% \bigskip
+%
+% \begin{function}{\ekv@name,\ekv@name@set,\ekv@name@key}
+% \begin{syntax}
+% \cs{ekv@name}\marg{set}\marg{key}\\
+% \cs{ekv@name@set}\marg{set}\\
+% \cs{ekv@name@key}\marg{key}
+% \end{syntax}
+% The names of the macros that correspond to a key in a set are build with
+% these macros. The default definition of |\ekv@name@set| is
+% ``\texttt{\csname ekv@name@set\endcsname{\set}}'' and the default of
+% |\ekv@name@key| is ``\texttt{\csname ekv@name@key\endcsname{\key}}''.
+% The complete name is build using |\ekv@name| which is equivalent to
+% \texttt{\cs[no-index]{ekv@name@set}\marg{set}\cs{ekv@name@key}\marg{key}}.
+% For |NoVal| keys an additional |N| gets appended irrespective of these
+% macros' definition, so their name is
+% \cs[no-index]{\csname ekv@name\endcsname{\set}{\key}N}. You might redefine
+% |\ekv@name@set| and |\ekv@name@key| locally but \emph{don't redefine}
+% |\ekv@name|!
+% \end{function}
+%
+% \subsubsection{Bugs}
+%
+% Just like \pkg{keyval}, \expkv\ is bug free. But if you find \pmso{bugs}hidden
+% features\footnote{Thanks, David!} you can tell me about them either via mail
+% (see the first page) or directly on GitHub if you have an account there:
+% \url{https://github.com/Skillmon/tex_expkv}
+%
+% \subsubsection{Comparisons}
+%
+% Comparisons of speed are done with a very simple test key and the help of the
+% \pkg{l3benchmark} package. The key and its usage should be equivalent to
+% \begin{lstlisting}
+% \protected\ekvdef{test}{height}{\def\myheight{#1}}
+% \ekvset{test}{ height = 6 }
+% \end{lstlisting}
+% and only the usage of the key, not its definition, is benchmarked.
+%
+% As far as I know \expkv\ is the only fully expandable \kv\ parser. I tried to
+% compare \expkv\ to every \kv\ package listed on
+% \href{https://ctan.org/topic/keyval}{CTAN}, however, one might notice that
+% some of those are missing from this list. That's because I didn't get the
+% others to work due to bugs, or because they just provide wrappers around other
+% packages in this list. For the impatient, the essence of these comparisons
+% regarding speed and buggy behaviour is contained in \autoref{tab:comp}.
+%
+% In this subsubsection is no benchmark of |\ekvparse| and |\keyval_parse:NNn|
+% contained, as most other packages don't provide equivalent features to my
+% knowledge. |\ekvparse| is slightly faster than |\ekvset|, but keep in mind
+% that it does less. The same is true for |\keyval_parse:NNn| compared to
+% |\keys_set:nn| of \pkg{expl3} (where the difference is much bigger).
+%
+% \paragraph{\pkg{keyval}} is between two and three times faster and has a
+% comparable feature set just a slightly different way how it handles keys
+% without values. That might be considered a drawback, as it limits the
+% versatility, but also as an advantage, as it might reduce doubled code. Keep
+% in mind that as soon as someone loads \pkg{xkeyval} the performance of
+% \pkg{keyval} gets replaced by \pkg{xkeyval}'s.
+%
+% Also \pkg{keyval} has a bug, which unfortunately can't really be resolved
+% without breaking backwards compatibility for \emph{many} documents, namely it
+% strips braces from the argument before stripping spaces if the argument isn't
+% surrounded by spaces, also it might strip more than one set of braces. Hence
+% all of the following are equivalent in their outcome, though the last two
+% lines should result in something different than the first two:
+% \begin{lstlisting}[belowskip=0pt]
+% \setkeys{foo}{bar=baz}
+% \setkeys{foo}{bar= {baz}}
+% \setkeys{foo}{bar={ baz}}
+% \setkeys{foo}{bar={{baz}}}
+% \end{lstlisting}
+%
+% \paragraph{\pkg{xkeyval}} is more than ten times slower, but it provides more
+% functionality, e.g., it has choice keys, boolean keys, and so on. It contains
+% the same bug as \pkg{keyval} as it has to be compatible with it by design (it
+% replaces \pkg{keyval}'s frontend), but also adds even more cases in which
+% braces are stripped that shouldn't be stripped, worsening the situation.
+%
+% \paragraph{\pkg{ltxkeys}} is over 200 times slower -- which is funny, because
+% it aims to be ``[\ldots] faster than these earlier packages [referring to
+% \pkg{keyval} and \pkg{xkeyval}].'' Since it aims to have a bigger feature set
+% than \pkg{xkeyval}, it most definitely also has a bigger feature set than
+% \expkv. Also, it can't parse |\long| input, so as soon as your values contain
+% a |\par|, it'll throw errors. Furthermore, \pkg{ltxkeys} doesn't strip outer
+% braces at all by design, which, imho, is a weird design choice. In addition
+% \pkg{ltxkeys} loads \pkg{catoptions} which is known to introduce bugs (e.g.,
+% see \url{https://tex.stackexchange.com/questions/461783}).
+%
+% \paragraph{\pkg{l3keys}} is at least three times slower, but has an, imho,
+% great interface to define keys. It strips \emph{all} outer spaces, even if
+% somehow multiple spaces ended up on either end. It offers more features, but
+% is pretty much bound to \pkg{expl3} code. Whether that's a drawback is up to
+% you.
+%
+% \paragraph{\pkg{pgfkeys}} is about one and a half times slower for one key,
+% but has an \emph{enormous} feature set. However, since adding additional keys
+% doesn't add as much needed time for \pkg{pgfkeys} compared to \expkv, it gets
+% faster than \expkv\ at around eight \kv\ pairs.
+% It has the same or a very similar bug \pkg{keyval} has. The brace bug (and
+% also the category fragility) can be fixed by \pkg{pgfkeyx}, but this package
+% was last updated in 2012 and it slows down |\pgfkeys| by factor~$8$. Also I
+% don't know whether this might introduce new bugs.
+%
+% \paragraph{\pkg{kvsetkeys} with \pkg{kvdefinekeys}} is about two times slower,
+% but it works even if commas and equals have category codes different from 12.
+% Else the features of the keys are equal to those of \pkg{keyval}, the parser
+% has more features, though.
+%
+% \paragraph{\pkg{options}} is a bit faster than \expkv\ (almost
+% \SI{10}{\percent}) and has a much bigger feature set. Unfortunately it also
+% suffers from the premature unbracing bug \pkg{keyval} has.
+%
+% \paragraph{\pkg{simplekv}} is hard to compare because I don't speak French (so
+% I don't understand the documentation) and from what I can see, there is no
+% direct way to define the equivalent test key. Nevertheless, I tested the
+% closest possible equivalent of my test key while siding for \pkg{simplekv}'s
+% design not forcing something into it it doesn't seem to be designed for. It is
+% more than four times slower and has hard to predict behaviour regarding brace
+% and space stripping, similar to \pkg{keyval}. The tested definition was:
+% \begin{lstlisting}[belowskip=0pt]
+% \usepackage{simplekv}
+% \setKVdefault[simplekv]{height={ abc}} % key setup
+% \setKV[simplekv]{ height = 6 } % benchmarked
+% \end{lstlisting}
+%
+% \paragraph{\pkg{yax}} is about 13 times slower. It has a pretty strange
+% syntax, imho, and again a direct equivalent is hard to define. It has the
+% premature unbracing bug, too. Also somehow loading \pkg{yax} broke
+% \pkg{options} for me. The tested definition was:
+% \begin{lstlisting}[belowskip=0pt]
+% \usepackage{yax}
+% \defactiveparameter yax {\storevalue\myheight yax:height } % key setup
+% \setparameterlist{yax}{ height = 6 } % benchmarked
+% \end{lstlisting}
+%
+% \begin{table}
+% \def\fnsym{\textcolor{red!80!black}{*}}
+% \begingroup
+% \centering
+% \newcommand*\yes{\textcolor{red!80!black} {yes}}^^A
+% \newcommand*\no {\textcolor{green!80!black}{no}}^^A
+% \caption[Comparison of \kv\ packages]
+% {^^A
+% Comparison of \kv\ packages. The packages are ordered from
+% fastest to slowest for one \kv\ pair. Benchmarking was done using
+% \pkg{l3benchmark} and the scripts in the \file{Benchmarks} folder
+% of the \href{https://github.com/Skillmon/tex_expkv}{git repository}.
+% The columns $p_i$ are the polynomial coefficients of a linear fit to the
+% run-time, $p_0$ can be interpreted as the overhead for initialisation
+% and $p_1$ the cost per key. The column ``Category Fragile'' lists
+% whether the parsing breaks with active commas or equal signs.^^A
+% \label{tab:comp}^^A
+% }
+% \begin{tabular}{l*2{S[table-format=4.3]}ccc}
+% \toprule
+% Package & {$p_1$} & {$p_0$} & Brace-Bug & Category Fragile & Date \\
+% \midrule
+% \pkg{keyval} & 13.415 & 2.229 & \yes & \yes & 2014-10-28 \\
+% \pkg{options} & 25.254 & 12.160 & \yes & \yes & 2015-03-01 \\
+% \expkv & 31.711 & 5.124 & \no & \no & 2020-01-15 \\
+% \pkg{pgfkeys} & 26.215 & 43.141 & \yes & \yes & 2020-01-08 \\
+% \pkg{kvsetkeys} & {\fnsym} & {\fnsym} & \no & \no & 2019-12-15 \\
+% \pkg{l3keys} & 107.434 & 23.372 & \no & \no & 2020-01-12 \\
+% \pkg{simplekv} & 162.046 & 1.014 & \yes & \yes & 2017-08-08 \\
+% \pkg{xkeyval} & 258.505 & 168.761 & \yes & \yes & 2014-12-03 \\
+% \pkg{yax} & 510.662 & 37.961 & \yes & \yes & 2010-01-22 \\
+% \pkg{ltxkeys} & 3937.979 & 4512.835 & \no & \no & 2012-11-17 \\
+% \bottomrule
+% \end{tabular}
+% \par
+% \endgroup
+% \medskip
+% \fnsym For \pkg{kvsetkeys} the linear model used for the other
+% packages is a poor fit, \pkg{kvsetkeys} seems to have approximately
+% quadratic run-time, the coefficients of the second degree polynomial fit are
+% $p_2=\num{9.653}$, $p_1=\num{40.896}$, and $p_0=\num{67.268}$. Of course the
+% other packages might not really have linear run-time, but at least from 1~to
+% 20~keys the fits don't seem too bad (the maximum ratio $p_2/p_1$
+% for the other packages is \num{8.987e-3}). If one extrapolates the fits
+% for 100 \kv\ pairs one finds that most of them match pretty well, the
+% exception being \pkg{ltxkeys}, which behaves quadratic as well with
+% $p_2=\num{29.773}$, $p_1=\num{3312.744}$, and $p_0=\num{6805.363}$.
+% \end{table}
+%
+% \subsection{Examples}
+%
+% \subsubsection{Standard Use-Case}
+%
+% Say we have a macro for which we want to create a \kv\ interface. The macro
+% has a parameter, which is stored in the dimension |\ourdim| having a default
+% value from its initialization. Now we want to be able to change that dimension
+% with the |width| key to some specified value. For that we'd do
+% \begin{lstlisting}
+% \newdimen\ourdim
+% \ourdim=150pt
+% \protected\ekvdef{our}{width}{\ourdim=#1\relax}
+% \end{lstlisting}
+% as you can see, we use the set |our| here. We want the key to behave different
+% if no value is specified. In that case the key should not use the its initial
+% value, but be smart and determine the available space from
+% \cs[no-index]{hsize}, so we also define
+% \begin{lstlisting}
+% \protected\ekvdefNoVal{our}{width}{\ourdim=.9\hsize}
+% \end{lstlisting}
+% Now we set up our macro to use this \kv\ interface
+% \begin{lstlisting}
+% \protected\def\ourmacro#1{\begingroup\ekvset{our}{#1}\the\ourdim\endgroup}
+% \end{lstlisting}
+% Finally we can use our macro like in the following\\
+% \begin{minipage}{6cm}
+% \begin{lstlisting}
+% \ourmacro{}\par
+% \ourmacro{width}\par
+% \ourmacro{width=5pt}\par
+% \end{lstlisting}
+% \end{minipage}^^A
+% \begin{minipage}{\dimexpr\linewidth-6cm\relax}
+% \newdimen\ourdim\ourdim=150pt
+% \protected\ekvdef{our}{width}{\ourdim=#1\relax}^^A
+% \protected\ekvdefNoVal{our}{width}{\ourdim=.9\hsize}^^A
+% \protected\def\ourmacro#1^^A
+% {\begingroup\ekvset{our}{#1}\the\ourdim\endgroup}^^A
+% \ourmacro{}\par
+% \ourmacro{width}\par
+% \ourmacro{width=5pt}\par
+% \end{minipage}
+%
+% \subsubsection{An Expandable \kv\ Macro Using \cs[no-index]{ekvsneak}}
+% \label{sec:sneakex}
+%
+% Let's set up an expandable macro, that uses a \kv\ interface. The problems
+% we'll face for this are:
+% \begin{enumerate}
+% \item ignoring duplicate keys
+% \item default values for keys which weren't used
+% \item providing the values as the correct argument to a macro (ordered)
+% \end{enumerate}
+%
+% First we need to decide which \kv\ parsing macro we want to do this with,
+% |\ekvset| or |\ekvparse|. For this example we also want to show the
+% usage of |\ekvsneak|, hence we'll choose |\ekvset|. And we'll have to use
+% |\ekvset| such that it builds a parsable list for our macro internals. To
+% gain back control after |\ekvset| is done we have to put an internal of our
+% macro at the start of that list, so we use an internal key that uses
+% |\ekvsneakPre| after any user input.
+%
+% To ignore duplicates will be easy if the value of the key used last will be
+% put first in the list, so the following will use |\ekvsneakPre| for the
+% user-level keys. If we wanted some key for which the first usage should be the
+% the binding one we would use |\ekvsneak| instead for that key.
+%
+% Providing default values can be done in different ways, we'll use a simple
+% approach in which we'll just put the outcome of our keys if they were used
+% with default values before the parsing list terminator.
+%
+% Ordering the keys can be done simply by searching for a specific token for
+% each argument which acts like a flag, so our sneaked out values will include
+% specific tokens acting as markers.
+%
+% Now that we have answers for our technical problems, we have to decide what
+% our example macro should do. How about we define a macro that calculates the
+% sine of a number and rounds that to a specified precision? As a small extra
+% this macro should understand input in radian and degree and the used
+% trigonometric function should be selectable as well. For the hard part of this
+% task (expandably evaluating trigonometric functions) we'll use the \pkg{xfp}
+% package.
+%
+% First we set up our keys according to our earlier considerations and set up
+% the user facing macro |\sine|. The end marker of the parsing list will be a
+% |\sine@stop| token, which we don't need to define and we put our defaults
+% right before it.
+%
+% \begin{lstlisting}
+% \RequirePackage{xfp}
+% \makeatletter
+% \ekvdef{expex}{f}{\ekvsneakPre{\f{#1}}}
+% \ekvdef{expex}{round}{\ekvsneakPre{\rnd{#1}}}
+% \ekvdefNoVal{expex}{degree}{\ekvsneakPre{\deg{d}}}
+% \ekvdefNoVal{expex}{radian}{\ekvsneakPre{\deg{}}}
+% \ekvdefNoVal{expex}{internal}{\ekvsneakPre{\sine@rnd}}
+% \newcommand*\sine[2]
+% {\ekvset{expex}{#1,internal}\rnd{3}\deg{d}\f{sin}\sine@stop{#2}}
+% \end{lstlisting}
+% For the sake of simplicity we defined the macro |\sine| with two mandatory
+% arguments, the first being the \kv\ list, the second the argument to the
+% trigonometric function. We could've used \pkg{xparse}'s facilities here to
+% define an expandable macro which takes an optional argument instead.
+%
+% Now we need to define some internal macros to extract the value of each key's
+% last usage (remember that this will be the group after the first special
+% flag-token). For that we use one delimited macro per key.
+% \begin{lstlisting}
+% \def\sine@rnd#1\rnd#2#3\sine@stop{\sine@deg#1#3\sine@stop{#2}}
+% \def\sine@deg#1\deg#2#3\sine@stop{\sine@f#1#3\sine@stop{#2}}
+% \def\sine@f#1\f#2#3\sine@stop{\sine@final{#2}}
+% \end{lstlisting}
+% After the macros |\sine@rnd|, |\sine@deg|, and |\sine@f| the macro
+% |\sine@final| will see
+% \texttt
+% {^^A
+% \cs[no-index]{sine@final}^^A
+% \marg{f}\marg{degree/radian}\marg{round}\marg{num}^^A
+% }.
+% Now |\sine@final| has to expandably deal with those arguments such that the
+% |\fpeval| macro of \pkg{xfp} gets the correct input. Luckily this is pretty
+% straight forward in this example. In |\fpeval| the trigonometric functions
+% have names such as |sin| or |cos| and the degree taking variants |sind| or
+% |cosd|. And since the |degree| key puts a |d| in |#2| and the |radian| key
+% leaves |#2| empty all we have to do to get the correct function name is stick
+% the two together.
+% \begin{lstlisting}
+% \newcommand*\sine@final[4]{\fpeval{round(#1#2(#4),#3)}}
+% \makeatother
+% \end{lstlisting}
+% Let's test our macro:\\
+% \begin{minipage}{.7\linewidth}
+% \begin{lstlisting}[gobble=4]
+% \sine{}{60}\par
+% \sine{round=10}{60}\par
+% \sine{f=cos,radian}{pi}\par
+% \edef\myval{\sine{f=tan}{1}}\texttt{\meaning\myval}
+% \end{lstlisting}
+% \end{minipage}\hfill
+% \begin{minipage}{.2\linewidth}
+% \makeatletter
+% \ekvdef{expex}{f}{\ekvsneakPre{\f{#1}}}^^A
+% \ekvdef{expex}{round}{\ekvsneakPre{\rnd{#1}}}^^A
+% \ekvdefNoVal{expex}{degree}{\ekvsneakPre{\deg{d}}}^^A
+% \ekvdefNoVal{expex}{radian}{\ekvsneakPre{\deg{}}}^^A
+% \ekvdefNoVal{expex}{internal}{\ekvsneakPre{\sine@rnd}}^^A
+% \newcommand*\sine[2]
+% {\ekvset{expex}{#1,internal}\rnd{3}\deg{d}\f{sin}\sine@stop{#2}}^^A
+% \def\sine@rnd#1\rnd#2#3\sine@stop{\sine@deg#1#3\sine@stop{#2}}^^A
+% \def\sine@deg#1\deg#2#3\sine@stop{\sine@f#1#3\sine@stop{#2}}^^A
+% \def\sine@f#1\f#2#3\sine@stop{\sine@final{#2}}^^A
+% \newcommand*\sine@final[4]{\fpeval{round(#1#2(#4),#3)}}^^A
+% \makeatother
+% \sine{}{60}\par
+% \sine{round=10}{60}\par
+% \sine{f=cos,radian}{pi}\par
+% \edef\myval{\sine{f=tan}{1}}\texttt{\meaning\myval}
+% \end{minipage}
+%
+%
+% \subsection{Error Messages}
+%
+% \expkv\ should only send messages in case of errors, there are no warnings and
+% no info messages. In this subsection those errors are listed.
+%
+% \subsubsection{Load Time}
+%
+% \file{expkv.tex} checks whether \eTeX\ is available. If it isn't, an error
+% will be thrown using |\errmessage|:
+% \begin{lstlisting}
+% ! expkv Error: e-TeX required.
+% \end{lstlisting}
+%
+% \subsubsection{Defining Keys}
+%
+% If you get any error from \expkv\ while you're trying to define a key, the
+% definition will be aborted and gobbled.
+%
+% If you try to define a key with an empty set name you'll get:
+% \begin{lstlisting}
+% ! expkv Error: empty set name not allowed.
+% \end{lstlisting}
+%
+% Similarly, if you try to define a key with an empty key name:
+% \begin{lstlisting}
+% ! expkv Error: empty key name not allowed.
+% \end{lstlisting}
+%
+% Both of these messages are done in a way that doesn't throw additional errors
+% due to |\global|, |\long|, etc., not being used correctly if you prefixed one
+% of the defining macros.
+%
+% \subsubsection{Using Keys}
+%
+% This subsubsection contains the errors thrown during |\ekvset|. The errors are
+% thrown in an expandable manner by providing an undefined macro. In the
+% following messages \lstinline|<key>| gets replaced with the problematic key's
+% name, and \lstinline|<set>| with the corresponding set. If any errors during
+% \kv\ handling are encountered, the entry in the comma separated list will be
+% omitted after the error is thrown and the next \kv\ pair will be parsed.
+%
+% If you're using an undefined key you'll get:
+% \begin{lstlisting}
+% ! Undefined control sequence.
+% <argument> \! expkv Error:
+% unknown key (`<key>', set `<set>').
+% \end{lstlisting}
+%
+% If you're using a key for which only a normal version and no |NoVal| version
+% is defined, but don't provide a value, you'll get:
+% \begin{lstlisting}
+% ! Undefined control sequence.
+% <argument> \! expkv Error:
+% value required (`<key>', set `<set>').
+% \end{lstlisting}
+%
+% If you're using a key for which only a |NoVal| version and no normal version
+% is defined, but provide a value, you'll get:
+% \begin{lstlisting}
+% ! Undefined control sequence.
+% <argument> \! expkv Error:
+% value forbidden (`<key>', set `<set>').
+% \end{lstlisting}
+%
+% If you're using a set for which you never executed one of the defining macros
+% from \autoref{sec:define} you'll get a low level \TeX\ error, as that isn't
+% actively tested by the parser (and hence will lead to undefined behaviour and
+% not be gracefully ignored). The error will look like
+% \begin{lstlisting}
+% ! Missing \endcsname inserted.
+% <to be read again>
+% \ekv<set>(
+% \end{lstlisting}
+%
+% \subsection{License}
+%
+% Copyright \textcopyright\ 2020\unless\ifnum\year=2020--\the\year\fi\
+% Jonathan P. Spratte
+%
+% \medskip\noindent
+% This work may be distributed and/or modified under the conditions of the
+% \LaTeX\ Project Public License (LPPL), either version 1.3c of this license or
+% (at your option) any later version. The latest version of this license is in
+% the file:
+%
+% \url{http://www.latex-project.org/lppl.txt}
+%
+% \noindent
+% This work is ``maintained'' (as per LPPL maintenance status) by
+%
+% \mbox{Jonathan P. Spratte}.
+%
+% \end{documentation}^^A=<<
+%
+% \begin{implementation}^^A>>=
+%
+% \clearpage
+%
+% \section{Implementation}^^A>>=
+%^^A the LaTeX package >>=
+% \subsection{The \LaTeX\ Package}
+% First we set up the \LaTeX\ package. That one doesn't really do much except
+% |\input|ting the generic code and identifying itself as a package.
+% \gobbledocstriptag
+%<*pkg>
+% \begin{macrocode}
+\def\ekv@tmp
+ {%
+ \ProvidesFile{expkv.tex}%
+ [\ekvDate\space v\ekvVersion\space an expandable key=val implementation]%
+ }
+\input{expkv.tex}
+\ProvidesPackage{expkv}%
+ [\ekvDate\space v\ekvVersion\space an expandable key=val implementation]
+% \end{macrocode}
+% \gobbledocstriptag
+%</pkg>
+%^^A=<<
+%^^A main file >>=
+% \subsection{The Generic Code}
+% The rest of this implementation will be the generic code.
+% \gobbledocstriptag
+%<*tex>
+%
+% Check whether \eTeX\ is available -- \expkv\ requires \eTeX.
+% \begin{macrocode}
+\begingroup\expandafter\expandafter\expandafter\endgroup
+\expandafter\ifx\csname numexpr\endcsname\relax
+ \errmessage{expkv requires e-TeX}
+ \expandafter\endinput
+\fi
+% \end{macrocode}
+%
+% We make sure that it's only input once:
+% \begin{macrocode}
+\expandafter\ifx\csname ekvVersion\endcsname\relax
+\else
+ \expandafter\endinput
+\fi
+% \end{macrocode}
+% \begin{macro}{\ekvVersion,\ekvDate}
+% We're on our first input, so lets store the version and date in a macro.
+% \begin{macrocode}
+\def\ekvVersion{0.3}
+\def\ekvDate{2020-01-22}
+% \end{macrocode}
+% \end{macro}
+%
+% If the \LaTeX\ format is loaded we want to be a good file and report back who
+% we are, for this the package will have defined |\ekv@tmp| to use
+% |\ProvidesFile|, else this will expand to a |\relax| and do no harm.
+% \begin{macrocode}
+\csname ekv@tmp\endcsname
+% \end{macrocode}
+%
+% Store the category code of |@| to later be able to reset it and change it to
+% 11.
+% \begin{macrocode}
+\expandafter\chardef\csname ekv@tmp\endcsname=\catcode`\@
+\catcode`\@=11
+% \end{macrocode}
+% |\ekv@tmp| might later be reused to gobble any prefixes which might be
+% provided to |\ekvdef| and similar in case the names are invalid, we just
+% temporarily use it here as means to store the current category code of |@| to
+% restore it at the end of the file, we never care for the actual definition of
+% it.
+%
+% \begin{macro}
+% {
+% \@gobble,\@firstofone,\@firstoftwo,\@secondoftwo,
+% \ekv@gobbletostop,\ekv@fi@gobble,\ekv@fi@secondoftwo
+% }
+% Since branching tests are often more versatile than |\if...\else...\fi|
+% constructs, we define helpers that are branching pretty fast. Also here are
+% some other utility functions that just grab some tokens. The ones that are
+% also contained in \LaTeX\ don't use the |ekv| prefix.
+% \begin{macrocode}
+\long\def\@gobble#1{}
+\long\def\@firstofone#1{#1}
+\long\def\@firstoftwo#1#2{#1}
+\long\def\@secondoftwo#1#2{#2}
+\long\def\ekv@gobbletostop#1\ekv@stop{}
+\long\def\ekv@fi@gobble\fi\@firstofone#1{\fi}
+\long\def\ekv@fi@secondoftwo\fi\@firstoftwo#1#2{\fi#2}
+% \end{macrocode}
+% \end{macro}
+% As you can see |\ekv@gobbletostop| uses a special marker |\ekv@stop|. The
+% package will use three such markers, the one you've seen already, |\ekv@mark|
+% and |\ekv@nil|. Contrarily to how for instance \pkg{expl3} does things, we
+% don't define them, as we don't need them to have an actual meaning. This has
+% the advantage that if they somehow get expanded -- which should never happen
+% if things work out -- they'll throw an error directly.
+%
+% \begin{macro}
+% {
+% \ekv@ifempty,\ekv@ifempty@,\ekv@ifempty@true,\ekv@ifempty@false,
+% \ekv@ifempty@true@F
+% }
+% We can test for a lot of things building on an if-empty test, so lets define a
+% really fast one. Since some tests might have reversed logic (true if something
+% is not empty) we also set up macros for the reversed branches.
+% \begin{macrocode}
+\long\def\ekv@ifempty#1%
+ {%
+ \ekv@ifempty@\ekv@ifempty@A#1\ekv@ifempty@B\ekv@ifempty@true
+ \ekv@ifempty@A\ekv@ifempty@B\@secondoftwo
+ }
+\long\def\ekv@ifempty@#1\ekv@ifempty@A\ekv@ifempty@B{}
+\long\def\ekv@ifempty@true\ekv@ifempty@A\ekv@ifempty@B\@secondoftwo#1#2{#1}
+\long\def\ekv@ifempty@false\ekv@ifempty@A\ekv@ifempty@B\@firstoftwo#1#2{#2}
+\long\def\ekv@ifempty@true@F\ekv@ifempty@A\ekv@ifempty@B\@firstofone#1{}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekv@ifblank@}
+% The obvious test that can be based on an if-empty is if-blank, meaning a test
+% checking whether the argument is empty or consists only of spaces. Our version
+% here will be tweaked a bit, as we want to check this, but with one leading
+% |\ekv@mark| token that is to be ignored.
+% \begin{macrocode}
+\long\def\ekv@ifblank@\ekv@mark#1{\ekv@ifempty@\ekv@ifempty@A}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekv@ifdefined}
+% We'll need to check whether something is defined quite frequently, so why not
+% define a macro that does this. The following test is expandable, slower than
+% the typical expandable test for undefined control sequences, but faster for
+% defined ones. Since we want to be as fast as possible for correct input, this
+% is to be preferred.
+% \begin{macrocode}
+\def\ekv@ifdefined#1%
+ {%
+ \expandafter
+ \ifx\csname\ifcsname #1\endcsname #1\else relax\fi\endcsname\relax
+ \ekv@fi@secondoftwo
+ \fi
+ \@firstoftwo
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}
+% {
+% \ekv@ifdefined@pair,\ekv@ifdefined@pair@,\ekv@ifdefined@key,
+% \ekv@ifdefined@key@
+% }
+% Since we can save some time if we only have to create the control sequence
+% once when we know beforehand how we want to use it, we build some other macros
+% for those cases (which we'll have quite often, once per key usage).
+% \begin{macrocode}
+\def\ekv@ifdefined@pair#1#2%
+ {%
+ \expandafter\ekv@ifdefined@pair@
+ \csname
+ \ifcsname #1{#2}\endcsname
+ #1{#2}%
+ \else
+ relax%
+ \fi
+ \endcsname
+ }
+\def\ekv@ifdefined@pair@#1%
+ {%
+ \ifx#1\relax
+ \ekv@fi@secondoftwo
+ \fi
+ \@firstoftwo
+ {\ekv@set@pair@#1\ekv@mark}%
+ }
+\def\ekv@ifdefined@key#1#2%
+ {%
+ \expandafter\ekv@ifdefined@key@
+ \csname
+ \ifcsname #1{#2}N\endcsname
+ #1{#2}N%
+ \else
+ relax%
+ \fi
+ \endcsname
+ }
+\def\ekv@ifdefined@key@#1%
+ {%
+ \ifx#1\relax
+ \ekv@fi@secondoftwo
+ \fi
+ \@firstoftwo#1%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekv@name,\ekv@name@set,\ekv@name@key}
+% The keys will all follow the same naming scheme, so we define it here.
+% \begin{macrocode}
+\def\ekv@name#1#2{\ekv@name@set{#1}\ekv@name@key{#2}}
+\def\ekv@name@set#1{ekv#1(}
+\def\ekv@name@key#1{#1)}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\ekv@checkvalid}
+% We place some restrictions on the allowed names, though, namely sets and
+% keys are not allowed to be empty -- blanks are fine (meaning \mbox{set-
+% or} key-names consisting of spaces).
+% \begin{macrocode}
+\protected\def\ekv@checkvalid#1#2%
+ {%
+ \ekv@ifempty{#1}%
+ {%
+ \def\ekv@tmp{}%
+ \errmessage{expkv Error: empty set name not allowed}%
+ }%
+ {%
+ \ekv@ifempty{#2}%
+ {%
+ \def\ekv@tmp{}%
+ \errmessage{expkv Error: empty key name not allowed}%
+ }%
+ \@secondoftwo
+ }%
+ \@gobble
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\ekvifdefined,\ekvifdefinedNoVal}
+% And provide user-level macros to test whether a key is defined.
+% \begin{macrocode}
+\def\ekvifdefined#1#2{\ekv@ifdefined{\ekv@name{#1}{#2}}}
+\def\ekvifdefinedNoVal#1#2{\ekv@ifdefined{\ekv@name{#1}{#2}N}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \ekvdef,\ekvdefNoVal,\ekvlet,\ekvletNoVal,\ekvletkv,\ekvletkvNoVal,
+% \ekv@defset
+% }
+% Set up the key defining macros |\ekvdef| etc.
+% \begin{macrocode}
+\protected\long\def\ekvdef#1#2#3%
+ {%
+ \ekv@checkvalid{#1}{#2}%
+ {%
+ \expandafter\def\csname\ekv@name{#1}{#2}\endcsname##1{#3}%
+ \ekv@defset{#1}%
+ }%
+ }
+\protected\long\def\ekvdefNoVal#1#2#3%
+ {%
+ \ekv@checkvalid{#1}{#2}%
+ {%
+ \expandafter\def\csname\ekv@name{#1}{#2}N\endcsname{#3}%
+ \ekv@defset{#1}%
+ }%
+ }
+\protected\def\ekvlet#1#2#3%
+ {%
+ \ekv@checkvalid{#1}{#2}%
+ {%
+ \expandafter\let\csname\ekv@name{#1}{#2}\endcsname#3%
+ \ekv@defset{#1}%
+ }%
+ }
+\protected\def\ekvletNoVal#1#2#3%
+ {%
+ \ekv@checkvalid{#1}{#2}%
+ {%
+ \expandafter\let\csname\ekv@name{#1}{#2}N\endcsname#3%
+ \ekv@defset{#1}%
+ }%
+ }
+\protected\def\ekvletkv#1#2#3#4%
+ {%
+ \ekv@checkvalid{#1}{#2}%
+ {%
+ \expandafter\let\csname\ekv@name{#1}{#2}\expandafter\endcsname
+ \csname\ekv@name{#3}{#4}\endcsname
+ \ekv@defset{#1}%
+ }%
+ }
+\protected\def\ekvletkvNoVal#1#2#3#4%
+ {%
+ \ekv@checkvalid{#1}{#2}%
+ {%
+ \expandafter\let\csname\ekv@name{#1}{#2}N\expandafter\endcsname
+ \csname\ekv@name{#3}{#4}N\endcsname
+ \ekv@defset{#1}%
+ }%
+ }
+\protected\def\ekv@defset#1%
+ {%
+ \expandafter\edef\csname\ekv@name@set{#1}\endcsname##1%
+ {\ekv@name@set{#1}\ekv@name@key{##1}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvset}
+% Set up |\ekvset|, which should not be affected by active commas and equal
+% signs. The equal signs are a bit harder to cope with and we'll do that later,
+% but replacing the active commas with commas of category other can be done
+% beforehand. That's why we define |\ekvset| here with a temporary meaning just
+% to set up the things with two different category codes. |#1| will be a
+% \texttt{,\textsubscript{13}} and |#2| will be a \texttt{=\textsubscript{13}}.
+% \begin{macrocode}
+\def\ekvset#1#2{%
+\endgroup
+\long\def\ekvset##1##2%
+ {%
+ \expandafter\ekv@set\csname\ekv@name@set{##1}\endcsname
+ \ekv@mark##2#1\ekv@stop#1{}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\ekv@set}
+% |\ekv@set| will split the \kv\ list at active commas. Then it has to check
+% whether there were unprotected other commas and resplit there.
+% \begin{macrocode}
+\long\def\ekv@set##1##2#1%
+ {%
+% \end{macrocode}
+% Test whether we're at the end, if so invoke |\ekv@endset|,
+% \begin{macrocode}
+ \ekv@ifstop##2\ekv@endset\ekv@mark\ekv@stop
+% \end{macrocode}
+% else go on with other commas,
+% \begin{macrocode}
+ \ekv@set@other##1##2,\ekv@stop,%
+% \end{macrocode}
+% and get the next active comma delimited \kv\ pair.
+% \begin{macrocode}
+ \ekv@set##1\ekv@mark
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\ekv@endset}
+% |\ekv@endset| is a hungry little macro. It will eat everything that remains
+% of |\ekv@set| and unbrace the sneaked stuff.
+% \begin{macrocode}
+\long\def\ekv@endset
+ \ekv@mark\ekv@stop\ekv@set@other##1,\ekv@stop,\ekv@set##2\ekv@mark
+ ##3%
+ {##3}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\ekv@set@other}
+% The macro |\ekv@set@other| is guaranteed to get only single \kv\ pairs.
+% So here we need to split at equal signs. If there is no equal sign, we need to
+% test whether we're done and if not this is a |NoVal| key.
+% \begin{macrocode}
+\long\def\ekv@set@other##1##2,%
+ {%
+ \ekv@ifblank@##2\ekv@nil\ekv@ifempty@B\ekv@ifempty@true@F
+ \ekv@ifempty@A\ekv@ifempty@B\@firstofone
+ {%
+ \ekv@ifhas@eq@other##2=\ekv@ifempty@B\ekv@ifempty@false
+ \ekv@ifempty@A\ekv@ifempty@B\@firstoftwo
+ {\ekv@set@eq@other##1##2\ekv@stop}%
+ {%
+ \ekv@ifhas@eq@active##2#2\ekv@ifempty@B\ekv@ifempty@false
+ \ekv@ifempty@A\ekv@ifempty@B\@firstoftwo
+ {\ekv@set@eq@active##1##2\ekv@stop}%
+ {%
+ \ekv@ifstop##2\ekv@endset@other\ekv@mark\ekv@stop
+ \ekv@strip{##2}\ekv@set@key##1%
+ }%
+ }%
+ }%
+ \ekv@set@other##1\ekv@mark%
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\ekv@set@eq@other}
+% |\ekv@set@eq@other| might not be the correct break point, there might be an
+% active equal sign in the currently parsed key-name. If so, we have to resplit.
+% \begin{macrocode}
+\long\def\ekv@set@eq@other##1##2=%
+ {%
+ \ekv@ifhas@eq@active##2#2\ekv@ifempty@B\ekv@ifempty@false
+ \ekv@ifempty@A\ekv@ifempty@B\@firstoftwo
+ {\ekv@set@eq@active##1##2=}%
+ {\ekv@strip{##2}\ekv@set@pair##1}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\ekv@set@eq@active}
+% We need to handle the active equal signs.
+% \begin{macrocode}
+\long\def\ekv@set@eq@active##1##2#2%
+ {%
+ \ekv@strip{##2}\ekv@set@pair##1%
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\ekv@ifhas@eq@other,\ekv@ifhas@eq@active,\ekv@endset@other}
+% And we have to set up the testing macros for our equal signs and
+% |\ekv@endset@other|.
+% \begin{macrocode}
+\long\def\ekv@ifhas@eq@other\ekv@mark##1={\ekv@ifempty@\ekv@ifempty@A}
+\long\def\ekv@ifhas@eq@active\ekv@mark##1#2{\ekv@ifempty@\ekv@ifempty@A}
+\long\def\ekv@endset@other
+ \ekv@mark\ekv@stop\ekv@strip##1\ekv@set@key##2%
+ \ekv@set@other##3\ekv@mark
+ {}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\ekvbreak,\ekvbreakPreSneak,\ekvbreakPostSneak}
+% Provide macros that can completely stop the parsing of |\ekvset|, who knows
+% what it'll be useful for.
+% \begin{macrocode}
+\long\def\ekvbreak##1##2\ekv@stop#1##3{##1}
+\long\def\ekvbreakPreSneak ##1##2\ekv@stop#1##3{##1##3}
+\long\def\ekvbreakPostSneak##1##2\ekv@stop#1##3{##3##1}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\ekvsneak,\ekvsneakPre}
+% One last thing we want to do for |\ekvset| is to provide macros that just
+% smuggle stuff after |\ekvset|'s effects.
+% \begin{macrocode}
+\long\def\ekvsneak##1##2\ekv@stop#1##3%
+ {%
+ ##2\ekv@stop#1{##3##1}%
+ }
+\long\def\ekvsneakPre##1##2\ekv@stop#1##3%
+ {%
+ ##2\ekv@stop#1{##1##3}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvparse}
+% Additionally to the |\ekvset| macro we also want to provide an |\ekvparse|
+% macro, that has the same scope as |\keyval_parse:NNn| from \pkg{expl3}.
+% This is pretty analogue to the |\ekvset| implementation, we just put an
+% |\unexpanded| here and there instead of other macros to stop the |\expanded|
+% on our output.
+% \begin{macrocode}
+\long\def\ekvparse##1##2##3%
+ {%
+ \expanded{\ekv@parse##1##2\ekv@mark##3#1\ekv@stop#1}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\ekv@parse}
+% \begin{macrocode}
+\long\def\ekv@parse##1##2##3#1%
+ {%
+ \ekv@ifstop##3\ekv@endparse\ekv@mark\ekv@stop
+ \ekv@parse@other##1##2##3,\ekv@stop,%
+ \ekv@parse##1##2\ekv@mark
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\ekv@endparse}
+% \begin{macrocode}
+\long\def\ekv@endparse
+ \ekv@mark\ekv@stop\ekv@parse@other##1,\ekv@stop,\ekv@parse##2\ekv@mark
+ {}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\ekv@parse@other}
+% \begin{macrocode}
+\long\def\ekv@parse@other##1##2##3,%
+ {%
+ \ekv@ifblank@##3\ekv@nil\ekv@ifempty@B\ekv@ifempty@true@F
+ \ekv@ifempty@A\ekv@ifempty@B\@firstofone
+ {%
+ \ekv@ifhas@eq@other##3=\ekv@ifempty@B\ekv@ifempty@false
+ \ekv@ifempty@A\ekv@ifempty@B\@firstoftwo
+ {\unexpanded{##2}\ekv@parse@eq@other##3\ekv@stop}%
+ {%
+ \ekv@ifhas@eq@active##3#2\ekv@ifempty@B\ekv@ifempty@false
+ \ekv@ifempty@A\ekv@ifempty@B\@firstoftwo
+ {\unexpanded{##2}\ekv@parse@eq@active##3\ekv@stop}%
+ {%
+ \ekv@ifstop##3\ekv@endparse@other\ekv@mark\ekv@stop
+ \unexpanded{##1}{\ekv@strip{##3}\unexpanded}%
+ }%
+ }%
+ }%
+ \ekv@parse@other##1##2\ekv@mark
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\ekv@parse@eq@other}
+% \begin{macrocode}
+\long\def\ekv@parse@eq@other##1=%
+ {%
+ \ekv@ifhas@eq@active##1#2\ekv@ifempty@B\ekv@ifempty@false
+ \ekv@ifempty@A\ekv@ifempty@B\@firstoftwo
+ {\ekv@parse@eq@active##1=}%
+ {{\ekv@strip{##1}\unexpanded}\ekv@parse@pair\ekv@mark}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\ekv@parse@eq@active}
+% \begin{macrocode}
+\long\def\ekv@parse@eq@active##1#2%
+ {%
+ {\ekv@strip{##1}\unexpanded}\ekv@parse@pair\ekv@mark
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\ekv@endparse@other}
+% \begin{macrocode}
+\long\def\ekv@endparse@other
+ \ekv@mark\ekv@stop\unexpanded##1%
+ \ekv@parse@other##2\ekv@mark
+ {}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\ekv@parse@pair}
+% \begin{macrocode}
+\long\def\ekv@parse@pair##1\ekv@stop
+ {%
+ {\ekv@strip{##1}\unexpanded}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% Finally really setting things up with |\ekvset|'s temporary meaning:
+% \begin{macrocode}
+}
+\begingroup
+\catcode`\,=13
+\catcode`\==13
+\ekvset,=
+% \end{macrocode}
+%
+% \begin{macro}{\ekv@ifstop}
+% The |\ekv@ifstop| test works similar to our if-empty test, but instead of
+% using tokens which are used nowhere else (|\ekv@ifempty@A| and
+% |\ekv@ifempty@B|) we use |\ekv@mark| and |\ekv@stop|.
+% \begin{macrocode}
+\long\def\ekv@ifstop#1\ekv@mark\ekv@stop{}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekv@set@pair,\ekv@set@pair@}
+% |\ekv@set@pair| needs to split the argument at the |=| sign and check
+% whether the key is defined.
+% \begin{macrocode}
+\long\def\ekv@set@pair#1#2%
+ {%
+ \ekv@ifdefined@pair#2{#1}%
+ {%
+ \ekv@ifdefined{#2{#1}N}%
+ \ekv@err@noarg
+ \ekv@err@unknown
+ #2{#1}%
+ \ekv@gobbletostop
+ }%
+ }
+\long\def\ekv@set@pair@#1#2\ekv@stop
+ {%
+ \ekv@strip{#2}#1%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekv@set@key}
+% \begin{macrocode}
+\long\def\ekv@set@key#1#2%
+ {%
+ \ekv@ifdefined@key#2{#1}%
+ {%
+ \ekv@ifdefined{#2{#1}}%
+ \ekv@err@reqval
+ \ekv@err@unknown
+ #2{#1}%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekv@err,\ekv@err@}
+% Since |\ekvset| is fully expandable as long as the code of the keys is (which
+% is unlikely) we want to somehow throw expandable errors, in our case via
+% undefined control sequences.
+% \begin{macrocode}
+\begingroup
+\edef\ekv@err
+ {%
+ \endgroup
+ \unexpanded{\long\def\ekv@err}##1%
+ {%
+ \unexpanded{\expandafter\ekv@err@\@firstofone}%
+ {\expandafter\noexpand\csname ! expkv Error:\endcsname ##1.}%
+ \unexpanded{\ekv@stop}%
+ }%
+ }
+\ekv@err
+\def\ekv@err@{\expandafter\ekv@gobbletostop}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}
+% {
+% \ekv@err@common,\ekv@err@common@,
+% \ekv@err@unknown,\ekv@err@noarg,\ekv@err@reqval
+% }
+% Now we can use |\ekv@err| to set up some error messages so that we can later
+% use those instead of the full strings.
+% \begin{macrocode}
+\long\def\ekv@err@common #1#2{\expandafter\ekv@err@common@\string#2{#1}}
+\long\def\ekv@err@common@#1#2#3#4#5(#6#7{\ekv@err{#6 (`#7', set `#5')}}
+\long\def\ekv@err@unknown#1#2{\ekv@err@common{unknown key}#1{#2}}
+\long\def\ekv@err@noarg #1#2{\ekv@err@common{value forbidden}#1{#2}}
+\long\def\ekv@err@reqval #1#2{\ekv@err@common{value required}#1{#2}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekv@strip,\ekv@strip@a,\ekv@strip@b,\ekv@strip@c}
+% Finally we borrow some ideas of \pkg{expl3}'s \pkg{l3tl} to strip spaces
+% from keys and values. This |\ekv@strip| also strips one level of outer braces
+% \emph{after} stripping spaces, so an input of | {abc} | becomes |abc| after
+% stripping. It should be used with |#1| prefixed by |\ekv@mark|.
+% \begin{macrocode}
+\def\ekv@strip#1%
+ {%
+ \long\def\ekv@strip##1%
+ {%
+ \ekv@strip@a
+ ##1%
+ \ekv@nil
+ \ekv@mark#1%
+ #1\ekv@nil{}%
+ \ekv@stop
+ }%
+ \long\def\ekv@strip@a##1\ekv@mark#1##2\ekv@nil##3%
+ {%
+ \ekv@strip@b##3##1##2\ekv@nil
+ }%
+ \long\def\ekv@strip@b##1#1\ekv@nil
+ {%
+ \ekv@strip@c##1\ekv@nil
+ }%
+ \long\def\ekv@strip@c\ekv@mark##1\ekv@nil##2\ekv@stop##3%
+ {%
+ ##3{##1}%
+ }%
+ }
+\ekv@strip{ }
+% \end{macrocode}
+% \end{macro}
+%
+% Now everything that's left is to reset the category code of |@|.
+% \begin{macrocode}
+\catcode`\@=\ekv@tmp
+% \end{macrocode}
+%
+% \gobbledocstriptag
+%</tex>
+%^^A=<<
+%
+%^^A=<<
+%
+% \end{implementation}^^A=<<
+%
+% \clearpage
+% \PrintIndex
+%
+\endinput
+%
+^^A vim: ft=tex fdm=marker fmr=>>=,=<<
diff --git a/macros/generic/expkv/expkv.pdf b/macros/generic/expkv/expkv.pdf
new file mode 100644
index 0000000000..d3bf8d0cac
--- /dev/null
+++ b/macros/generic/expkv/expkv.pdf
Binary files differ
diff --git a/macros/latex/contrib/caption/README b/macros/latex/contrib/caption/README
index 79aee4f0f0..fc43fccd45 100644
--- a/macros/latex/contrib/caption/README
+++ b/macros/latex/contrib/caption/README
@@ -1,7 +1,7 @@
==========================================================================
The `caption' package bundle
-Release 2020-01-03
+Release 2020-01-22
Copyright (C) 1994-2020 Axel Sommerfeldt (axel.sommerfeldt@f-m.fm)
License: LPPL = LaTeX Project Public Licence
diff --git a/macros/latex/contrib/caption/subcaption.dtx b/macros/latex/contrib/caption/subcaption.dtx
index 3b58669d79..a3b8bdb2ee 100644
--- a/macros/latex/contrib/caption/subcaption.dtx
+++ b/macros/latex/contrib/caption/subcaption.dtx
@@ -28,7 +28,7 @@
% caption-deu.tex, caption-eng.tex, caption-rus.tex.
%
% \fi
-% \CheckSum{229}
+% \CheckSum{232}
%
% \iffalse
%<*driver>
@@ -924,14 +924,14 @@
%
% \begin{macrocode}
\NeedsTeXFormat{LaTeX2e}[1994/12/01]
-\ProvidesPackage{subcaption}[2020/01/03 v1.3b Sub-captions (AR)]
+\ProvidesPackage{subcaption}[2020/01/22 v1.3d Sub-captions (AR)]
% \end{macrocode}
%
% \subsection{Initial code}
%
% Since we base on the \package{caption} package we load it here.
% \begin{macrocode}
-\RequirePackage{caption}[2019/09/01] % needs v3.3c or newer
+\RequirePackage{caption}[2020/01/03] % needs v3.4h or newer
% \end{macrocode}
%
% \begin{macro}{\subcaption@CheckCompatibility}
@@ -986,23 +986,6 @@
% \end{macrocode}
% \end{macro}
%
-% \iffalse
-% \subsection{Declaration of options}
-% We do not have own options.
-% \fi
-%
-% \subsection{Execution of options}
-%
-% We use |\caption@ExecuteOptions| and |\caption@ProcessOptions| here to add
-% the options to the `|sub|' option list instead of executing them immediately.
-% \changes{v1.1}{2018/05/01}{Bugfix: Option \texttt{font+=small} changed to \texttt{size=smaller}}
-% \begin{macrocode}
-\caption@SetupOptions{subcaption}{\captionsetup[sub]{#2}}%
-\caption@ExecuteOptions{subcaption}{%
- size=smaller,labelformat=parens,labelsep=space,skip=6pt,list=0,hypcap=0}
-\caption@ProcessOptions*{subcaption}
-% \end{macrocode}
-%
% \subsection{Main code}
%
% \changes{v1.1}{2011/10/30}{Adapted to the newfloat package}
@@ -1071,6 +1054,7 @@
% \begin{macro}{subfigure}
% \begin{macro}{subtable}
% \changes{v1.2}{2016/02/21}{Optional argument values `B' and `T' added}
+% \changes{v1.3d}{2020/01/22}{Definition and usage of \cs{@subfloatboxreset} added}
% This is just an ordinary \env{minipage} environment with
% |\setcaptionsubtype| as first contents line.
% It will be defined using the helper macro |\caption@For{sub|\-|type|\-|list}|
@@ -1106,8 +1090,12 @@
\else
\minipage[#1]#2{#3}%
\fi\fi
+ \@subfloatboxreset
\setcaptionsubtype\relax}
% \end{macrocode}
+% \begin{macrocode}
+\providecommand*\@subfloatboxreset{}
+% \end{macrocode}
% \end{macro}
% \end{macro}
%
@@ -1208,6 +1196,20 @@
% \end{macrocode}
% \end{macro}
%
+% \subsection{Execution of options}
+%
+% We use |\caption@ExecuteOptions| and |\caption@ProcessOptions| here to add
+% the options to the `|sub|' option list instead of executing them immediately.
+% \changes{v1.1}{2018/05/01}{Bugfix: Option \texttt{font+=small} changed to \texttt{size=smaller}}
+% \begin{macrocode}
+\caption@SetupOptions{subcaption}{\captionsetup[sub]{#2}}%
+\caption@ExecuteOptions{subcaption}{%
+ size=smaller,labelformat=parens,labelsep=space,skip=6pt,list=0,hypcap=0}
+\caption@ProcessOptions*{subcaption}
+% \end{macrocode}
+%
+% \subsection{Bonus material}
+%
% \subsubsection{The \cs{subfloat} command}
%
% \begin{macro}{\subfloat}
@@ -1243,7 +1245,8 @@
% \begin{macrocode}
\def\subfloat@#1{%
\setbox\@tempboxa\hbox{#1}%
- \caption@iiiibox\setcaptionsubtype
+ \caption@iiiibox
+ \setcaptionsubtype
{\phantomcaption\@gobble}{\phantomcaption\@gobble}% no box with \caption
{}% no optional arguments for \caption
{}% no sub-caption
diff --git a/macros/latex/contrib/dashundergaps/README.md b/macros/latex/contrib/dashundergaps/README.md
index 62bcbe1618..aa95e95f5a 100644
--- a/macros/latex/contrib/dashundergaps/README.md
+++ b/macros/latex/contrib/dashundergaps/README.md
@@ -12,11 +12,11 @@ Package source can be found below:
https://github.com/FrankMittelbach/fmitex/
-The license is LPPL.
+The license is LPPL 1.3c.
-----
-Copyright (C) 2018 Frank Mittelbach<br />
+Copyright (C) 2018-2020 Frank Mittelbach<br />
<https://latex-project.org/> <br />
All rights reserved.
diff --git a/macros/latex/contrib/dashundergaps/changes.txt b/macros/latex/contrib/dashundergaps/changes.txt
index ddb4ee6293..74ad759760 100644
--- a/macros/latex/contrib/dashundergaps/changes.txt
+++ b/macros/latex/contrib/dashundergaps/changes.txt
@@ -1,3 +1,16 @@
+2020-01-22 Frank Mittelbach <Frank.Mittelbach@latex-project.org>
+
+ * dashundergaps.dtx (subsection{Loading and fixing/changing \pkg{ulem}}):
+ Adjusted definition to new ulem release
+
+ * Some release cleanup.
+
+2019-07-14 Frank Mittelbach <Frank.Mittelbach@latex-project.org>
+
+ * dashundergaps.dtx (subsection{The main implementation part}):
+ As the code doesn't run with expl3 versions prior to mid 2018, we
+ check against that (github/7).
+
2018-11-09 Frank Mittelbach <Frank.Mittelbach@latex-project.org>
* dashundergaps.dtx v2.0d
diff --git a/macros/latex/contrib/dashundergaps/dashundergaps-code.pdf b/macros/latex/contrib/dashundergaps/dashundergaps-code.pdf
index 81d6122575..f200ad1d9c 100644
--- a/macros/latex/contrib/dashundergaps/dashundergaps-code.pdf
+++ b/macros/latex/contrib/dashundergaps/dashundergaps-code.pdf
Binary files differ
diff --git a/macros/latex/contrib/dashundergaps/dashundergaps-doc.pdf b/macros/latex/contrib/dashundergaps/dashundergaps-doc.pdf
index 047685d56d..fc1a592034 100644
--- a/macros/latex/contrib/dashundergaps/dashundergaps-doc.pdf
+++ b/macros/latex/contrib/dashundergaps/dashundergaps-doc.pdf
Binary files differ
diff --git a/macros/latex/contrib/dashundergaps/dashundergaps.dtx b/macros/latex/contrib/dashundergaps/dashundergaps.dtx
index f26f362baa..9b5fbcc1fd 100644
--- a/macros/latex/contrib/dashundergaps/dashundergaps.dtx
+++ b/macros/latex/contrib/dashundergaps/dashundergaps.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: dashundergaps.dtx (C) Copyright 2018 Frank Mittelbach
+%% File: dashundergaps.dtx (C) Copyright 2018-2020 Frank Mittelbach
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -17,8 +17,8 @@
% for those people who are interested or want to report an issue.
%
-\def\dashundergapsdate {2018/11/18}
-\def\dashundergapsversion{v2.0d}
+\def\dashundergapsdate {2020-01-22} % don't forget to also adjust build.lua!
+\def\dashundergapsversion{v2.0f}
%<*driver>
\let\fmipagebreak\pagebreak
@@ -29,7 +29,6 @@
[final]
{l3doc-TUB}
-
\setcounter{page}{1}
% fix for _TF undefined,
@@ -533,19 +532,20 @@
%
% \begin{macro}{\dotuline}
% The dots produced by \cs{dotuline} depend on the current font,
-% which is a somewhat questionable design\Dash if you underline a text %part
+% which is a somewhat questionable design\Dash if you underline a text
% with a single bold word somewhere inside it will change the
% shape of the dot line. So we always use the \cs{normalfont}
% dot (this is not done in the original definition).
+% \changes{v2.0f}{2020/01/22}{Adjusted definition to new ulem release}
% \begin{macrocode}
-\def\dotuline{\bgroup
+\protected\def\dotuline{\leavevmode\bgroup
\UL@setULdepth
+ \ifx\UL@on\UL@onin \advance\ULdepth2\p@\fi
\markoverwith{\begingroup
- \advance\ULdepth0.08ex
+% \advance\ULdepth0.08ex
\lower\ULdepth\hbox{\normalfont \kern.1em .\kern.04em}%
\endgroup}%
\ULon}
-\MakeRobust\dotuline
% \end{macrocode}
% \end{macro}
%
@@ -556,12 +556,12 @@
% the lowering. We change that to be based on the current
% value of \cs{ULdepth} so that the user (or this package here)
% can change the placement.
+% \changes{v2.0f}{2020/01/22}{Adjusted definition to new ulem release}
% \begin{macrocode}
-\def\uwave{\bgroup
+\protected\def\uwave{\leavevmode\bgroup
\UL@setULdepth
\advance\ULdepth 0.6\p@
\markoverwith{\lower\ULdepth\hbox{\sixly \char58}}\ULon}
-\MakeRobust\uwave
% \end{macrocode}
% \end{macro}
%
@@ -635,6 +635,24 @@
\RequirePackage{xparse,l3keys2e}
% \end{macrocode}
%
+% As the code uses some functions from \pkg{expl3} that got
+% introduced sometime in 2018 we need to require a fairly recent
+% version (the date is somewhat arbitrarily picked).
+% \begin{macrocode}
+\@ifpackagelater{expl3}{2018-06-24}
+ {}
+ {%
+ \PackageError{dashundergaps}{Support package l3kernel too old}
+ {%
+ Please install an up to date version of l3kernel\MessageBreak
+ using your TeX package manager or from CTAN.\MessageBreak
+ \MessageBreak
+ Loading dashundergaps will abort!%
+ }%
+ \endinput
+ }
+% \end{macrocode}
+%
% Here we introduce the package and specify its version number:
% \begin{macrocode}
\ProvidesExplPackage{dashundergaps}
@@ -698,7 +716,6 @@
% number of gaps, it makes little sense to modify it at the
% document level. However, there may be use cases even for that and
% more importantly, by making it a user-level counter it is
-%\fmipagebreak
% possible to refer to the total number of gaps easily, e.g., via
% \cs{thetotalgapnumber}.
% ^^A\makeatletter\@endparpenalty=10000\makeatother
@@ -1050,7 +1067,7 @@
% package via \cs{usepackage}.
% \begin{macrocode}
\ProcessKeysPackageOptions{fmdug}
-%<*package>
+%</package>
% \end{macrocode}
%
% \Finale
diff --git a/macros/latex/contrib/dashundergaps/dashundergaps.ins b/macros/latex/contrib/dashundergaps/dashundergaps.ins
index 20ebf84d7a..935cdce488 100644
--- a/macros/latex/contrib/dashundergaps/dashundergaps.ins
+++ b/macros/latex/contrib/dashundergaps/dashundergaps.ins
@@ -3,7 +3,7 @@
%% driver files from the dtx file(s) in this package when run through
%% LaTeX or TeX.
%%
-%% Copyright 2018 Frank Mittelbach
+%% Copyright 2018-2020 Frank Mittelbach
%%
%%
%% This file is part of the dashundergaps Bundle for LaTeX.
@@ -15,7 +15,7 @@
%% The latest version of this license is in
%% http://www.latex-project.org/lppl.txt
%% and version 1.3c or later is part of all distributions of LaTeX
-%% version 2005/12/01 or later.
+%% version 2008 or later.
%%
%% In particular, NO PERMISSION is granted to modify the contents of this
%% file since it contains the legal notices that are placed in the files
@@ -35,7 +35,7 @@
This is a generated file.
-Copyright 2018 Frank Mittelbach
+Copyright 2018-2020 Frank Mittelbach
This file was generated from file(s) of the LaTeX `dashundergaps Bundle'.
--------------------------------------------------------------------------
diff --git a/macros/latex/contrib/dashundergaps/l3doc-TUB.cls b/macros/latex/contrib/dashundergaps/l3doc-TUB.cls
index 4db508e93c..e3f9138d73 100644
--- a/macros/latex/contrib/dashundergaps/l3doc-TUB.cls
+++ b/macros/latex/contrib/dashundergaps/l3doc-TUB.cls
@@ -891,7 +891,7 @@
\tl_greplace_all:Nno \g__codedoc_base_name_tl
{ ~ } { \c_catcode_other_space_tl }
\seq_get:NN #1 \l__codedoc_tmpa_tl
- \str_if_eq_x:nnTF { \l__codedoc_tmpa_tl } { \scan_stop: }
+ \str_if_eq:eeTF { \l__codedoc_tmpa_tl } { \scan_stop: }
{
\seq_gclear:N \g__codedoc_variants_seq
\__codedoc_names_typeset_auxii:x { \g__codedoc_base_name_tl }
@@ -954,7 +954,7 @@
#1
{
\l__codedoc_tmpa_tl
- \str_if_eq_x:nnF { \l__codedoc_tmpb_tl } { \scan_stop: }
+ \str_if_eq:eeF { \l__codedoc_tmpb_tl } { \scan_stop: }
{ : \l__codedoc_tmpb_tl }
\bool_if:NT \l__codedoc_macro_TF_bool { TF }
}
@@ -2098,7 +2098,7 @@
\tl_if_empty:nTF {#3}
{ { } { } { } }
{
- \str_if_eq_x:nnTF {#3} { TeX }
+ \str_if_eq:eeTF {#3} { TeX }
{
{ TeX~and~LaTeX2e }
{ \string\TeX{}~and~\string\LaTeXe{} }
diff --git a/macros/latex/contrib/nicematrix/nicematrix-french.pdf b/macros/latex/contrib/nicematrix/nicematrix-french.pdf
index ccc4611524..45b40e96ba 100644
--- a/macros/latex/contrib/nicematrix/nicematrix-french.pdf
+++ b/macros/latex/contrib/nicematrix/nicematrix-french.pdf
Binary files differ
diff --git a/macros/latex/contrib/nicematrix/nicematrix-french.tex b/macros/latex/contrib/nicematrix/nicematrix-french.tex
index 1035a9bab4..c4324295c3 100644
--- a/macros/latex/contrib/nicematrix/nicematrix-french.tex
+++ b/macros/latex/contrib/nicematrix/nicematrix-french.tex
@@ -16,6 +16,8 @@
\usepackage{siunitx}
+\usepackage{unicode-math}
+
\newbox\ExampleOne
\setbox\ExampleOne\hbox{%
@@ -97,7 +99,7 @@ tableau.
Cette extension peut être utilisée avec |xelatex|, |lualatex| et |pdflatex| mais aussi avec le cheminement
classique |latex|-|dvips|-|ps2pdf| (ou Adobe Distiller). Deux ou trois compilations successives peuvent être
nécessaires. Cette extension nécessite et charge les extensions \pkg{expl3}, \pkg{l3keys2e}, \pkg{xparse},
-\pkg{array}, \pkg{amsmath} et \pkg{tikz} . Elle charge aussi la bibliothèque Tikz \pkg{fit}. L'utilisateur final
+\pkg{array}, \pkg{amsmath} et \pkg{tikz}. Elle charge aussi la bibliothèque Tikz \pkg{fit}. L'utilisateur final
n'a qu'à charger l'extension \pkg{nicematrix} avec l'instruction habituelle : |\usepackage{nicematrix}|.
@@ -556,6 +558,12 @@ $\begin{pmatrix}
\end{scope}
+\subsection{Réglage fin des lignes en pointillés}
+
+L'écart entre un nœud et l'extrémité d'une ligne en pointillés est fixée par |dotted-lines-margin|. La valeur
+initiale de cette clé est de $0.3$~em (il est conseillé d'utiliser une unité de mesure dépendante de la fonte
+courante). Pour un exemple, voir p.~\pageref{permutation}.
+
\section{Les nœuds Tikz créés par l'extension nicematrix}
@@ -1269,8 +1277,9 @@ Pour des raisons techniques, il n'est pas possible d'écrire |\Block{|$i$|-|$j$|
(mais on peut écrire |\Block{|$i$|-|$j$|}<>{<}| avec le résultat attendu).
+\section{Fonctionnalités avancées}
-\section{L'option small}
+\subsection{L'option small}
Avec l'option |small|, les environnements de l'extension \pkg{nicematrix} sont composés d'une manière proche de ce
que propose l'environnement |{smallmatrix}| de l'\pkg{amsmath} (et les environnements |{psmallmatrix}|,
@@ -1311,7 +1320,7 @@ En fait, l'option |small| correspond aux réglages suivants :
\item les caractéristiques des lignes en pointillés sont également modifiées.
\end{itemize}
-\section{Les compteurs iRow et jCol}
+\subsection{Les compteurs iRow et jCol}
Dans les cases du tableau, il est possible d'utiliser les compteurs LaTeX |iRow| et |jCol| qui représentent le
numéro de la rangée courante et le numéro de la colonne courante\footnote{On rappelle que le numéro de la «première
@@ -1366,11 +1375,11 @@ $C = ~emphase#\pAutoNiceMatrix@{3-3}{C_{\arabic{iRow},\arabic{jCol}}}$
$C = \pAutoNiceMatrix{3-3}{C_{\arabic{iRow},\arabic{jCol}}}$
-\section{L'option hlines}
+\subsection{L'option hlines}
Dans les environnements de \pkg{nicematrix}, on peut bien entendu ajouter des filets horizontaux entre les lignes
avec la commande~|\hline|. Par souci de commodité, l'extension \pkg{nicematrix} fournit l'option |hlines| qui impose
-directement que tous les filets horizontaux soient tracés (à l'exception, très naturelle, du filet avant
+directement que tous les filets horizontaux soient tracés (à l'exception, très naturelle, du filet avanet
l'éventuelle «première rangée» et après l'éventuelle «dernière rangée»).
\medskip
@@ -1385,8 +1394,42 @@ c & c & b & a & e
\end{BVerbatim}
\raisebox{-5mm}{\box\ExampleOne}
+\subsection{L'option light-syntax}
+
+L'option |light-syntax|\footnote{Cette option est inspirée de
+l'extension \pkg{spalign} de Joseph Rabinoff.} permet d'alléger la saisie des matrices, ainsi que leur lisibilité dans le source TeX.
+Lorsque cette option est activée, on doit utiliser le point-virgule comme marqueur de fin de rangée et séparer les
+colonnes par des espaces. On remarquera toutefois que, comme souvent dans le monde TeX, les espaces après les
+séquences de contrôles ne sont pas comptées et que les éléments entre accolades sont considérés comme un tout.
+
+\bigskip
+L'exemple suivant a été composé avec XeLaTeX en utilisant \pkg{unicode-math}, ce qui permet d'utiliser directement
+les lettres grecques en Unicode.
+
+\medskip
+\begin{scope}
+\def\alpha{$α$}
+\def\beta{$β$}
+\begin{BVerbatim}[baseline=c,boxwidth=10cm]
+$\begin{bNiceMatrix}[~emphase#light-syntax@,first-row,first-col]
+{} ~alpha ~beta ;
+~alpha 2\cos ~alpha {\cos ~alpha + \cos ~beta} ;
+~beta \cos ~alpha+\cos ~beta { 2 \cos ~beta }
+\end{bNiceMatrix}$
+\end{BVerbatim}
+\end{scope}
+%
+$\begin{bNiceMatrix}[light-syntax,first-row,first-col]
+{} α β ;
+α 2\cos α {\cos α + \cos β} ;
+β \cos α+\cos β { 2 \cos β }
+\end{bNiceMatrix}$
+
+\medskip
+On peut changer le caractère utilisé pour indiquer les fins de rangées avec l'option |end-of-row|. Comme dit
+précédemment, la valeur initiale de ce paramètre est un point-virgule.
-\section{Utilisation du type de colonne S de siunitx}
+\subsection{Utilisation du type de colonne S de siunitx}
Si l'extension \pkg{siunitx} est chargée (avant ou après \pkg{nicematrix}), il est possible d'utiliser les colonnes
de type |S| de \pkg{siunitx} dans les environnements de \pkg{nicematrix}. L'implémentation n'utilise explicitement
@@ -1413,6 +1456,8 @@ $\begin{pNiceArray}{SCWc{1cm}C}[nullify-dots,first-row]
\medskip
En revanche, les colonnes |d| de l'extension \pkg{dcolumn} ne sont pas prises en charge par \pkg{nicematrix}.
+
+
\section{Remarques techniques}
\subsection{Pour définir de nouveaux types de colonnes}
@@ -1764,11 +1809,15 @@ b & a & b & \Ddots & & \Vdots \\
\vspace{2cm}
-Une matrice de permutation :
+Une matrice de permutation.
+
+À titre d'exemple, on a augmenté la valeur du paramètre |dotted-lines-margin|.
+
+\label{permutation}
\bigskip
\begin{BVerbatim}[baseline=c]
-$\begin{pNiceMatrix}
+$\begin{pNiceMatrix}[~emphase#dotted-lines-margin=6em@]
0 & 1 & 0 & & \Cdots & 0 \\
\Vdots & & & \Ddots & & \Vdots \\
& & & \Ddots & & \\
@@ -1778,7 +1827,7 @@ $\begin{pNiceMatrix}
\end{pNiceMatrix}$
\end{BVerbatim}
\hspace{2.5cm}
-$\begin{pNiceMatrix}
+$\begin{pNiceMatrix}[dotted-lines-margin=0.6em]
0 & 1 & 0 & & \Cdots & 0 \\
\Vdots & & & \Ddots & & \Vdots \\
& & & \Ddots & & \\
@@ -2052,15 +2101,15 @@ réglage de \pkg{colortbl} sont néanmoins assez limitées. C'est pourquoi nous
surligner une rangée de la matrice. Nous créons un nœud Tikz rectangulaire qui englobe les nœuds de la deuxième
rangée en utilisant les outils de la bibliothèque Tikz \pkg{fit}. Ce nœud est rempli après la construction de la
matrice. Pour que l'on puisse voir le texte \emph{sous} le nœud, nous devons utiliser la transparence avec le
-|blend mode| égal à |multiply|. Attention : certains lecteurs de \textsc{pdf} ne sont pas capables de rendre la
-transparence correctement.
+|blend mode| égal à |multiply|.
\tikzset{highlight/.style={rectangle,
fill=red!15,
blend mode = multiply,
rounded corners = 0.5 mm,
- inner sep=1pt}}
+ inner sep=1pt,
+ fit=#1}}
\medskip
\begin{Verbatim}
@@ -2068,16 +2117,17 @@ transparence correctement.
fill=red!15,
~emphase#blend mode = multiply@,
rounded corners = 0.5 mm,
- inner sep=1pt}}
+ inner sep=1pt,
+ fit=~#1}}
-$\begin{bNiceMatrix}[~emphase#code-after = {\tikz \node[highlight, fit = (2-1) (2-3)] {} ;}@]
+$\begin{bNiceMatrix}[~emphase#code-after = {\tikz \node [highlight = (2-1) (2-3)] {} ;}@]
0 & \Cdots & 0 \\
1 & \Cdots & 1 \\
0 & \Cdots & 0
\end{bNiceMatrix}$
\end{Verbatim}
-\[\begin{bNiceMatrix}[code-after = {\tikz \node[highlight, fit = (2-1) (2-3)] {} ;}]
+\[\begin{bNiceMatrix}[code-after = {\tikz \node [highlight = (2-1) (2-3)] {} ;}]
0 & \Cdots & 0 \\
1 & \Cdots & 1 \\
0 & \Cdots & 0
@@ -2131,25 +2181,27 @@ Si on veut surligner chaque rangée de la matrice, on peut utiliser la technique
\tikzset{mes-options/.style={remember picture,
overlay,
name prefix = exemple-,
- every node/.style = {fill = red!15,
- blend mode = multiply,
- inner sep = 0pt}}}
+ highlight/.style = {fill = red!15,
+ blend mode = multiply,
+ inner sep = 0pt,
+ fit = ~#1}}}
\end{Verbatim}
\tikzset{mes-options/.style={remember picture,
overlay,
name prefix = exemple-,
- every node/.style = {fill = red!15,
- blend mode = multiply,
- inner sep = 0pt}}}
+ highlight/.style = {fill = red!15,
+ blend mode = multiply,
+ inner sep = 0pt,
+ fit = #1}}}
\begin{Verbatim}
\begin{tikzpicture}[mes-options]
-\node [fit = (1-1) (1-3)] {} ;
-\node [fit = (2-1) (2-3)] {} ;
-\node [fit = (3-1) (3-3)] {} ;
+\node [highlight = (1-1) (1-3)] {} ;
+\node [highlight = (2-1) (2-3)] {} ;
+\node [highlight = (3-1) (3-3)] {} ;
\end{tikzpicture}
\end{Verbatim}
@@ -2158,12 +2210,13 @@ On obtient la matrice suivante.
\[\begin{pNiceArray}{CCC}[
last-col,
- code-after = {\begin{tikzpicture}[every node/.style = {fill = red!15,
- blend mode = multiply,
- inner sep = 0pt}]
- \node [fit = (1-1) (1-3)] {} ;
- \node [fit = (2-1) (2-3)] {} ;
- \node [fit = (3-1) (3-3)] {} ;
+ code-after = {\begin{tikzpicture}[highlight/.style = {fill = red!15,
+ blend mode = multiply,
+ inner sep = 0pt,
+ fit = #1}]
+ \node [highlight = (1-1) (1-3)] {} ;
+ \node [highlight = (2-1) (2-3)] {} ;
+ \node [highlight = (3-1) (3-3)] {} ;
\end{tikzpicture}}]
a & a + b & a + b + c & L_1 \\
a & a & a + b & L_2 \\
@@ -2175,9 +2228,9 @@ Le résultat peut paraître décevant. On peut l'améliorer en utilisant les «n
\begin{Verbatim}
\begin{tikzpicture}[mes-options, ~emphase#name suffix = -medium@]
-\node [fit = (1-1) (1-3)] {} ;
-\node [fit = (2-1) (2-3)] {} ;
-\node [fit = (3-1) (3-3)] {} ;
+\node [highlight = (1-1) (1-3)] {} ;
+\node [highlight = (2-1) (2-3)] {} ;
+\node [highlight = (3-1) (3-3)] {} ;
\end{tikzpicture}
\end{Verbatim}
@@ -2187,13 +2240,14 @@ On obtient la matrice suivante.
\[\begin{pNiceArray}{CCC}[
last-col,
create-medium-nodes,
- code-after = {\begin{tikzpicture}[every node/.style = {fill = red!15,
- blend mode = multiply,
- inner sep = 0pt},
+ code-after = {\begin{tikzpicture}[highlight/.style = {fill = red!15,
+ blend mode = multiply,
+ inner sep = 0pt,
+ fit = #1},
name suffix = -medium]
- \node [fit = (1-1) (1-3)] {} ;
- \node [fit = (2-1) (2-3)] {} ;
- \node [fit = (3-1) (3-3)] {} ;
+ \node [highlight = (1-1) (1-3)] {} ;
+ \node [highlight = (2-1) (2-3)] {} ;
+ \node [highlight = (3-1) (3-3)] {} ;
\end{tikzpicture}}]
a & a + b & a + b + c & L_1 \\
a & a & a + b & L_2 \\
@@ -2302,8 +2356,8 @@ Dans la matrice produit, on remarquera que les lignes en pointillés sont «semi
\begin{Verbatim}
\begin{tikzpicture}[remember picture, overlay]
- \node [highlight, fit = (A-3-1) (A-3-5) ] {} ;
- \node [highlight, fit = (B-1-3) (B-5-3) ] {} ;
+ \node [highlight = (A-3-1) (A-3-5) ] {} ;
+ \node [highlight = (B-1-3) (B-5-3) ] {} ;
\draw [color = gray] (A-3-3) to [bend left] (B-3-3) ;
\end{tikzpicture}
\end{Verbatim}
@@ -2341,8 +2395,8 @@ L_i & a_{i1} & \Cdots & a_{ik} & \Cdots & a_{in} \\
\end{NiceMatrixBlock}
\begin{tikzpicture}[remember picture, overlay]
- \node [highlight, fit = (A-3-1) (A-3-5) ] {} ;
- \node [highlight, fit = (B-1-3) (B-5-3) ] {} ;
+ \node [highlight = (A-3-1) (A-3-5) ] {} ;
+ \node [highlight = (B-1-3) (B-5-3) ] {} ;
\draw [color = gray] (A-3-3) to [bend left] (B-3-3) ;
\end{tikzpicture}
diff --git a/macros/latex/contrib/nicematrix/nicematrix.dtx b/macros/latex/contrib/nicematrix/nicematrix.dtx
index 9ccfc120b5..bbbc805d70 100644
--- a/macros/latex/contrib/nicematrix/nicematrix.dtx
+++ b/macros/latex/contrib/nicematrix/nicematrix.dtx
@@ -15,8 +15,8 @@
%
% \fi
% \iffalse
-\def\myfileversion{3.9}
-\def\myfiledate{2020/01/10}
+\def\myfileversion{3.10}
+\def\myfiledate{2020/01/22}
%
%
%<*batchfile>
@@ -77,6 +77,7 @@ c & c & b & a & e
\usepackage{arydshln}
\setlength{\columnseprule}{0.4pt}
\usepackage{footnotehyper}
+\usepackage{unicode-math}
\parindent 0pt
\EnableCrossrefs
@@ -540,7 +541,7 @@ c & c & b & a & e
% option is an alias for the conjonction of two options:
% |renew-dots| and |renew-matrix|.\footnote{The options |renew-dots|,
% |renew-matrix| and |transparent| can be fixed with the command
-% |\NiceMatrixOptiosn| like the other options. However, they can also be fixed
+% |\NiceMatrixOptions| like the other options. However, they can also be fixed
% as options of the command |\usepackage| (it's an exception for these three
% specific options.)}
%
@@ -585,7 +586,12 @@ c & c & b & a & e
% \end{pmatrix}$
% \end{scope}
%
-%
+% \subsection{Fine tuning of the dotted lines}
+%
+% The distance between a node and the end of a dotted line is set by
+% |dotted-lines-margin|. The initial value of this key is $0.3$~em (it's
+% recommended to use a unit dependant of the current font). For an example,
+% cf.~p.~\pageref{permutation}.
%
%
% \section{The Tikz nodes created by nicematrix}
@@ -1326,8 +1332,9 @@ c & c & b & a & e
% write |\Block{|$i$|-|$j$|}<>{<}| with the expected result.
%
%
+% \section{Advanced features}
%
-% \section{The option small}
+% \subsection{The option small}
%
% With the option |small|, the environments of the extension \pkg{nicematrix}
% are composed in a way similar to the environment |{smallmatrix}| of the
@@ -1372,7 +1379,7 @@ c & c & b & a & e
% \item the characteristics of the dotted lines are also modified.
% \end{itemize}
%
-% \section{The counters iRow and jCol}
+% \subsection{The counters iRow and jCol}
%
% In the cells of the array, it's possible to use the LaTeX counters |iRow| and
% |jCol| which represent the number of the current row and the number of the
@@ -1429,7 +1436,7 @@ c & c & b & a & e
%
% $C = \pAutoNiceMatrix{3-3}{C_{\arabic{iRow},\arabic{jCol}}}$
%
-% \section{The option hlines}
+% \subsection{The option hlines}
%
% You can add horizontal rules between rows in the environments of
% \pkg{nicematrix} with the usual command |\hline|. But, by convenience, the
@@ -1450,7 +1457,44 @@ c & c & b & a & e
% \end{BVerbatim}
% \raise-5mm\box\ExampleOne
%
-% \section{Utilisation of the column type S of siunitx}
+% \subsection{The option light-syntax}
+%
+% The option |light-syntax|\footnote{This option is inspired by the extension
+% \pkg{spalign} of Joseph Rabinoff.} allow the user to compose the arrays with a
+% lighter syntax, which gives a more readable TeX source.
+%
+% When this option is used, one should use the semicolon for the end of a row
+% and a space to separate the columns. However, as usual in the TeX world, the
+% spaces after a control sequence are discarded and the elements between curly
+% braces are considered as a whole.
+%
+% \bigskip
+% The following example has been composed with XeLaTeX with \pkg{unicode-math},
+% which allows the use of greek letters directly in the TeX source.
+%
+% \medskip
+% \begin{scope}
+% \def\alpha{$α$}
+% \def\beta{$β$}
+% \begin{BVerbatim}[baseline=c,boxwidth=10cm]
+% $\begin{bNiceMatrix}[~emphase#light-syntax@,first-row,first-col]
+% {} ~alpha ~beta ;
+% ~alpha 2\cos ~alpha {\cos ~alpha + \cos ~beta} ;
+% ~beta \cos ~alpha+\cos ~beta { 2 \cos ~beta }
+% \end{bNiceMatrix}$
+% \end{BVerbatim}
+% \end{scope}
+% $\begin{bNiceMatrix}[light-syntax,first-row,first-col]
+% {} α β ;
+% α 2\cos α {\cos α + \cos β} ;
+% β \cos α+\cos β { 2 \cos β }
+% \end{bNiceMatrix}$
+%
+% \medskip
+% It's possible to change the character used to mark the end of rows with the
+% option |end-of-row|. As said before, the initial value is a semicolon.
+%
+% \subsection{Utilisation of the column type S of siunitx}
%
% If the package \pkg{siunitx} is loaded (before or after \pkg{nicematrix}),
% it's possible to use the |S| column type of \pkg{siunitx} in the environments
@@ -1480,6 +1524,8 @@ c & c & b & a & e
% On the other hand, the |d| columns of the package \pkg{dcolumn} are not
% supported by \pkg{nicematrix}.
%
+%
+%
% \section{Technical remarks}
%
% \subsection{Definition of new column types}
@@ -1571,7 +1617,7 @@ c & c & b & a & e
%
% The environments created by \pkg{nicematrix} are numbered by an internal
% global counter. The command |\NiceMatrixLastEnv| provides the number of the
-% last environment of \pkg{nicematrix} (for LaTeX, it's a —fully expandable—
+% last environment of \pkg{nicematrix} (for LaTeX, it's a ``fully expandable''
% command and not a counter).
%
% For the environment of number~$n$, the node in row~$i$ and column~$j$ has the
@@ -1850,11 +1896,13 @@ c & c & b & a & e
%
% \vspace{2cm}
%
-% A permutation matrix:
+% A permutation matrix (as an example, we have raised the value of
+% |dotted-lines-margin|).
%
+% \label{permutation}
% \bigskip
% \begin{BVerbatim}[baseline=c]
-% $\begin{pNiceMatrix}
+% $\begin{pNiceMatrix}[~emphase#dotted-lines-margin=0.6em@]
% 0 & 1 & 0 & & \Cdots & 0 \\
% \Vdots & & & \Ddots & & \Vdots \\
% & & & \Ddots & & \\
@@ -1864,7 +1912,7 @@ c & c & b & a & e
% \end{pNiceMatrix}$
% \end{BVerbatim}
% \hspace{2.5cm}
-% $\begin{pNiceMatrix}
+% $\begin{pNiceMatrix}[dotted-lines-margin=0.6em]
% 0 & 1 & 0 & & \Cdots & 0 \\
% \Vdots & & & \Ddots & & \Vdots \\
% & & & \Ddots & & \\
@@ -2147,14 +2195,14 @@ c & c & b & a & e
% nodes of the second row with the Tikz library \pkg{fit}. This Tikz node is
% filled after the construction of the matrix. In order to see the text
% \emph{under} this node, we have to use transparency with the |blend mode|
-% equal to |multiply|. Warning: some \textsc{pdf} readers are not able to render
-% transparency correctly.
+% equal to |multiply|.
%
% \tikzset{highlight/.style={rectangle,
% fill=red!15,
% blend mode = multiply,
% rounded corners = 0.5 mm,
-% inner sep=1pt}}
+% inner sep=1pt,
+% fit = #1}}
%
% \medskip
% \begin{Verbatim}
@@ -2162,16 +2210,17 @@ c & c & b & a & e
% fill=red!15,
% ~emphase#blend mode = multiply@,
% rounded corners = 0.5 mm,
-% inner sep=1pt}}
+% inner sep=1pt,
+% fit = ~#1}}
%
-% $\begin{bNiceMatrix}[~emphase#code-after = {\tikz \node[highlight, fit = (2-1) (2-3)] {} ;}@]
+% $\begin{bNiceMatrix}[~emphase#code-after = {\tikz \node [highlight = (2-1) (2-3)] {} ;}@]
% 0 & \Cdots & 0 \\
% 1 & \Cdots & 1 \\
% 0 & \Cdots & 0
% \end{bNiceMatrix}$
% \end{Verbatim}
%
-% \[\begin{bNiceMatrix}[code-after = {\tikz \node[highlight, fit = (2-1) (2-3)] {} ;}]
+% \[\begin{bNiceMatrix}[code-after = {\tikz \node [highlight = (2-1) (2-3)] {} ;}]
% 0 & \Cdots & 0 \\
% 1 & \Cdots & 1 \\
% 0 & \Cdots & 0
@@ -2223,30 +2272,33 @@ c & c & b & a & e
% technique three times.
%
% \begin{Verbatim}
-% \tikzset{myoptions/.style={remember picture,
-% overlay,
-% name prefix = example-,
-% every node/.style = {fill = red!15,
-% blend mode = multiply,
-% inner sep = 0pt}}}
+% \tikzset{mes-options/.style={remember picture,
+% overlay,
+% name prefix = exemple-,
+% highlight/.style = {fill = red!15,
+% blend mode = multiply,
+% inner sep = 0pt,
+% fit = ~#1}}}
% \end{Verbatim}
%
%
-% \tikzset{myoptions/.style={remember picture,
-% overlay,
-% name prefix = example-,
-% every node/.style = {fill = red!15,
-% blend mode = multiply,
-% inner sep = 0pt}}}
+% \tikzset{mes-options/.style={remember picture,
+% overlay,
+% name prefix = exemple-,
+% highlight/.style = {fill = red!15,
+% blend mode = multiply,
+% inner sep = 0pt,
+% fit = #1}}}
%
% \begin{Verbatim}
-% \begin{tikzpicture}[myoptions]
-% \node [fit = (1-1) (1-3)] {} ;
-% \node [fit = (2-1) (2-3)] {} ;
-% \node [fit = (3-1) (3-3)] {} ;
+% \begin{tikzpicture}[mes-options]
+% \node [highlight = (1-1) (1-3)] {} ;
+% \node [highlight = (2-1) (2-3)] {} ;
+% \node [highlight = (3-1) (3-3)] {} ;
% \end{tikzpicture}
% \end{Verbatim}
%
+%
% \medskip
% We obtain the following matrix.
%
@@ -2269,10 +2321,10 @@ c & c & b & a & e
% nodes'' instead of the ``normal nodes''.
%
% \begin{Verbatim}
-% \begin{tikzpicture}[myoptions, ~emphase#name suffix = -medium@]
-% \node [fit = (1-1) (1-3)] {} ;
-% \node [fit = (2-1) (2-3)] {} ;
-% \node [fit = (3-1) (3-3)] {} ;
+% \begin{tikzpicture}[mes-options, ~emphase#name suffix = -medium@]
+% \node [highlight = (1-1) (1-3)] {} ;
+% \node [highlight = (2-1) (2-3)] {} ;
+% \node [highlight = (3-1) (3-3)] {} ;
% \end{tikzpicture}
% \end{Verbatim}
%
@@ -2282,19 +2334,21 @@ c & c & b & a & e
% \[\begin{pNiceArray}{CCC}[
% last-col,
% create-medium-nodes,
-% code-after = {\begin{tikzpicture}[every node/.style = {fill = red!15,
-% blend mode = multiply,
-% inner sep = 0pt},
+% code-after = {\begin{tikzpicture}[highlight/.style = {fill = red!15,
+% blend mode = multiply,
+% inner sep = 0pt,
+% fit = #1},
% name suffix = -medium]
-% \node [fit = (1-1) (1-3)] {} ;
-% \node [fit = (2-1) (2-3)] {} ;
-% \node [fit = (3-1) (3-3)] {} ;
+% \node [highlight = (1-1) (1-3)] {} ;
+% \node [highlight = (2-1) (2-3)] {} ;
+% \node [highlight = (3-1) (3-3)] {} ;
% \end{tikzpicture}}]
-% a & a + b & a + b + c & L_1\\
+% a & a + b & a + b + c & L_1 \\
% a & a & a + b & L_2 \\
% a & a & a & L_3
% \end{pNiceArray}\]
%
+%
%
% \vspace{1cm}
%
@@ -2403,8 +2457,8 @@ c & c & b & a & e
%
% \begin{Verbatim}
% \begin{tikzpicture}[remember picture, overlay]
-% \node [highlight, fit = (A-3-1) (A-3-5) ] {} ;
-% \node [highlight, fit = (B-1-3) (B-5-3) ] {} ;
+% \node [highlight = (A-3-1) (A-3-5) ] {} ;
+% \node [highlight = (B-1-3) (B-5-3) ] {} ;
% \draw [color = gray] (A-3-3) to [bend left] (B-3-3) ;
% \end{tikzpicture}
% \end{Verbatim}
@@ -2442,8 +2496,8 @@ c & c & b & a & e
% \end{NiceMatrixBlock}
%
% \begin{tikzpicture}[remember picture, overlay]
-% \node [highlight, fit = (A-3-1) (A-3-5) ] {} ;
-% \node [highlight, fit = (B-1-3) (B-5-3) ] {} ;
+% \node [highlight = (A-3-1) (A-3-5) ] {} ;
+% \node [highlight = (B-1-3) (B-5-3) ] {} ;
% \draw [color = gray] (A-3-3) to [bend left] (B-3-3) ;
% \end{tikzpicture}
%
@@ -2473,13 +2527,14 @@ c & c & b & a & e
%
% \subsection{Declaration of the package and extensions loaded}
%
+%<@@=nicematrix>
+%
+% \bigskip
% First, \pkg{tikz} and the Tikz library |fit| are loaded before the
% |\ProvidesExplPackage|. They are loaded this way because |\usetikzlibrary| in
% |expl3| code fails.\footnote{cf.
% |tex.stackexchange.com/questions/57424/using-of-usetikzlibrary-in-an-expl3-package-fails|}
%
-%<@@=nicematrix>
-%
% \begin{macrocode}
\RequirePackage{tikz}
\usetikzlibrary{fit}
@@ -2692,6 +2747,7 @@ c & c & b & a & e
{ }
}
% \end{macrocode}
+%
%
% \bigskip
% The length |\l_@@_inter_dots_dim| is the distance between two dots for the
@@ -2701,6 +2757,18 @@ c & c & b & a & e
\dim_new:N \l_@@_inter_dots_dim
\dim_set:Nn \l_@@_inter_dots_dim { 0.45 em }
% \end{macrocode}
+%
+% \bigskip
+% The length |\l_@@_dotted_lines_margin_dim| is the minimal distance between a
+% node (in fact an anchor of that node) and a dotted line (we say ``minimal''
+% because, by definition, a dotted line is not a continuous line and, therefore,
+% this distance may vary a little).
+% \begin{macrocode}
+\dim_new:N \l_@@_dotted_lines_margin_dim
+\dim_set:Nn \l_@@_dotted_lines_margin_dim { 0.3 em }
+% \end{macrocode}
+%
+% \bigskip
% The length |\l_@@_radius_dim| is the radius of the dots for the dotted lines.
% The default value is 0.34~pt but it will be changed if the option |small| is
% used.
@@ -2940,13 +3008,17 @@ c & c & b & a & e
}
}
% \end{macrocode}
-%
-%
+%
+%
% \bigskip
% \subsection{The options}
%
-%
-%
+% The boolean |\l_@@_light_syntax_bool| corresponds to the option |light-syntax|.
+% \begin{macrocode}
+\bool_new:N \l_@@_light_syntax_bool
+% \end{macrocode}
+%
+% \bigskip
% The token list |\l_@@_pos_env_str| will contain one of the three values |t|,
% |c| or |b| and will indicate the position of the environment as in the option
% of the environment |{array}|. For the environment |{pNiceMatrix}|,
@@ -3038,18 +3110,36 @@ c & c & b & a & e
\dim_new:N \l_@@_extra_right_margin_dim
% \end{macrocode}
%
+% \medskip
+% The token list |\l_@@_end_of_row_tl| corresponds to the option |end-of-row|.
+% It specifies the symbol used to mark the ends of rows when the light syntax is
+% used.
+% \begin{macrocode}
+\tl_new:N \l_@@_end_of_row_tl
+\tl_set:Nn \l_@@_end_of_row_tl { ; }
+% \end{macrocode}
%
-%
+%
% \bigskip
% First, we define a set of keys ``|NiceMatrix / Global|'' which will be used
% (with the mechanism of |.inherit:n|) by other sets of keys.
% \begin{macrocode}
\keys_define:nn { NiceMatrix / Global }
{
+ dotted-lines-margin .dim_set:N = \l_@@_dotted_lines_margin_dim ,
+ dotted-lines-margin .value_required:n = true ,
+ light-syntax .bool_set:N = \l_@@_light_syntax_bool ,
+ light-syntax .default:n = true ,
+ end-of-row .tl_set:N = \l_@@_end_of_row_tl ,
+ end-of-row .value_required:n = true ,
code-for-first-col .tl_set:N = \l_@@_code_for_first_col_tl ,
+ code-for-first-col .value_required:n = true ,
code-for-last-col .tl_set:N = \l_@@_code_for_last_col_tl ,
+ code-for-last-col .value_required:n = true ,
code-for-first-row .tl_set:N = \l_@@_code_for_first_row_tl ,
+ code-for-first-row .value_required:n = true ,
code-for-last-row .tl_set:N = \l_@@_code_for_last_row_tl ,
+ code-for-last-row .value_required:n = true ,
small .bool_set:N = \l_@@_small_bool ,
hlines .bool_set:N = \l_@@_hlines_bool ,
parallelize-diags .bool_set:N = \l_@@_parallelize_diags_bool ,
@@ -3061,6 +3151,7 @@ c & c & b & a & e
% |\Vdots| and |\Ddots|.
% \begin{macrocode}
renew-dots .bool_set:N = \l_@@_renew_dots_bool ,
+ renew-dots .value_forbidden:n = true ,
nullify-dots .bool_set:N = \l_@@_nullify_dots_bool ,
% \end{macrocode}
%
@@ -3081,21 +3172,7 @@ c & c & b & a & e
extra-left-margin .dim_set:N = \l_@@_extra_left_margin_dim ,
extra-right-margin .dim_set:N = \l_@@_extra_right_margin_dim ,
extra-margin .meta:n =
- { extra-left-margin = #1 , extra-right-margin = #1 } ,
-% \end{macrocode}
-% The following lines are the properties |.value_required:n| and
-% |.value_forbidden:n| or the keys. These properties have no effect because they
-% are not transmitted by inheritance (unfortunately). We maintain these lines in
-% the \textsc{dtx} only for the case of a modification of |l3keys|.
-%
-% \begin{macrocode}
-%<*comment>
- code-for-first-col .value_required:n = true ,
- code-for-last-col .value_required:n = true ,
- code-for-first-row .value_required:n = true ,
- code-for-last-row .value_required:n = true ,
- renew-dots .value_forbidden:n = true ,
-%</comment>
+ { extra-left-margin = #1 , extra-right-margin = #1 }
}
% \end{macrocode}
%
@@ -3109,6 +3186,7 @@ c & c & b & a & e
\str_if_eq:nnTF { #1 } { auto }
{ \bool_set_true:N \l_@@_auto_columns_width_bool }
{ \dim_set:Nn \l_@@_columns_width_dim { #1 } } ,
+ columns-width .value_required:n = true ,
name .code:n =
\unless \ifmeasuring@
\str_set:Nn \l_tmpa_str { #1 }
@@ -3117,26 +3195,17 @@ c & c & b & a & e
{ \seq_gput_left:NV \g_@@_names_seq \l_tmpa_str }
\str_set_eq:NN \l_@@_name_str \l_tmpa_str
\fi ,
+ name .value_required:n = true ,
code-after .tl_gset:N = \g_@@_code_after_tl ,
+ code-after .value_required:n = true ,
first-col .code:n = \int_zero:N \l_@@_first_col_int ,
first-row .code:n = \int_zero:N \l_@@_first_row_int ,
last-row .int_set:N = \l_@@_last_row_int ,
last-row .default:n = -1 ,
-% \end{macrocode}
-% The following lines are the properties |.value_required:n| and
-% |.value_forbidden:n| or the keys. These properties have no effect because they
-% are not transmitted by inheritance (unfortunately). We maintain these lines in
-% the \textsc{dtx} only for the case of a modification of |l3keys|.
-%
-% \begin{macrocode}
-%<*comment>
- columns-width .value_required:n = true ,
- name .value_required:n = true ,
- code-after .value_required:n = true ,
-%</comment>
}
% \end{macrocode}
-%
+%
+%
% \bigskip
% We begin the construction of the major sets of keys (used by the different
% user commands and environments).
@@ -3181,13 +3250,10 @@ c & c & b & a & e
% \begin{macrocode}
renew-matrix .code:n = \@@_renew_matrix: ,
renew-matrix .value_forbidden:n = true ,
- RenewMatrix .code:n = \@@_error:n { Option~RenewMatrix~suppressed }
- \@@_renew_matrix: ,
+ RenewMatrix .code:n = \@@_error:n { Option~RenewMatrix~suppressed } ,
transparent .meta:n = { renew-dots , renew-matrix } ,
transparent .value_forbidden:n = true,
- Transparent .code:n = \@@_error:n { Option~Transparent~suppressed }
- \@@_renew_matrix:
- \bool_set_true:N \l_@@_renew_dots_bool ,
+ Transparent .code:n = \@@_error:n { Option~Transparent~suppressed } ,
% \end{macrocode}
%
%
@@ -3296,7 +3362,7 @@ c & c & b & a & e
% be used without value because the number of columns of the array can be read
% in the preamble of the array.
% \begin{macrocode}
- last-col .code:n = \tl_if_empty:nF {#1}
+ last-col .code:n = \tl_if_empty:nF { #1 }
{ \@@_error:n { last-col~non~empty~for~NiceArray } }
\int_zero:N \l_@@_last_col_int ,
unknown .code:n = \@@_error:n { Unknown~option~for~NiceArray }
@@ -3359,12 +3425,9 @@ c & c & b & a & e
%
% We will call \emph{corners} of the matrix the cases which are at the
% intersection of the exterior rows and exterior columns (of course, the four
-% corners doesn't always exist simultaneously). In a corner of the matrix, it
-% would be logical to use none of the codes |\l_@@_code_for_first_row_tl| and
-% \emph{al}. As for now, this result is acheived only for the north-west corner
-% (this allows an automatic numerotation of the rows ans the columns with |iRow|
-% and |jCol| with the first col and the first row --- probably the preferential
-% choice for such a numerotation).
+% corners doesn't always exist simultaneously). The codes
+% |\l_@@_code_for_first_row_tl| and \emph{al} don't apply in the corners of the
+% matrix.
% \begin{macrocode}
\int_compare:nNnTF \c@iRow = \c_zero_int
{ \int_compare:nNnT \c@jCol > \c_zero_int \l_@@_code_for_first_row_tl }
@@ -3483,63 +3546,34 @@ c & c & b & a & e
\cs_new_protected:Nn \@@_renewcolumntype:nn
{
\newcolumntype #1 [ 2 ]
- {
- > {
+ {
+ > {
\hbox_set:Nw \l_tmpa_box
- \@@_Cell:
+ \_@@_Cell:
}
c
- < {
- \@@_end_Cell:
+ < {
+ \_@@_end_Cell:
\hbox_set_end:
- #2
- \hbox_set:Nn \l_tmpb_box
- { \makebox [ ##2 ] [ ##1 ] { \box_use:N \l_tmpa_box } }
- \dim_set:Nn \l_tmpa_dim { \box_dp:N \l_tmpb_box }
- \box_move_down:nn \l_tmpa_dim
- {
- \vbox:n
- {
- \hbox_to_wd:nn { \box_wd:N \l_tmpb_box }
- {
- \hfil
- \tikz [ remember~picture , overlay ]
- \coordinate (@@~north~east) ;
- }
- \hbox:n
- {
- \tikz [ remember~picture , overlay ]
- \coordinate (@@~south~west) ;
- \box_move_up:nn \l_tmpa_dim { \box_use:N \l_tmpb_box }
- }
- }
- }
-% \end{macrocode}
-% The |w|-node is created using the Tikz library |fit| after construction of the
-% nodes |(@@~south~west)| and |(@@~north~east)|. It's not possible to construct
-% by a standard |node| instruction because such a construction give an erroneous
-% result with some engines (|XeTeX|, |LuaTeX|) although the result is good with
-% |pdflatex| (why?).
-% \begin{macrocode}
- \tikz [ remember~picture , overlay ]
- \node
+ #2
+ \tikz [ remember~picture ]
+ \node
[
- node~contents = { } ,
name = nm - \int_use:N \g_@@_env_int -
\int_use:N \c@iRow -
\int_use:N \c@jCol - w,
- alias =
+ alias =
\str_if_empty:NF \l_@@_name_str
- {
+ {
\l_@@_name_str -
\int_use:N \c@iRow -
- \int_use:N \c@jCol - w
+ \int_use:N \c@jCol - w
} ,
inner~sep = \c_zero_dim ,
- fit = (@@~south~west) (@@~north~east)
- ]
+ ]
+ { \makebox [ ##2 ] [ ##1 ] { \box_use:N \l_tmpa_box } }
;
- }
+ }
}
}
% \end{macrocode}
@@ -4012,8 +4046,8 @@ c & c & b & a & e
}
% \end{macrocode}
%
-% The code in |\@@_pre_array:| is common to |{NiceArrayWithDelims}| and
-% |{NiceMatrix}|.
+% The code in |\@@_pre_array:| is used only by |{NiceArrayWithDelims}|. It
+% exists only for historical reasons. We should change that.
% \begin{macrocode}
\@@_pre_array:
% \end{macrocode}
@@ -4036,7 +4070,6 @@ c & c & b & a & e
\c_math_toggle_token
\left #1 \vcenter to 3 cm { } \right.
\c_math_toggle_token
-
}
\dim_gset:Nn \g_@@_left_delim_dim { \box_wd:N \l_tmpa_box }
\hbox_set:Nn \l_tmpa_box
@@ -4089,119 +4122,28 @@ c & c & b & a & e
\skip_horizontal:n \l_@@_left_margin_dim
\skip_horizontal:n \l_@@_extra_left_margin_dim
\c_math_toggle_token
-% \end{macrocode}
-% Here is the call to |\array| (we have a dedicated macro |\@@_array:| because
-% of compatibility with the classes \cls{revtex4-1} and \cls{revtex4-2}).
-% \begin{macrocode}
- \exp_args:NV \@@_array: \l_tmpa_tl
+ \bool_if:NTF \l_@@_light_syntax_bool
+ { \begin { @@-light-syntax } }
+ { \begin { @@-normal-syntax } }
}
% \end{macrocode}
%
-% \bigskip
-% We begin the second part of the environment |{NiceArrayWithDelims}|. If all
-% the columns must have the same width (if the user has used the option
-% |columns-width| or the option |auto-column-width| of the environment
-% |{NiceMatrixBlock}|), we add a row in the array to fix the width of the
-% columns and construct the ``|col|'' nodes |nm-|\textsl{a}|-col-|\textsl{j}
-% (these nodes will be used by the horizontal open dotted lines and by the
-% commands |\@@_vdottedline:n|).
%
% \begin{macrocode}
- {
- \bool_if:nT
- {
- \l_@@_auto_columns_width_bool
- || \dim_compare_p:nNn \l_@@_columns_width_dim > \c_zero_dim
- }
- {
- \crcr
- \int_compare:nNnT \l_@@_first_col_int = 0 { \omit & }
- \omit
-% \end{macrocode}
-% First, we put a ``|col|'' node on the left of the first column (of course, we
-% have to do that \emph{after} the |\omit|).
-% \begin{macrocode}
- \skip_horizontal:N \arraycolsep
- \tikz [ remember~picture , overlay ]
- \coordinate [ name = nm - \int_use:N \g_@@_env_int - col - 0 ] ;
- \skip_horizontal:n { - \arraycolsep }
-% \end{macrocode}
-% We compute in |\g_tmpa_dim| the common width of the columns. We use a global
-% variable because we are in a cell of an |\halign| and because we have to use this
-% variable in other cells (of the same row). The affectation of |\g_tmpa_dim|,
-% like all the affectations, must be done after the |\omit| of the cell.
-% \begin{macrocode}
- \bool_if:nTF
- {
- \l_@@_auto_columns_width_bool
- && ! \l_@@_block_auto_columns_width_bool
- }
- {
- \dim_gset:Nn \g_tmpa_dim
- { \g_@@_max_cell_width_dim + 2 \arraycolsep }
- }
- {
- \dim_gset:Nn \g_tmpa_dim
- { \l_@@_columns_width_dim + 2 \arraycolsep }
- }
- \skip_horizontal:N \g_tmpa_dim
- \tikz [ remember~picture , overlay ]
- \coordinate [ name = nm - \int_use:N \g_@@_env_int - col - 1 ] ;
-% \end{macrocode}
-% We begin a loop over the columns. The integer |\g_tmpa_int| will be the
-% number of the current column. This integer is not used to fix the
-% width of the column (since all the columns have the same width equal to
-% |\g_@@_tmpa_dim|) but for the Tikz nodes.
-% \begin{macrocode}
- \int_gset:Nn \g_tmpa_int 1
- \bool_if:nTF \g_@@_last_col_found_bool
- { \prg_replicate:nn { \g_@@_col_total_int - 3 } }
- { \prg_replicate:nn { \g_@@_col_total_int - 2 } }
- {
- &
- \omit
-% \end{macrocode}
-% The incrementation of the counter |\g_tmpa_int| must be done after the |\omit|
-% of the cell.
-% \begin{macrocode}
- \int_gincr:N \g_tmpa_int
- \skip_horizontal:N \g_tmpa_dim
-% \end{macrocode}
-% We create a ``|col|'' node on the right of the current column.
-% \begin{macrocode}
- \tikz [ remember~picture , overlay ]
- \coordinate
- [
- name = nm - \int_use:N \g_@@_env_int -
- col - \int_use:N \g_tmpa_int
- ] ;
- }
-% \end{macrocode}
-% For the last column, we want a special treatment because of the final
-% |\arraycolsep|.
-% \begin{macrocode}
- &
- \omit
- \int_gincr:N \g_tmpa_int
- \skip_horizontal:N \g_tmpa_dim
- \skip_horizontal:n { - \arraycolsep }
- \tikz [ remember~picture , overlay ]
- \coordinate
- [
- name = nm - \int_use:N \g_@@_env_int -
- col - \int_use:N \g_tmpa_int
- ] ;
- \skip_horizontal:N \arraycolsep
- }
- \endarray
+ {
+ \bool_if:NTF \l_@@_light_syntax_bool
+ { \end { @@-light-syntax } }
+ { \end { @@-normal-syntax } }
\c_math_toggle_token
\skip_horizontal:n \l_@@_right_margin_dim
\skip_horizontal:n \l_@@_extra_right_margin_dim
\hbox_set_end:
% \end{macrocode}
-%
+% Now, the box containing the array is constructed (in |\l_@@_the_array_box|).
+% However, we have some computations to do before inserting that box in the TeX
+% flow (mainly because the exterior columns are in overlapping positions).
+%
% \bigskip
-%
% \begin{macrocode}
\int_compare:nNnT \l_@@_last_row_int > { -2 }
{
@@ -4216,7 +4158,6 @@ c & c & b & a & e
}
% \end{macrocode}
%
-%
% Now, we compute |\l_tmpa_dim| which is the vertical dimension of the ``first
% row'' above the array (when the key |first-row| is used).
% \begin{macrocode}
@@ -4338,6 +4279,195 @@ c & c & b & a & e
%
%
% \interitem
+% The construction of the array in the environment |{NiceArrayWithDelims}| is,
+% in fact, done by the environment |{@@-light-syntax}| or by the environment
+% |{@@-normal-syntax}| (whether the option |light-syntax| is used or not). When
+% the key |light-syntax| is not used, the construction is a standard
+% environment (and, thus, it's possible to use verbatim in the arrray).
+% \begin{macrocode}
+\NewDocumentEnvironment { @@-normal-syntax } { }
+% \end{macrocode}
+% Here is the call to |\array| (we have a dedicated macro |\@@_array:| because
+% of compatibility with the classes \cls{revtex4-1} and \cls{revtex4-2}).
+% \begin{macrocode}
+ { \exp_args:NV \@@_array: \l_tmpa_tl }
+ {
+% \end{macrocode}
+%
+% If all the columns must have the same width (if the user has used the option
+% |columns-width| or the option |auto-column-width| of the environment
+% |{NiceMatrixBlock}|), we will add a row in the array to fix the width of the
+% columns and construct the ``|col|'' nodes |nm-|\textsl{a}|-col-|\textsl{j}
+% (these nodes will be used by the horizontal open dotted lines and by the
+% commands |\@@_vdottedline:n|). We have written a dedicated function for that job.
+% \begin{macrocode}
+ \@@_create_row_of_col_nodes:
+ \endarray
+ }
+% \end{macrocode}
+%
+%
+% \bigskip
+% When the key |light-syntax| is used, we use an environment which takes its whole
+% body as an argument (with the specifier |b| of \pkg{xparse}).
+% \begin{macrocode}
+\NewDocumentEnvironment { @@-light-syntax } { b }
+ {
+% \end{macrocode}
+% Here is the call to |\array| (we have a dedicated macro |\@@_array:| because
+% of compatibility with the classes \cls{revtex4-1} and \cls{revtex4-2}).
+% \begin{macrocode}
+ \exp_args:NV \@@_array: \l_tmpa_tl
+% \end{macrocode}
+% The body of the environment, which is stored in the argument |#1|, is now
+% splitted into items (and \emph{not} tokens)
+% \begin{macrocode}
+ \seq_gclear_new:N \g_@@_rows_seq
+ \tl_set_rescan:Nno \l_@@_end_of_row_tl { } \l_@@_end_of_row_tl
+ \exp_args:NNV \seq_gset_split:Nnn \g_@@_rows_seq \l_@@_end_of_row_tl { #1 }
+% \end{macrocode}
+% We need a global affectation because, when executing |\l_tmpa_tl|, we will
+% exit the first cell of the array.
+% \begin{macrocode}
+ \seq_gpop_left:NN \g_@@_rows_seq \l_tmpa_tl
+ \exp_args:NV \@@_line_with_light_syntax_i:n \l_tmpa_tl
+ \seq_map_function:NN \g_@@_rows_seq \@@_line_with_light_syntax:n
+ \@@_create_row_of_col_nodes:
+ \endarray
+ }
+% \end{macrocode}
+% Now, the second part of the environment. It is empty. That's not surprising
+% because we have caught the whole body of the environment with the specifier
+% |b| provided by \pkg{xparse}.
+% \begin{macrocode}
+ { }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_line_with_light_syntax_i:n #1
+ {
+ \seq_gclear_new:N \g_@@_cells_seq
+ \seq_gset_split:Nnn \g_@@_cells_seq { ~ } { #1 }
+ \seq_gpop_left:NN \g_@@_cells_seq \l_tmpa_tl
+ \l_tmpa_tl
+ \seq_map_function:NN \g_@@_cells_seq \@@_cell_with_light_syntax:n
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_line_with_light_syntax:n #1
+ {
+ \tl_if_empty:nF { #1 }
+ { \\ \@@_line_with_light_syntax_i:n { #1 } }
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_cell_with_light_syntax:n #1 { & #1 }
+% \end{macrocode}
+%
+% \bigskip
+% The command |\@@_create_row_of_col_nodes:| will construct the potential last
+% row. That last row (when it is created) is a false row used to fix the width
+% of the columns (when the array is constructed with an option whhich specify
+% the width of the columns) and create the |col|-nodes (that nodes will be used
+% by |\vdottedline| for instance).
+% \begin{macrocode}
+\cs_new:Npn \@@_create_row_of_col_nodes:
+ {
+ \bool_if:nT
+ {
+ \l_@@_auto_columns_width_bool
+ || \dim_compare_p:nNn \l_@@_columns_width_dim > \c_zero_dim
+ }
+ {
+ \crcr
+ \int_compare:nNnT \l_@@_first_col_int = 0 { \omit & }
+ \omit
+% \end{macrocode}
+% First, we put a ``|col|'' node on the left of the first column (of course, we
+% have to do that \emph{after} the |\omit|).
+% \begin{macrocode}
+ \skip_horizontal:N \arraycolsep
+ \tikz [ remember~picture , overlay ]
+ \coordinate [ name = nm - \int_use:N \g_@@_env_int - col - 0 ] ;
+ \skip_horizontal:n { - \arraycolsep }
+% \end{macrocode}
+% We compute in |\g_tmpa_dim| the common width of the columns. We use a global
+% variable because we are in a cell of an |\halign| and because we have to use this
+% variable in other cells (of the same row). The affectation of |\g_tmpa_dim|,
+% like all the affectations, must be done after the |\omit| of the cell.
+% \begin{macrocode}
+ \bool_if:nTF
+ {
+ \l_@@_auto_columns_width_bool
+ && ! \l_@@_block_auto_columns_width_bool
+ }
+ {
+ \dim_gset:Nn \g_tmpa_dim
+ { \g_@@_max_cell_width_dim + 2 \arraycolsep }
+ }
+ {
+ \dim_gset:Nn \g_tmpa_dim
+ { \l_@@_columns_width_dim + 2 \arraycolsep }
+ }
+ \skip_horizontal:N \g_tmpa_dim
+ \tikz [ remember~picture , overlay ]
+ \coordinate [ name = nm - \int_use:N \g_@@_env_int - col - 1 ] ;
+% \end{macrocode}
+% We begin a loop over the columns. The integer |\g_tmpa_int| will be the
+% number of the current column. This integer is not used to fix the
+% width of the column (since all the columns have the same width equal to
+% |\g_@@_tmpa_dim|) but for the Tikz nodes.
+% \begin{macrocode}
+ \int_gset:Nn \g_tmpa_int 1
+ \bool_if:nTF \g_@@_last_col_found_bool
+ { \prg_replicate:nn { \g_@@_col_total_int - 3 } }
+ { \prg_replicate:nn { \g_@@_col_total_int - 2 } }
+ {
+ &
+ \omit
+% \end{macrocode}
+% The incrementation of the counter |\g_tmpa_int| must be done after the |\omit|
+% of the cell.
+% \begin{macrocode}
+ \int_gincr:N \g_tmpa_int
+ \skip_horizontal:N \g_tmpa_dim
+% \end{macrocode}
+% We create a ``|col|'' node on the right of the current column.
+% \begin{macrocode}
+ \@@_create_col_node:
+ }
+% \end{macrocode}
+% For the last column, we want a special treatment because of the final
+% |\arraycolsep|.
+% \begin{macrocode}
+ &
+ \omit
+ \int_gincr:N \g_tmpa_int
+ \skip_horizontal:N \g_tmpa_dim
+ \skip_horizontal:n { - \arraycolsep }
+ \@@_create_col_node:
+ \skip_horizontal:N \arraycolsep
+ }
+ }
+% \end{macrocode}
+%
+% \bigskip
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_create_col_node:
+ {
+ \tikz [ remember~picture , overlay ]
+ \coordinate
+ [
+ name = nm - \int_use:N \g_@@_env_int -
+ col - \int_use:N \g_tmpa_int
+ ] ;
+ }
+% \end{macrocode}
+%
+%
+% \interitem
% Here is the preamble for the ``first column'' (if the user uses the key
% |first-col|)
% \begin{macrocode}
@@ -4853,8 +4983,8 @@ c & c & b & a & e
\bool_if:nTF \g_@@_medium_nodes_bool
{
\bool_if:NTF \g_@@_large_nodes_bool
- \@@_create_medium_and_large_nodes:
- \@@_create_medium_nodes:
+ \@@_create_medium_and_large_nodes:
+ \@@_create_medium_nodes:
}
{ \bool_if:NT \g_@@_large_nodes_bool \@@_create_large_nodes: }
\int_zero_new:N \l_@@_initial_i_int
@@ -4926,11 +5056,11 @@ c & c & b & a & e
% a & a+b & a+b+c
% \end{pNiceMatrix}\]
% For a closed extremity, we use the normal node and for a open one, we use the
-% ``medium node'' or, if it exists, the |w|~node.
+% ``medium node'' or, if it exists, the |w|-node.
% \[ \begin{pNiceMatrix}[create-medium-nodes,
% code-after = {\begin{tikzpicture}
-% \node [highlight, fit={(2-1)}] {} ;
-% \node [highlight, fit={(2-3-medium)}] {};
+% \node [highlight = (2-1)] {} ;
+% \node [highlight = (2-3-medium) ] {};
% \end{tikzpicture}
% }]
% a+b+c & a+b & a\\
@@ -5149,7 +5279,7 @@ c & c & b & a & e
% \end{macrocode}
% If we have at least one open extremity, we create the ``medium nodes'' in the
% matrix\footnote{We should change this. Indeed, for an open extremity of an
-% \emph{horizontal} dotted line, we use the |w|~node, if, it exists, and not the
+% \emph{horizontal} dotted line, we use the |w|-node, if, it exists, and not the
% ``medium node''.}. We remind that, when used once, the command
% |\@@_create_medium_nodes:| becomes no-op in the current TeX group.
% \begin{macrocode}
@@ -5264,7 +5394,7 @@ c & c & b & a & e
\bool_if:NTF \l_@@_initial_open_bool
{
% \end{macrocode}
-% If a |w| node exists we use the |w| node for the extremity.
+% If a |w|-node exists we use the |w|-node for the extremity.
% \begin{macrocode}
\cs_if_exist:cTF
{
@@ -5606,18 +5736,30 @@ c & c & b & a & e
}
{
\int_set:Nn \l_tmpa_int
- { \dim_ratio:nn { \l_@@_l_dim - 0.3 em } \l_@@_inter_dots_dim }
+ {
+ \dim_ratio:nn
+ { \l_@@_l_dim - \l_@@_dotted_lines_margin_dim }
+ \l_@@_inter_dots_dim
+ }
}
}
{
\bool_if:NTF \l_@@_final_open_bool
{
\int_set:Nn \l_tmpa_int
- { \dim_ratio:nn { \l_@@_l_dim - 0.3 em } \l_@@_inter_dots_dim }
+ {
+ \dim_ratio:nn
+ { \l_@@_l_dim - \l_@@_dotted_lines_margin_dim }
+ \l_@@_inter_dots_dim
+ }
}
{
\int_set:Nn \l_tmpa_int
- { \dim_ratio:nn { \l_@@_l_dim - 0.6 em } \l_@@_inter_dots_dim}
+ {
+ \dim_ratio:nn
+ { \l_@@_l_dim - ( \l_@@_dotted_lines_margin_dim * 2 ) }
+ \l_@@_inter_dots_dim
+ }
}
}
% \end{macrocode}
@@ -6217,7 +6359,7 @@ c & c & b & a & e
\int_compare:nNnF \c@iRow = \c_zero_int
{
\int_compare:nNnF \c@iRow = \l_@@_last_row_int
- \@@_vline_i:
+ \@@_vline_i:
}
}
}
@@ -6440,12 +6582,12 @@ c & c & b & a & e
{
\begin { tikzpicture } [ remember~picture , overlay ]
\@@_computations_for_medium_nodes:
+ \tikzset { name~suffix = -medium }
% \end{macrocode}
% Now, we can create the ``medium nodes''. We use a command |\@@_create_nodes:|
% because this command will also be used for the creation of the ``large nodes''
% (after changing the value of |name-suffix|).
% \begin{macrocode}
- \tikzset { name~suffix = -medium }
\@@_create_nodes:
\end { tikzpicture }
\cs_set_protected:Npn \@@_create_medium_nodes: { }
@@ -6484,6 +6626,7 @@ c & c & b & a & e
{
\begin { tikzpicture } [ remember~picture , overlay ]
\@@_computations_for_medium_nodes:
+% \end{macrocode}
% Now, we can create the ``medium nodes''. We use a command |\@@_create_nodes:|
% because this command will also be used for the creation of the ``large nodes''
% (after changing the value of |name-suffix|).
@@ -6944,6 +7087,7 @@ c & c & b & a & e
% \subsection{Error messages of the package}
%
%
+%
% \begin{macrocode}
\@@_msg_new:nn { unknown~cell~for~line~in~code-after }
{
@@ -7025,7 +7169,7 @@ c & c & b & a & e
\@@_msg_new:nn { Option~Transparent~suppressed }
{
The~option~'Transparent'~has~been~renamed~'transparent'.\\
- However,~you~can~go~on~for~this~time.
+ If~you~go~on~this~command~will~be~ignored.
}
% \end{macrocode}
%
@@ -7033,7 +7177,7 @@ c & c & b & a & e
\@@_msg_new:nn { Option~RenewMatrix~suppressed }
{
The~option~'RenewMatrix'~has~been~renamed~'renew-matrix'.\\
- However,~you~can~go~on~for~this~time.
+ If~you~go~on~this~command~will~be~ignored.
}
% \end{macrocode}
%
@@ -7064,16 +7208,19 @@ c & c & b & a & e
create-extra-nodes,~
create-medium-nodes,~
create-large-nodes,~
+ dotted-lines-margin,~
+ end-of-row,~
exterior-arraycolsep,~
hlines,~
left-margin,~
letter-for-dotted-lines,~
+ light-syntax,~
nullify-dots,~
parallelize-diags,~
renew-dots,~
renew-matrix,~
right-margin,~
- small~
+ small,~
and~transparent
}
% \end{macrocode}
@@ -7099,6 +7246,8 @@ c & c & b & a & e
create-extra-nodes,~
create-medium-nodes,~
create-large-nodes,~
+ dotted-lines-margin,~
+ end-of-row,~
extra-left-margin,~
extra-right-margin,~
first-col,~
@@ -7107,12 +7256,13 @@ c & c & b & a & e
last-col,~
last-row,~
left-margin,~
+ light-syntax,~
name,~
nullify-dots,~
parallelize-diags,~
renew-dots,~
right-margin,~
- small~
+ small,~
and~t.
}
% \end{macrocode}
@@ -7140,6 +7290,8 @@ c & c & b & a & e
create-extra-nodes,~
create-medium-nodes,~
create-large-nodes,~
+ dotted-lines-margin,~
+ end-of-row,~
extra-left-margin,~
extra-right-margin,~
first-col,~
@@ -7148,26 +7300,25 @@ c & c & b & a & e
last-col,~
last-row,~
left-margin,~
+ light-syntax,~
name,~
nullify-dots,~
parallelize-diags,~
renew-dots,~
- right-margin~
+ right-margin,~
and~small.
}
% \end{macrocode}
%
-% The following message should be changed because, normally, there can be any
-% longer artefact in the environments of \pkg{amsmath}.
+%
% \begin{macrocode}
\@@_msg_new:nnn { Duplicate~name }
{
The~name~'\l_keys_value_tl'~is~already~used~and~you~shouldn't~use~
the~same~environment~name~twice.~You~can~go~on,~but,~
maybe,~you~will~have~incorrect~results~especially~
- if~you~use~'columns-width=auto'.~If~you~use~nicematrix~inside~some~
- environments~of~amsmath,~this~error~may~be~an~artefact.~In~this~case,~
- use~the~option~'allow-duplicate-names'.\\
+ if~you~use~'columns-width=auto'.~If~you~don't~want~to~see~this~
+ message~again,~use~the~option~'allow-duplicate-names'.\\
For~a~list~of~the~names~already~used,~type~H~<return>. \\
}
{
@@ -7582,15 +7733,20 @@ c & c & b & a & e
%
% New options |create-medium-nodes| and |create-large-nodes|.
%
+% \subsection*{Changes between version 3.9 and 3.10}
+%
+% New option |light-syntax| (and |end-of-row|).
+%
+% New option |dotted-lines-margin| for fine tuning of the dotted lines.
+%
% \PrintIndex
%
% \tableofcontents
-% \endinput
%
+% \endinput
% Local Variables:
% TeX-fold-mode: t
% TeX-fold-preserve-comments: nil
-% ispell-local-dictionary: english
% fill-column: 80
% End:
diff --git a/macros/latex/contrib/nicematrix/nicematrix.pdf b/macros/latex/contrib/nicematrix/nicematrix.pdf
index 01f2e3261b..c4738a0111 100644
--- a/macros/latex/contrib/nicematrix/nicematrix.pdf
+++ b/macros/latex/contrib/nicematrix/nicematrix.pdf
Binary files differ
diff --git a/macros/latex/contrib/parskip/changes.txt b/macros/latex/contrib/parskip/changes.txt
index e76b860cb9..6ada7d93b6 100644
--- a/macros/latex/contrib/parskip/changes.txt
+++ b/macros/latex/contrib/parskip/changes.txt
@@ -1,3 +1,9 @@
+#### placed on CTAN as 2.0d ####
+
+ 2020-01-22 Frank Mittelbach <Frank.Mittelbach@latex-project.org>
+
+ * distribution cleanup no code change
+
2019-01-16 Frank Mittelbach <Frank.Mittelbach@latex-project.org>
* parskip.dtx (subsubsection{Option handling}):
diff --git a/macros/latex/contrib/parskip/parskip-code.pdf b/macros/latex/contrib/parskip/parskip-code.pdf
index 453269b738..1127576e80 100644
--- a/macros/latex/contrib/parskip/parskip-code.pdf
+++ b/macros/latex/contrib/parskip/parskip-code.pdf
Binary files differ
diff --git a/macros/latex/contrib/parskip/parskip.dtx b/macros/latex/contrib/parskip/parskip.dtx
index 731cb2a9f4..dd0a6b07df 100644
--- a/macros/latex/contrib/parskip/parskip.dtx
+++ b/macros/latex/contrib/parskip/parskip.dtx
@@ -3,7 +3,7 @@
%% File: parskip.dtx
%% (C) Copyright 1989 H.Partl, TU Wien
%% (C) Copyright 2001 Robin Fairbairns
-%% (C) Copyright 2018-2019 Frank Mittelbach
+%% (C) Copyright 2018-2020 Frank Mittelbach
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -108,7 +108,7 @@
% not given (or given without a value) then \verb=.5\baselineskip=
% plus \texttt{2pt} of stretch is assumed.
% \item[\option{indent}]
-% With the package option \texttt{indent} it is possible to explicitly
+% With the package option \texttt{indent} it is possible to explicitly set
% the paragraph indentation. Using this option without a value keeps the
% document class indentation unchanged, if it is specified with a
% value then that value is used. If the package is loaded without
@@ -177,7 +177,7 @@
% \end{macrocode}
%
% \begin{macrocode}
-\ProvidesPackage{parskip}[2019-01-16 v2.0c non-zero parskip adjustments]
+\ProvidesPackage{parskip}[2020-01-22 v2.0d non-zero parskip adjustments]
% \end{macrocode}
%
%
diff --git a/macros/latex/contrib/parskip/parskip.ins b/macros/latex/contrib/parskip/parskip.ins
index 4ea23e43b7..306d69304e 100644
--- a/macros/latex/contrib/parskip/parskip.ins
+++ b/macros/latex/contrib/parskip/parskip.ins
@@ -35,7 +35,7 @@
This is a generated file.
-Copyright 2018 Frank Mittelbach
+Copyright 2018-2020 Frank Mittelbach
This file was generated from file(s) of the LaTeX `parskip Bundle'.
-------------------------------------------------------------------
@@ -46,7 +46,7 @@ of this license or (at your option) any later version.
The latest version of this license is in
http://www.latex-project.org/lppl.txt
and version 1.3c or later is part of all distributions of LaTeX
-version 2005/12/01 or later.
+version 2008 or later.
This file may only be distributed together with a copy of the LaTeX
`parskip Bundle'. You may however distribute the `parskip Bundle'
diff --git a/macros/latex/contrib/parskip/parskip.pdf b/macros/latex/contrib/parskip/parskip.pdf
index 9d13c7e913..3672f9caf7 100644
--- a/macros/latex/contrib/parskip/parskip.pdf
+++ b/macros/latex/contrib/parskip/parskip.pdf
Binary files differ
diff --git a/macros/latex/contrib/widows-and-orphans/README.md b/macros/latex/contrib/widows-and-orphans/README.md
index 147333ff6b..0275059b8e 100644
--- a/macros/latex/contrib/widows-and-orphans/README.md
+++ b/macros/latex/contrib/widows-and-orphans/README.md
@@ -14,7 +14,7 @@ Package source can be found below:
https://github.com/FrankMittelbach/fmitex/
-The license is LPPL.
+The license is LPPL 1.3c.
A general discussion on how to manage widows and orphans can be found in a TugBoat article located at
@@ -22,7 +22,7 @@ https://www.latex-project.org/publications/indexbytopic/2e-packages/
-----
-Copyright (C) 2018 Frank Mittelbach<br />
+Copyright (C) 2018-2020 Frank Mittelbach<br />
<https://latex-project.org/> <br />
All rights reserved.
diff --git a/macros/latex/contrib/widows-and-orphans/changes.txt b/macros/latex/contrib/widows-and-orphans/changes.txt
index 398f99f7d0..018420535d 100644
--- a/macros/latex/contrib/widows-and-orphans/changes.txt
+++ b/macros/latex/contrib/widows-and-orphans/changes.txt
@@ -1,3 +1,9 @@
+2020-01-22 Frank Mittelbach <Frank.Mittelbach@latex-project.org>
+
+ * widows-and-orphans.dtx:
+
+ Version 1.0c was a maintenance release without any code changes.
+
2018-11-18 <Frank.Mittelbach@latex-project.org>
* widows-and-orphans.dtx: Surplus open parenthese in message,
diff --git a/macros/latex/contrib/widows-and-orphans/widows-and-orphans-code.pdf b/macros/latex/contrib/widows-and-orphans/widows-and-orphans-code.pdf
index 2c8da3b152..4e555c1dc9 100644
--- a/macros/latex/contrib/widows-and-orphans/widows-and-orphans-code.pdf
+++ b/macros/latex/contrib/widows-and-orphans/widows-and-orphans-code.pdf
Binary files differ
diff --git a/macros/latex/contrib/widows-and-orphans/widows-and-orphans-doc.pdf b/macros/latex/contrib/widows-and-orphans/widows-and-orphans-doc.pdf
index b432515a1e..79cc9ef6fd 100644
--- a/macros/latex/contrib/widows-and-orphans/widows-and-orphans-doc.pdf
+++ b/macros/latex/contrib/widows-and-orphans/widows-and-orphans-doc.pdf
Binary files differ
diff --git a/macros/latex/contrib/widows-and-orphans/widows-and-orphans.dtx b/macros/latex/contrib/widows-and-orphans/widows-and-orphans.dtx
index bef8cd4a69..ddf05363e1 100644
--- a/macros/latex/contrib/widows-and-orphans/widows-and-orphans.dtx
+++ b/macros/latex/contrib/widows-and-orphans/widows-and-orphans.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%%
-%% File: widows-and-orphans.dtx (C) Copyright 2017-2018 Frank Mittelbach
+%% File: widows-and-orphans.dtx (C) Copyright 2017-2020 Frank Mittelbach
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -334,7 +334,7 @@
% \end{figure}
%
% \begin{macrocode}
-\ProvidesExplPackage{widows-and-orphans}{2018/11/18}{v1.0b}
+\ProvidesExplPackage{widows-and-orphans}{2020/01/22}{v1.0c}
{Detecting widows and orphans (FMi)}
% \end{macrocode}
%
diff --git a/macros/latex/contrib/widows-and-orphans/widows-and-orphans.ins b/macros/latex/contrib/widows-and-orphans/widows-and-orphans.ins
index 916cab227c..344a5148bd 100644
--- a/macros/latex/contrib/widows-and-orphans/widows-and-orphans.ins
+++ b/macros/latex/contrib/widows-and-orphans/widows-and-orphans.ins
@@ -35,7 +35,7 @@
This is a generated file.
-Copyright 2017-2018 Frank Mittelbach
+Copyright 2017-2020 Frank Mittelbach
This file was generated from file(s) of the LaTeX windows-and-orphans Bundle.
@@ -47,7 +47,7 @@ of this license or (at your option) any later version.
The latest version of this license is in
https://www.latex-project.org/lppl/
and version 1.3c or later is part of all distributions of LaTeX
-version 2005/12/01 or later.
+version 2008 or later.
This file may only be distributed together with a copy of the LaTeX
windows-and-orphans Bundle. You may however distribute the Bundle