summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/easyfloats
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2020-12-21 03:01:35 +0000
committerNorbert Preining <norbert@preining.info>2020-12-21 03:01:35 +0000
commit4cc7922324b7a08ba0418e8f245cf1dcfa1891ac (patch)
treecd90cb6c072285e779f7555a85966b81a8757e15 /macros/latex/contrib/easyfloats
parent2d9d44100d72263a7df34c12aaa89dbe6ee6fe0c (diff)
CTAN sync 202012210301
Diffstat (limited to 'macros/latex/contrib/easyfloats')
-rw-r--r--macros/latex/contrib/easyfloats/DEPENDS.txt14
-rw-r--r--macros/latex/contrib/easyfloats/README.md49
-rw-r--r--macros/latex/contrib/easyfloats/doc/content/bug-reports-and-contributions.tex41
-rw-r--r--macros/latex/contrib/easyfloats/doc/content/documentation.tex1082
-rw-r--r--macros/latex/contrib/easyfloats/doc/content/examples.tex355
-rw-r--r--macros/latex/contrib/easyfloats/doc/content/installation.tex8
-rw-r--r--macros/latex/contrib/easyfloats/doc/content/license.tex17
-rw-r--r--macros/latex/contrib/easyfloats/doc/content/motivation.tex378
-rw-r--r--macros/latex/contrib/easyfloats/doc/content/names.tex18
-rw-r--r--macros/latex/contrib/easyfloats/doc/content/other-packages.tex51
-rw-r--r--macros/latex/contrib/easyfloats/doc/content/titlepage.tex17
-rw-r--r--macros/latex/contrib/easyfloats/doc/content/used-packages.tex29
-rw-r--r--macros/latex/contrib/easyfloats/doc/easyfloats.bib141
-rw-r--r--macros/latex/contrib/easyfloats/doc/easyfloats.pdfbin0 -> 546772 bytes
-rw-r--r--macros/latex/contrib/easyfloats/doc/easyfloats.tex63
-rw-r--r--macros/latex/contrib/easyfloats/doc/lexer/latex_atletter.py17
-rw-r--r--macros/latex/contrib/easyfloats/doc/links.tex44
-rw-r--r--macros/latex/contrib/easyfloats/doc/preamble/bibliography.tex35
-rw-r--r--macros/latex/contrib/easyfloats/doc/preamble/description-links.tex224
-rw-r--r--macros/latex/contrib/easyfloats/doc/preamble/examplecode.tex778
-rw-r--r--macros/latex/contrib/easyfloats/doc/preamble/keydoc.tex754
-rw-r--r--macros/latex/contrib/easyfloats/doc/preamble/link.tex53
-rw-r--r--macros/latex/contrib/easyfloats/doc/preamble/macros.tex218
-rw-r--r--macros/latex/contrib/easyfloats/doc/preamble/markdown.tex153
-rw-r--r--macros/latex/contrib/easyfloats/doc/preamble/pdfstring.tex35
-rw-r--r--macros/latex/contrib/easyfloats/doc/undescribed-keywords.tex247
-rw-r--r--macros/latex/contrib/easyfloats/easyfloats-file-list.txt40
-rw-r--r--macros/latex/contrib/easyfloats/easyfloats.dtx1897
-rw-r--r--macros/latex/contrib/easyfloats/easyfloats.ins82
29 files changed, 6840 insertions, 0 deletions
diff --git a/macros/latex/contrib/easyfloats/DEPENDS.txt b/macros/latex/contrib/easyfloats/DEPENDS.txt
new file mode 100644
index 0000000000..2f8165695e
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/DEPENDS.txt
@@ -0,0 +1,14 @@
+# packages loaded by default
+float
+caption
+subcaption
+graphicx # can be disabled using package option nographic
+pgfkeys
+etoolbox
+environ
+array # can be disabled using package option noarray
+booktabs # can be disabled using package option nobooktabs
+
+# packages loaded if the corresponding package option is given
+soft longtable
+soft graphbox
diff --git a/macros/latex/contrib/easyfloats/README.md b/macros/latex/contrib/easyfloats/README.md
new file mode 100644
index 0000000000..58cca59837
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/README.md
@@ -0,0 +1,49 @@
+# Abstract
+
+In standard LaTeX inserting objects like figures or tables requires too much knowledge for beginners and too much typing effort and hardcoding for people like me.
+This package aims to make insertion of figures and tables easier for both beginners and experts.
+Despite the term *floats* in it's name it also allows to disable floating of such objects.
+
+
+# Documentation
+
+The documentation is contained in the file [doc/easyfloats.pdf](doc/easyfloats.pdf).
+
+The source code for the documentation is *not* contained in the dtx file but in the directory [doc](doc).
+To build the documentation run:
+```sh
+cd doc
+pdflatex easyfloats.tex
+biber easyfloats
+pdflatex easyfloats.tex
+pdflatex easyfloats.tex
+```
+
+
+# Dependencies
+
+The dependencies are listed in [DEPENDS.txt](DEPENDS.txt).
+It's syntax is explained on http://tug.org/texlive/pkgcontrib.html#deps.
+See also section *Used packages* in the [documentation](doc/easyfloats.pdf).
+
+
+# License
+
+This package and it's documentation are distributed under the [LaTeX Project Public License](https://www.latex-project.org/lppl/), version 1.3 or later.
+The preamble of the documentation may alternatively, at your choice, be reused under the terms of the [WTFPL](http://www.wtfpl.net/), version 2 or later.
+
+Additionally to the rights granted by the LaTeX Project Public License
+you have permission to freely distribute *unmodified* copies
+of the files [easyfloats.sty](easyfloats.sty) and [doc/easyfloats.pdf](doc/easyfloats.pdf) without other files of this work.
+The other files of this work can be found at:
+https://gitlab.com/erzo/latex-easyfloats
+
+The examples and tests are distributed under the [WTFPL](http://www.wtfpl.net/), version 2 or later.
+
+
+# Contact
+
+Bug reports and feature requests can be submitted at
+https://gitlab.com/erzo/latex-easyfloats/-/issues.
+
+Please see also section *Bug reports and contributions* in the [documentation](doc/easyfloats.pdf).
diff --git a/macros/latex/contrib/easyfloats/doc/content/bug-reports-and-contributions.tex b/macros/latex/contrib/easyfloats/doc/content/bug-reports-and-contributions.tex
new file mode 100644
index 0000000000..ccfb7dce9a
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/doc/content/bug-reports-and-contributions.tex
@@ -0,0 +1,41 @@
+% !TeX root = ../easyfloats.tex
+
+\section{Bug reports and contributions}
+\label{bug-reports-and-contributions}
+
+If you find a bug please open an issue for it
+on \url{https://gitlab.com/erzo/latex-easyfloats/-/issues}
+including a minimal example where the bug occurs,
+an explanation of what you expected to happen
+and the version of \LaTeX\ and the packages you are using (which are included in the log file).
+Issues which are not reproducible will be closed.
+
+If you have a feature request please open an issue for it
+on \url{https://gitlab.com/erzo/latex-easyfloats/-/issues}
+including a minimal example which you would like to work,
+an explanation of what it should do
+and a use case explaining why this would be useful.
+
+Before opening an issue please check that there is not yet an issue for it already.
+
+If you want to resolve an issue yourself please create a merge request.
+Make the changes in \filename{easyfloats.dtx}.
+You can generate the sty file with \verb|tex easyfloats.ins|
+but you do not need to do that manually because \filename{test/autotest.py} does that automatically for you.
+Before creating a merge request please make sure that the automated tests still pass.
+Run the python3 script \filename{test/autotest.py} from the project root or test directory without arguments.
+While running the tests it shows a progress bar in square brackets.
+A dot stands for a successful test, an F for a failed test and an E for an error in the test script.
+Merge requests where a test prints F will most likely be rejected.
+If you get an E please create a bug report issue.
+
+Please use *tabs* for indentation.
+
+A merge request should include:
+\begin{itemize}
+\item The changes to \filename{easyfloats.dtx}
+\item The automatically generated \filename{easyfloats.sty}
+\item Additions to the documentation
+\item Automated tests in the \filename{test} directory to make sure the new feature or bug fix does not break in the future
+\item A link in the merge request description to the issue which it is supposed to close
+\end{itemize}
diff --git a/macros/latex/contrib/easyfloats/doc/content/documentation.tex b/macros/latex/contrib/easyfloats/doc/content/documentation.tex
new file mode 100644
index 0000000000..6dd1d9b62d
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/doc/content/documentation.tex
@@ -0,0 +1,1082 @@
+% !TeX root = ../easyfloats.tex
+
+\section{Documentation}
+\label{documentation}
+
+This section contains the documentation on how to use this package.
+
+\Cref{options} gives general information on options which environments and commands defined by this package may take.
+The options themselves are explained in \cref{environments,commands} where the environments and commands defined by this package are explained.
+
+\Cref{initialization} describes what is happening when loading this package.
+\Cref{package-options} describes the options which can be passed to `\usepackage` when loading this package.
+
+\Cref{help} explains a few features which may help you to get a better understanding about what is going on.
+This might be useful if you run into unexpected errors or this package behaves different than you expected.
+
+
+\subsection{Options}
+\label{options}
+
+The environments and commands defined by this package take options (implemented with the \pkg{pgfkeys} package).
+Options are a comma separated list of `<key>`s or `<key>=<value>` pairs.
+
+Which keys are allowed for which environment\slash command and which values are allowed for which key is specified in \cref{environments,commands} where the environments and commands are documented.
+This section gives general information about these options.
+
+This section does *not* apply to the package options which are explained in \cref{package-options}.
+
+
+\subsubsection{Initial vs default values}
+\label{initial-vs-default-values}
+
+I am using the words *initial value* and *default value* like they are used in the \mycite{tikz}.
+
+The *initial* value of an option is the value which is used if the key is *not* given.
+
+The *default* value of an option is the value which is used if the key is given without a value.
+Most keys don't have a default value, i.e.\ if you use the key you must explicitly give it a value.
+
+\subsubsection{Options scope}
+\label{options-scope}
+
+Setting an option always applies until the end of the current group.
+For the argument of an environment this is the corresponding `\end` command.
+For the argument of the \cmd{\includegraphicobject} command this is the end of this command.
+For the argument of \cmd{\objectset} this may be the end of the document.
+
+If you are not familiar with the concept of groups in \TeX\ \mycite[chapter~10]{texbytopic} is one possible place to read up on it.
+
+\subsubsection{Special characters in options}
+\label{special-characters-in-options}
+
+If a value contains a comma or an equals sign it must be wrapped in curly braces.
+
+Spaces before and after a comma (separating an option) and before or after an equals sign (separating key and value) are ignored.
+However, a space after the opening brace is *not* ignored.
+So if you put the first key on the next line make sure to comment out the linebreak.
+If a leading or trailing space in a value is desired wrap the value in curly braces.
+
+`\par` (aka an empty line) is forbidden in keys but allowed in values.
+
+\subsubsection{Key patterns}
+\label{key-patterns}
+
+Sometimes I am talking about entire groups of keys instead of individual keys.
+I specify those groups with a pattern which matches the keys that I am referring to.
+In these patterns parenthesis stand for something optional and angular brackets for wildcards.
+
+For example the pattern `(<env>) arg(s)` matches the keys `tabular* arg` and `args` (and many more)
+but not `env arg` because `env` is not an existing environment.
+
+If a key has a version which ends on a `+` to append a value instead of replacing it the space in front of the `+` is optional.
+
+\subsubsection{Key name vs key path}
+\label{key-name-vs-key-path}
+
+\pkg{pgfkeys} organizes all keys \textcquote[page~954]{tikz}{in a large tree that is reminiscent of the Unix file tree.}
+The keys of this package are located in the three paths `/object`, `/subobject` and `/graphicobject`.
+
+In error messages thrown by the \pkg{pgfkeys} package the full path of a key is shown.
+
+When setting keys, however, you need not and should not specify the full path.
+The commands and environments of this package set the path automatically.
+Using full paths does not directly cause an error or a warning but trying to set options for a style or style group with \cmd{\objectset} causes undefined behavior.
+
+Therefore, error messages thrown directly by this package omit the path and show the name of the key only.
+
+\subsubsection{Key types}
+\label{key-types}
+
+In \pkg{pgfkeys} there are different types of keys.
+Which type a key belongs to is relevant for debugging if you want to check the value of a key, see \cref{help}.
+
+\keytypedoc{storing key}
+ Keys of this type are like a variable.
+ They store the given value.
+ This value can be showed using the `.show value` handler (see \cref{help}).
+
+\keytypedoc{executed key}
+ Keys of this type are like a function.
+ They execute some predefined code and possibly take a value as argument.
+
+\keytypedoc{boolean key}
+ is a special case of an executed key which sets a plain \TeX\ if command.
+ This if command and it's meaning can be showed with the `.show boolean` handler (which is *not* contained in \pkg{pgfkeys}, I have defined it in this package).
+
+ The allowed values for a key of this type are `true` and `false`.
+ The default value (i.e.\ the value which is assumed if the key is given without a value) is `true`.
+
+\keytypedoc{forwarding key}
+ is a special case of an executed key which calls another key.
+
+\keytypedoc{handler}
+ Keys defined in the path `/handlers`.
+ They can be applied to other keys by appending them to the path.
+ For users of this package they can be helpful for debugging.
+ For example `\objectset{env/.show value}` shows the value of the key `env`.
+
+ The \pkg{pgfkeys} package also defines handlers which expand the value.
+ I haven't come up with an example where this might be useful in the context of this package but e.g.\ `tabular arg/.expand once=\colspec,` works as expected.
+
+\keytypedoc{unknown key handler}
+ is a special key which is called if a given key does not exist and it's name is not a handler.
+ I am using this to implement key patterns.
+\endkeytypedoc
+
+\subsubsection{Styles}
+\label{styles}
+\DescribeMeta{style}
+\DescribeMeta{styles}
+
+This package defines two styles, one for figures and one for tables.
+
+You can think of these styles as an extension of the \pkg{float} package's float styles.
+
+These styles are somewhat inspired by the \pkg{pgfkeys} styles but are different.
+They are neither set nor applied in the same way.
+
+A style is a list of options which is not set immediately but locally for each object belonging to that style.
+
+The options of a style can be set by passing the name of the style as an optional argument to the \cmd{\objectset} command,
+e.g.\ `\objectset[figure]{<options>}` or `\objectset[table]{<options>}`.
+
+A style is applied by using the corresponding environment (e.g.\ \env{figureobject} or \env{tableobject})
+or `\graphicobjectstyle{<style>}` for \cmd{\includegraphicobject}.
+
+New styles can be defined with `\NewObjectStyle` as explained in \cref{new-object-styles-and-types}.
+
+\subsubsection{Style groups}
+\label{style-groups}
+\DescribeMeta{group}
+
+This package defines one group of styles called `all` which contains all defined styles.
+
+When setting options one can use a group name instead of a style name.
+In that case the options are set for all styles in the group.
+
+\subsubsection{Options processing order}
+\label{options-processing-order}
+
+\begin{enumerate}
+\item Options set with `\objectset{<options>}` have the lowest priority.
+\item Options set for a specific style with `\objectset[<styles>]{<options>}` take precedence because they are set later (at the object, not the `\objectset` command).
+\item Options passed directly to the object have the highest priority.
+\end{enumerate}
+
+For example:
+
+\begin{examplecode}
+\objectset[figure]{placement=p}
+\objectset{placement=H}
+\objectset[table]{placement=htbp}
+\end{examplecode}
+
+Given the above preamble both figure- and tableobjects are floating.
+Tableobjects are allowed to be placed where they are specified in the source code.
+Figureobjects are put on a separate float page.
+The second line (which would disable floating) has no effect (unless you define a custom style) because it is overridden not only by the third but also the first line.
+
+
+\subsection{Environments}
+\label{environments}
+
+This package defines the following environments.
+Each of them takes exactly one mandatory argument,
+options as a comma separated key=value list.
+
+\subsubsection{`object` environment}
+\label{object-environment}
+\begingroup
+\keydocpath{/object}
+\DescribeEnv{object}
+The `object` environment is used internally by \env{figureobject} and \env{tableobject}.
+Don't use this directly.
+You can define more environments like `figureobject` or `tableobject` with \cmd{\NewObjectStyle} if needed.
+
+This environment redefines the `\caption` and `\label` commands to set the \key{caption}\slash `label` option so that you can use them as usual except you cannot create several labels.
+If you really need several labels for the same object put the additional `\label` command(s) inside of the caption argument, there `\label` has it's original meaning.
+The location or the order of `\caption` and `\label` inside of the object environment is not relevant.
+Nevertheless I recommend to always put the `\label` after the `\caption` as it is usually required in order to get the references right (if you choose to use these commands instead of the options).
+Where the caption is typeset (above or below the object) is determined by the float style.
+
+This environment takes the following options:
+\keydoc{type = <type>}{storing key}
+\DescribeMeta{type}
+ The floating environment to use, e.g.\ `figure` or \env{table}.
+\keydoc[initial value=empty]{float style = plain | plaintop | ruled | boxed | <empty>}{storing key}
+ How the object is supposed to look like,
+ most importantly whether the caption is supposed to be above or below the object.
+ See the \pkg{float} package for more information.
+
+ If the value is empty the float type is *not* restyled before the\slash each object.
+ However, this package restyles \env{table} to `plaintop` and `figure` to `plain` when it is loaded.
+ The reasoning is explained in~\autocite{texexchange_caption_position}.
+
+\keydoc{caption = <text>}{storing key}
+ The caption to place above or below the float.
+
+ The appearance of the caption can be configured using `\captionsetup` defined by the \pkg{caption} package.
+ The \pkg{caption} package is loaded automatically by this package.
+\keydoc{list caption = <text>}{storing key}
+ The caption to place in the list of `<type>`s.
+ If this is not given, the value of \key{caption} is used instead.
+\keydoc{details = <text>}{storing key}
+ This is appended to the caption which is placed above or below the object but not to the list of `<type>`s.
+ \begin{examplecodekey}
+ caption=CTAN lion drawing by Duane Bibby,
+ details=Thanks to \url{www.ctan.org}.
+ \end{examplecodekey}
+ is equivalent to
+ \begin{examplecodekey\starred}{\ExamplecodeEscapeinside $ $}
+ list caption=CTAN lion drawing by Duane Bibby,
+ caption=CTAN lion drawing by Duane Bibby.$\\$ Thanks to \url{www.ctan.org}.
+ \end{examplecodekey\starred}
+\keydoc[initial value=a full stop followed by a space]{details sep = <text>}{storing key}
+ The separator to be placed between caption and details if details are given.
+\keydoc{label = <label>}{storing key}
+ Defines a label to reference this object.
+\keydoc{add label = <label>}{storing key}
+ Defines an additional label which can be used synonymously to label.
+ If this key is given several times, only the last one will have an effect.
+\keydoc[initial value=empty]{placement = [htbp]+!? | H | <empty>}{storing key}
+ The optional argument passed to the floating environment.
+ Allowed values:
+ \begin{itemize}
+ \item any combination of the letters `htbp` (where no letter is occuring more than once), optionally combined with an exclamation mark.
+ This means that the object will be a floating object.
+ The order of the letters makes no difference.
+ They have the following meanings:
+ \begin{itemize}
+ \item `h`: \LaTeX\ is allowed to place the object `h`ere, where it is defined.
+ \item `t`: \LaTeX\ is allowed to place the object at the `t`op of a page.
+ \item `b`: \LaTeX\ is allowed to place the object at the `b`ottom of a page.
+ \item `p`: \LaTeX\ is allowed to place the object on a separate `p`age only for floats.
+ \item `!`: \textcquote[page~27]{latex2e}{\LaTeX\ ignores the restrictions on both the number of floats that can appear and the relative amounts of float and non-float text on the page.}
+ \end{itemize}
+ \item `H`: \LaTeX\ places the object exactly here, no matter how unfitting that may be.
+ In contrast to a single `h` or `h!` where the object is still a floating object which may float somewhere else if it does not fit here,
+ `H` means here and nowhere else.
+ `H` is defined by the \pkg{float} package which is loaded by this package automatically.
+ \item empty: do *not* pass the optional argument.
+ In this case the placement of the float can be changed using the `\floatplacement` command of the \pkg{float} package.
+ I have defined this key instead of advertising `\floatplacement` because `\floatplacement` does not allow the value~`H`.
+ \end{itemize}
+
+\keydoc[initial value=`\centering`]{align = <code>}{storing key}
+ \TeX\ code which is inserted at the beginning of the `<type>` environment.
+\keydoc[initial value=empty]{exec = <code>}{storing key} /
+\keydoc{exec += <code>}{executed key}
+ \TeX\ code which is inserted at the beginning of the `<type>` environment before align.
+ Can be used to define a command for this object, see \cref{local-definitions-in-tables}.
+\keydoc{graphic <option> = <value>}{unknown key handler}
+\keylinktarget{graphic width}
+ Is applied to \cmd{\includegraphicobject} and \cmd{\includegraphicsubobject}.
+ Is ignored for other objects.
+
+ `<option>` can be any key which is unique to one of these two commands and any key allowed by the `\includegraphics` command (see \pkg{graphicx}\slash \pkg{graphbox} package).
+ Unlike `\setkeys{Gin}{<options>}` this works with all keys (compare \pkg{graphicx} documentation~\autocite[section~4.6]{graphicx}, unfortunately it's not getting more specific than \enquote{Most of the keyval keys}).
+
+ I am checking if the key is existing immediately but I cannot check the value (only whether it is required).
+ Therefore if you pass a wrong value the error message will not appear where you set this option but at the object where it is applied.
+
+ If you set `graphic width` globally and want to override it locally you can use `graphic width=!`.
+ This is a feature of the graphicx package but it is not well documented in it's documentation~\autocite{graphicx}.
+ (Which is why I am mentioning it here.)
+ The exclamation mark is mentioned for the `\resizebox` command.
+
+\bigpar
+
+\keydoc[initial value=empty]{env = <env>}{storing key}
+ The name of an additional inner environment in which the body is wrapped, e.g.\ `tabular`, \env{tabularx}, `tikzpicture`.
+ If empty the body is *not* wrapped in another environment (additional to object).
+
+ Please note that using this option can lead to difficult to find errors with confusing error messages
+ if you forget that you used it or it has a different value than you think it has.
+ In this case `show env args` may help you.
+
+ Please note that due to the way how environments are implemented in \LaTeX2 (this will change in \LaTeX3~\autocite{ltx3env})
+ it is not possible to check whether a given name is an environment or a command.
+ But if you pass something that is *not* defined you will get an error.
+
+ If you have loaded the \pkg{longtable} package (either with the package option \pkgoptn{longtable} or with a `\usepackage{longtable}`)
+ you can set the value of this key to \val{longtable}.
+ In that case the necessary changes are performed
+ so that the content of this object environment is set in a \env{longtable} environment
+ and does *not* float but can span across page breaks.
+ In this case `type`, `placement` and `align` are ignored.
+
+\keydoc{<env> arg = <value>}{unknown key handler}
+\keylinktarget{(<env>) arg(s) (+)}
+\keylinktarget{(<env>) arg(s)}
+\keylinktarget{tabularx arg+}
+\keylinktarget{tabularx arg}
+\keylinktarget{\detokenize{tabular* arg}}
+\keylinktarget{tabular arg}
+\NoDescribeKey{env arg}
+ The value is wrapped in braces and passed as argument to the additional inner environment if the value of `env` is not empty and `<env>` equals the value of `env`.
+ Arguments to this environment can be given as an argument to the `*object` environment as well but this key provides the possibility to pass arguments on a global level (or to override a globally passed argument).
+ For example this can be used to give all tabularx-tables a consistent width:
+
+ \begin{examplecode}
+ % in preamble
+ \objectset[table]{tabularx arg=.8\linewidth}
+
+ % in document
+ \begin{tableobject}{caption=Test Table, label=tab1, env=tabularx}{XX}
+ ...
+ \end{tableobject}
+ \end{examplecode}
+
+\keydoc{<env> args = <value>}{unknown key handler}
+ Same like `<env> arg` except that the value is *not* wrapped in braces.
+ This can be used to pass several arguments or an optional argument.
+ Please not that this key cannot be used to pass exactly one undelimited argument consisting of more (or less) than one token because `\pgfkeys` (which I am using internally) strips several levels of braces.
+\keydoc{arg = <value>}{unknown key handler}
+ If `env` has a non-empty value this is an abbreviation of `<env> arg` where `<env>` is the value of `env`.
+
+ Please note that because this key depends on the value of another key the order in which these two keys are given is important.
+
+ The value of `env` is considered when this key is evaluated.
+ If you use `\objectset[<styles>]{<options>}` (with it's optional argument) the processing of the keys is delayed but it makes some basic error handling already so that the line numbers are as fitting as possible.
+ For this error handling only the options passed to this call of the command are considered.
+ (Trying to consider previously set values correctly would make things more difficult because you might be applying these options to several styles at once where one might have `env` set and another not.)
+ Therefore the following causes an error message:
+
+ \begin{examplecode}
+ \objectset[table]{env=tabularx}
+ \objectset[table]{arg=.8\linewidth}
+ \end{examplecode}
+
+ While this would not:
+
+ \begin{examplecode}
+ \objectset{env=tabularx}
+ \objectset{arg=.8\linewidth}
+ \end{examplecode}
+
+ Anyway, I recommend to always use this option directly after `env` (if you intend to use it).
+ `env` and it's `args` belong together:
+
+ \begin{examplecode}
+ \objectset{env=tabularx, arg=.8\linewidth}
+ \end{examplecode}
+
+\keydoc{args = <value>}{unknown key handler}
+ If `env` has a non-empty value this is an abbreviation of `<env> args` where `<env>` is the value of `env`.
+ The notes on error handling of the `arg` key apply to this key as well.
+\keydoc{(<env>) arg(s) += <value>}{unknown key handler}
+ A plus sign can be appended to the key (patterns) `<env> arg`, `<env> args`, `args` and `arg`.
+ In that case a possibly previously passed argument is not overridden but this value is appended to it.
+ For example the following pattern allows to easily switch between tabular and tabularx tables on a global level:
+
+ \begin{examplecode}
+ % in preamble
+ \objectset[table]{tabularx arg=.8\linewidth, env=tabularx}
+ \newcolumntype{Y}{>{\raggedleft\arraybackslash}X}
+
+ % in document
+ \begin{tableobject}{caption=Test Table, label=tab1, tabular arg=lr, tabularx arg+=XY}
+ ...
+ \end{tableobject}
+ \end{examplecode}
+
+\bigpar
+
+\keydoc{first head = <code>}{storing key}
+ Is inserted at the beginning of the object (if `env` is non-empty: inside of the inner environment and after possibly specified `(<env>) arg(s)`).
+ If this is not given, `head` is used instead.
+\keydoc{last foot = <code>}{storing key}
+ Is inserted at the end of the object (if `env` is non-empty: inside of the inner environment).
+ If this is not given, `foot` is used instead.
+\keydoc[initial value=empty]{head = <code>}{storing key}
+ This value is used for `first head` if `first head` is not given.
+ If `env=longtable` this is the head after a pagebreak inside of the table.
+\keydoc[initial value=empty]{foot}{storing key}
+ This value is used for `last foot` if `last foot` is not given.
+ If `env=longtable` this is the foot before a pagebreak inside of the table.
+\keydoc{table head = <code>}{executed key}
+ This is a convenience key which sets `first head`, `last foot`, `head` and `foot`.
+ The value is the column headers without rules\slash lines and without the trailing `\\`.
+\keydoc{table break text = <text>}{storing key}
+ A text put in the `foot` by `table head`.
+\keydoc{table head style = <code>}{executed key}
+ Defines how `table head` fills out `first head`, `last foot`, `head` and `foot`.
+
+ Initial value:
+
+ \begin{examplecode}
+ {%
+ first head =
+ \toprule
+ #1 \\
+ \midrule,
+ head =
+ #1 \\
+ \midrule,
+ foot =
+ \midrule
+ \ifx\object@tableBreakText\@empty
+ \else
+ \multicolumn{\the\LT@cols}{r@\relax}{\object@tableBreakText}%
+ \fi,
+ last foot =
+ \bottomrule,
+ }
+ \end{examplecode}
+
+ (Note the curly braces which are required because the value contains commas and equal signs, see \cref{special-characters-in-options}.
+ `\the\LT@cols` is the number of columns of the longtable and `\object@tableBreakText` is the value of `table break text`.
+ Commands containing an @ in their name are internal commands and can only be used between `\makeatletter` and `\makeatother`, see also \autocite{texexchange_make_at}.)
+
+\bigpar
+
+\keydoc[initial value=`false`, default value=`true`]{show env args =? true | false}{boolean key}
+ Show the code which is assembled from the `env` and `(<env>) arg(s) (+)` keys before executing it.
+ See \cref{help}.
+ Please note that arguments may be given as additional arguments and not as `(<env>) arg(s) (+)` like in `\begin{tableobject}{env=tabular}{cl}`.
+ Such arguments are *not* shown by this key.
+ This key applies to subobjects as well.
+
+\keydoc[initial value=`true`, default value=`true`]{warn no caption =? true | false}{boolean key}
+ Give a warning if \key{caption} is *not* given.
+\keydoc[initial value=`true`, default value=`true`]{warn no label =? true | false}{boolean key}
+ Give a warning if `label` is *not* given.
+\keydoc[initial value=`false`, default value=`true`]{warn other env =? true | false}{boolean key}
+ Give a warning when `<env> args` is given if `env` does not have the value `<env>` and the value of `env` is not empty.
+ This applies to subobjects as well.
+
+ The \cmd{\objectset} command if used with it's optional argument does not set the options immediately but stores them in different macros for different object styles.
+ Therefore if you change this value for certain styles this change does not affect following `\objectset` commands.
+ Without the optional style argument, however, the change takes effect immediately.
+
+ In order to avoid duplicates this warning is printed only where the key is passed by the user
+ and *not* where it is applied implicitly because of a previous `\objectset[<styles>]{<options>}`.
+
+\keydoc[initial value=`false`, default value=`true`]{contains subobjects =? true | false}{boolean key} /
+\keydoc{sub =? true | false}{forwarding key}
+ Specifies that this object contains subobjects, see \cref{subobject-environment}.
+ Is relevant only if `env` is set.
+ The value of `env` is applied to the subobjects instead of this object.
+ This is not executed immediately but only after all options have been processed so that you do not need to pay special attention to pass `env` before `contains subobjects`.
+
+ If this is *not* given (or more precisely: if this is false)
+ and the value of `env` is *not* empty I look ahead whether the object contains a subobject.
+ If I find a subobject I pretend you had passed this option and print a warning.
+ I insist on you explicitly passing this option because the lookahead does not work in all situations.
+ It ignores space and `\par` tokens but if there is any other token before the subobject,
+ for example a `\small` to fit two tables side by side which are a little too wide
+ (which may not be the best solution but an easy quick fix)
+ or a `\typeout` for debugging,
+ the lookahead does not find the subobject (possibly) resulting in unpredictable errors.
+ For example if you set `env=tabular` it will most likely complain about an \errormessage{Illegal pream-token}
+ or about a \errormessage{Missing number, treated as zero} with `env=tabular*` because the required arguments are missing.
+\endkeydoc
+
+
+All `(<env>) arg(s) (+)` options apply to subobjects as well.
+
+Additionally the following options are passed through to the corresponding options of all subobjects inside of this object, they are all \keytype[forwarding key]{forwarding keys}.
+\newcommand{\TargetKey}[2]{/subobject/\stripsubobject #2\relax}%
+\def\stripsubobject subobject #1\relax{\stripoptplus{#1}}%
+See \env{subobject} environment.
+\forwardingkeydoc{subobject linewidth = <dimen>}
+\forwardingkeydoc{subobject sep = <code>}
+\forwardingkeydoc{subobject hor =? <code>}
+\forwardingkeydoc{subobject hor sep (+)= <code>}
+\forwardingkeydoc{subobject ver =? <code>}
+\forwardingkeydoc{subobject ver sep (+)= <code>}
+\forwardingkeydoc{subobject exec (+)= <code>}
+\forwardingkeydoc{subobject env = <env>}
+\forwardingkeydoc[target=/subobject/subcaptionbox]{subcaptionbox}
+\forwardingkeydoc[target=/subobject/subcaptionbox inner pos]{subcaptionbox inner pos = c | l | r | s | <empty>}
+\forwardingkeydoc[target=/subobject/subpage]{subpage}
+\forwardingkeydoc[target=/subobject/subpage outer pos]{subpage outer pos = c | t | b | T | B | auto | Auto | <empty>}
+\forwardingkeydoc[target=/subobject/subpage height]{subpage height = <dimen>}
+\forwardingkeydoc[target=/subobject/subpage inner pos]{subpage inner pos = c | t | b | s | <empty>}
+\forwardingkeydoc[target=/subobject/subpage align]{subpage align = <code>}
+
+\forwardingkeydoc{subobject warn no caption =? true | false}
+\forwardingkeydoc{subobject warn no label =? true | false}
+\endkeydoc
+\endgroup
+
+
+\subsubsection{`figureobject` environment}
+\label{figureobject-environment}
+\DescribeEnv{figureobject}
+Is used for inserting figures.
+Takes the same options like the \env{object} environment.
+It differs in the following initial values:
+\begin{itemize}
+\item `type=figure`
+\end{itemize}
+
+\subsubsection{`tableobject` environment}
+\label{tableobject-environment}
+\DescribeEnv{tableobject}
+Is used for inserting tables.
+Takes the same options like the \env{object} environment.
+It differs in the following initial values:
+\begin{itemize}
+\item `type=table`
+\end{itemize}
+
+
+\subsubsection{`subobject` environment}
+\label{subobject-environment}
+\begingroup
+\keydocpath{/subobject}
+\DescribeEnv{subobject}
+To be used inside of an `*object` environment if you want to place several images\slash tables\slash whatever together.
+See also \cmd{\includegraphicsubobject}.
+
+I recommend to *not* put anything between the subobjects manually so that you can control their positioning with the `hor` and `ver` options.
+(Spaces after a subobject are ignored but empty lines are not.)
+
+Unlike the `object` environment, `\caption` and `\label` *cannot* be used inside of the subobject environment.
+Use the \key{caption} and `label` options instead.
+
+There are two different backends available, both provided by the \pkg{subcaption} package.
+See the `subcaptionbox` and `subpage` keys.
+
+The `subobject` environment has exactly one mandatory argument, a comma separated list of the following options.
+
+
+The following options correspond to those of an `object`.
+See \cref{object-environment}.
+\newcommand{\TargetKey}[2]{/object/#2}%
+\correspondingkeydoc{label = <label>}{storing key}
+
+\correspondingkeydoc{caption = <text>}{storing key}
+
+\correspondingkeydoc{list caption = <text>}{storing key}
+
+ (The \pkg{subcaption} package disables subcaptions in the list of figures\slash tables\slash whatever by default.
+ To enable them use `\captionsetup[sub]{list=true}`.)
+\correspondingkeydoc{details = <text>}{storing key}
+
+\correspondingkeydoc{details sep = <text>}{storing key}
+
+\correspondingkeydoc{exec = <code>}{storing key} /
+\correspondingkeydoc{exec += <code>}{executed key}
+
+\correspondingkeydoc{graphic <option> = <value>}{unknown key handler}
+
+ (This key is completely useless.
+ It only has a meaning in the context of \cmd{\includegraphicsubobject} but there these options can be used directly without the prefix `graphic`.
+ I am allowing it anyway in order to support the same key like in \cmd{\objectset} which is supported by \cmd{\includegraphicobject} as well.)
+\correspondingkeydoc{env = <env>}{storing key}
+
+ (See also the `contains subobjects` option of the \env{object} environment.)
+\correspondingkeydoc{(<env>) arg(s) (+) = <value>}{unknown key handler}
+
+ (All values passed to the corresponding keys of the \env{object} environment apply to this option, too.)
+
+\correspondingkeydoc{warn no caption =? true | false}{boolean key}
+
+\correspondingkeydoc{warn no label =? true | false}{boolean key}
+
+\forwardingkeydoc[target=/object]{warn other env =? true | false}
+
+\forwardingkeydoc[target=/object]{show env args =? true | false}
+
+\endkeydoc
+
+The following options are unique for the `subobject` environment:
+\keydoc[initial value=`.5\linewidth`]{linewidth = <dimen>}{storing key}
+ The horizontal space available for the subobject.
+ The content of the subobject is centered within this width.
+ If two subobjects displayed side by side have a small width they may appear too far apart from each other with the initial value.
+ Then you can decrease this value so that they come closer together.
+ (With `subcaptionbox` this value may be empty.
+ In that case the subobject takes as much space as it needs
+ and `\linewidth` inside of the subobject is the same like in the parent object.)
+
+ If you want to place more than two subobjects side by side you must decrease this value accordingly.
+ Keep in mind that you need to consider the width of `hor sep` as well if you changed it.
+
+ Dimensions can be given relative to other dimensions or in numbers.
+ Aside from absolute units like `pt` or `cm` \TeX\ also recognizes units relative to the current font size: `em` and `ex`.
+ For more information on dimensions see \mycite[chapter~10]{texbook} or \mycite[chapter~8]{texbytopic}.
+
+\keydoc{sep = <code>}{storing key}
+ A separator which is inserted before each subobject except for the first subobject inside of the current parent object.
+
+\keydoc[default value=empty]{hor =? <code>}{executed key}
+ Set the value of `sep` to the value of `hor sep` so that the subobjects are placed side by side.
+ If you pass a value the value will be appended to `sep` after setting it to `hor sep`.
+
+ Please note that options are only valid until the end of a group.
+ Therefore if you use this inside of a subobject it does *not* apply for the following subobject.
+ Instead use `subobject hor` on the parent object.
+
+\keydoc[initial value=empty]{hor sep = <code>}{storing key} /
+\keydoc{hor sep += <code>}{executed key}
+ The separator to be used if the subobjects are suppossed to be placed side by side.
+
+ Please note that `hor` must be used *after* setting this key, otherwise this option will not take effect.
+
+\keydoc[default value=empty]{ver =? <code>}{executed key}
+ Set the value of `sep` to the value of `ver sep` so that the subobjects are placed below each other.
+ If you pass a value the value will be appended to `sep` after setting it to `ver sep`.
+
+ Please note that options are only valid until the end of a group.
+ Therefore if you use this inside of a subobject it does *not* apply for the following subobject.
+ Instead use `subobject ver` on the parent object.
+
+\keydoc[initial value=`\par\bigskip`]{ver sep = <code>}{storing key} /
+\keydoc{ver sep += <code>}{executed key}
+ The separator to be used if the subobjects are suppossed to be placed below each other.
+
+ Please note that `ver` must be used *after* setting this key, otherwise this option will not take effect.
+
+\bigpar
+
+\keydoc{subcaptionbox}{executed key}
+ The \pkg{subcaption} package provides several possibilities to insert subobjects.
+ This option tells the subobject environment to use the `\subcaptionbox` command instead of the `subfigure` or `subtable` environment, see option `subpage`.
+ (This key does *not* take a value.)
+
+ This option allows to pass an empty value to `linewidth`.
+ It can be useful if you have subobjects with a small width
+ so that you don't need to try different `subobject linewidth`s.
+ The example in \cref{subobjects-2} could be rewritten as following:
+
+ \begin{examplecode}
+ \documentclass{article}
+ \usepackage{easyfloats}
+
+ \objectset[table]{%
+ env = tabular,
+ subcaptionbox,
+ subobject linewidth =,
+ subobject hor = \qquad,
+ }
+ \captionsetup[sub]{list=true}
+
+ \begin{document}
+ \begin{tableobject}{contains subobjects,
+ caption = Two test tables,
+ label = tabs abc 123,
+ }
+ \begin{subobject}{caption=Abc \& 123, arg=rl}
+ \toprule
+ abc & 123 \\
+ de & 45 \\
+ f & 6 \\
+ \bottomrule
+ \end{subobject}
+ \begin{subobject}{caption=123 \& abc, arg=lr}
+ \toprule
+ 123 & abc \\
+ 45 & de \\
+ 6 & f \\
+ \bottomrule
+ \end{subobject}
+ \end{tableobject}
+ \end{document}
+ \end{examplecode}
+
+ Note that this works only if the subobject captions are very short.
+ If they are wider than the subobjects the line breaks which looks ugly.
+
+ If you want to use this option with `env=tabular` (or similar) you must pass the column specification with the option `arg=lr` (instead of as a separate argument).
+ Otherwise you will get the error message \errormessage{Package array Error: Illegal pream-token (\BODY): `c' used.}
+
+ This option is *not* compatible with `env=tabularx` and does not allow verbatim content inside of the subobject.
+
+\keydoc{subcaptionbox inner pos = c | l | r | s | <empty>}{storing key}
+ The horizontal position of the content in the box.
+ Also allowed is any justification defined with `\DeclareCaptionJustification`
+ (see the \pkg{caption} package documentation).
+ An empty value means that this optional argument is
+ *not* passed to the `\subcaptionbox` command.
+ This option has no effect if `linewidth` is empty.
+ I discourage using this option because it destroys
+ the alignment of (sub)object and (sub)caption.
+
+\bigpar
+
+\keydoc{subpage}{executed key}
+ This is (after `subcaptionbox`) the second and nowadays initial backend for the `subobject` environment.
+ It uses the `subfigure`\slash `subtable` environment defined by the \pkg{subcaption} package.
+ (This key does *not* take a value.)
+
+ The `subfigure` and `subtable` environments are minipages and take the same arguments
+ which can be set with `linewidth`, `subpage outer pos`, `subpage height` and `subpage inner pos`.
+
+\keydoc[initial value=`auto`]{subpage outer pos = c | t | b | T | B | auto | Auto | <empty>}{storing key}
+ The vertical position of the minipage on the baseline.
+
+ Additionally to the values `t`, `c` and `b` supported by the minipage environment
+ the \pkg{subcaption} package v1.2 adds the allowed values `T` and `B`
+ and this key also allows the values `auto`, `Auto` and empty.
+
+ While `t` and `b` align the top\slash bottom *baseline* of the content
+ `T` and `B` align the very top\slash bottom of the content.
+
+ `c` aligns the center of the content.
+
+ `auto` means `t` if the caption is displayed at the top
+ or `b` if the caption is displayed at the bottom
+ so that the captions are aligned
+ (same behavior like `subcaptionbox`).
+
+ If a subobject has neither caption nor label `auto` may not work as expected.
+ Instead `Auto` can be used which is based on `T` and `B` instead of `t` and `b`.
+ Note that `Auto` requires version 1.2 or newer of the \pkg{subcaption} package.
+
+ Empty is equivalent to `c`.
+
+ Invalid values are silently ignored and are equivalent to `c`.
+
+
+\keydoc[initial value=empty]{subpage height = <dimen>}{storing key}
+ The height of the minipage.
+ An empty value means that this optional argument is
+ *not* passed to the `subfigure`\slash `subtable` environment.
+
+ Dimensions can be given relative to other dimensions or in numbers.
+ Aside from absolute units like `pt` or `cm` \TeX\ also recognizes units relative to the current font size: `em` and `ex`.
+ For more information on dimensions see \mycite[chapter~10]{texbook} or \mycite[chapter~8]{texbytopic}.
+
+\keydoc[initial value=empty]{subpage inner pos = c | t | b | s | <empty>}{storing key}
+ The vertical position of the content on the minipage.
+ Empty means that this optional argument is
+ *not* passed to the `subfigure`\slash `subtable` environment.
+ This option has no effect if `subpage height` is empty.
+
+\keydoc[initial value=`\centering`]{subpage align = <code>}{storing key}
+
+ \TeX\ code which is inserted at the beginning of the `subfigure`\slash `subtable` environment.
+\endkeydoc
+
+If you want to change the numbering of subobjects please refer to the \pkg{subcaption} package documentation~\autocite[section~5 \sectionname{The `\DeclareCaptionSubType` command}]{subcaption}.
+The \pkg{subcaption} package is loaded automatically by this package.
+\endgroup
+
+
+\subsection{Commands}
+\label{commands}
+
+In this section I am describing the commands defined by this package.
+
+
+\subsubsection{`\includegraphicobject` command}
+\label{includegraphicobject-command}
+\begingroup
+\keydocpath{/graphicobject}
+\DescribeMacro{\includegraphicobject}
+`\includegraphicobject{<filename>}` \\
+`\includegraphicobject[<options>]{<filename>}` \\
+`\includegraphicobject[<style>][<options>]{<filename>}`
+
+Is used for inserting graphics from a different file.
+It is very similar to \pkg{graphicx}' `\includegraphics` command, except that the graphic is automatically set in a \env{figureobject} environment.
+You can change this by setting the object style with \cmd{\graphicobjectstyle} or an additional optional argument given *before* the usual optional argument.
+The mandatory argument is the same: The name of the graphics file to include *without* the file extension.
+The optional argument accepts---aside from all the options defined by \pkg{graphicx}\slash \pkg{graphbox}---also all options of the \env{figureobject} environment.
+Additionally there are the following unique options:
+\keydoc[initial value=`true`, default value=`true`]{auto caption =? true | false}{boolean key}
+ If no \key{caption} is given the file name is used as caption.
+ All underscores in the file name are replaced by `\textunderscore`.
+ This option is intended to be used on a global level but works in the optional argument of this command as well.
+\keydoc[initial value=`false`, default value=`true`]{auto caption strip path =? true | false}{boolean key}
+ If `auto caption` is true and the file name is used as caption
+ a possibly leading path is stripped (everything before and including the last slash in `<filename>`).
+ This is initially false because I am assuming that in most cases where the path should not be displayed `\graphicspath{{path/}}` would be used.
+\keydoc[initial value=`true`, default value=`true`]{auto label =? true | false}{boolean key}
+ If no `label` is given the file name is used as label.
+ This option is intended to be used on a global level but works in the optional argument of this command as well.
+\keydoc[initial value=`false`, default value=`true`]{auto label strip path =? true | false}{boolean key}
+ If `auto label` is true and the file name is used as label
+ a possibly leading path is stripped (everything before and including the last slash in `<filename>`).
+ This is initially false because I am assuming that in most cases where the filename without path is unique `\graphicspath{{path/}}` would be used.
+\keydoc[initial value=`true`, default value=`true`]{warn env =? true | false}{boolean key}
+ Give a warning if `env` is not empty.
+\keydoc[initial value=`true`, default value=`true`]{no env =? true | false}{boolean key}
+ Reset `env` to an empty value.
+ This happens after evaluating `warn env`.
+\endkeydoc
+
+You may not use this command inside of an `*object` environment.
+Otherwise you will get an \errormessage{object environment may not be nested} error.
+See also \cmd{\includegraphicsubobject}.
+\endgroup
+
+\subsubsection{`\includegraphicsubobject` command}
+\label{includegraphicsubobject-command}
+\DescribeMacro{\includegraphicsubobject}
+`\includegraphicsubobject{<filename>}` \\
+`\includegraphicsubobject[<options>]{<filename>}`
+
+To be used if you want to place several graphics from different files in one object.
+
+It takes the same options like \cmd{\includegraphicobject} except that it takes options for the \env{subobject} environment instead of options for the `object` environment.
+Also it does *not* take the optional `<style>` argument.
+
+You may not use this command outside of an `*object` environment.
+Otherwise you will get a \errormessage{subobject environment may not be used outside of an object} error.
+See also \cmd{\includegraphicobject}.
+
+
+\subsubsection{Setting options globally}
+\label{setting-options-globally}
+
+\DescribeMacro{\objectset}
+`\objectset{<options>}` \\
+`\objectset[<styles>]{<options>}`
+
+Sets the passed options for all following objects until the end of the current group.
+All options of the \env{object} environment are allowed.
+
+A comma separated list of styles or style groups can be given in an optional argument.
+In that case the options are not set immediately but appended to the specified style(s).
+The options are set locally for any following object of the specified style(s) in the same group.
+Although setting the options is delayed the options are checked immediately so that error messages and warnings point to the line where the option is specified in the code, not where it is technically set.
+(In order for that to work properly it is important that options are specified with the key name only and not with the full path, see \cref{key-name-vs-key-path}.)
+However, the value can usually *not* be checked immediately, only whether it is required or not.
+Therefore if you pass a wrong value the error message will not appear where you set this option but at the object where it is applied.
+An exception is the key `env` where the value is checked immediately for plausibility whether it might be the name of an environment.
+
+If `<styles>` is empty or an empty group the options are not applied.
+No error or warning is printed.
+
+There is a style group called `all` which all styles belong to.
+`\objectset{<options>}` and `\objectset[all]{<options>}` are mostly equivalent
+except that the former (without optional argument) is more efficient because it sets the options immediately
+and the latter (with the optional argument given) is able to override options set for a style.
+
+
+\DescribeMacro{\graphicobjectstyle}
+`\graphicobjectstyle{<style>}` can be used to change the object style used by \cmd{\includegraphicobject}.
+For example, if you have a single table in a file called \filename{catcodes.pdf} you can insert it as following.
+Alternatively, you can use the optional `<style>` argument.
+
+\begin{examplecode}
+\begingroup
+\graphicobjectstyle{table}
+\includegraphicobject[caption=Catcodes]{catcodes}
+\endgroup
+\end{examplecode}
+
+
+\DescribeMacro{\graphicspath}
+`\graphicspath{{path/}}`: see \pkg{graphicx} package documentation~\autocite[section~4.5]{graphicx}.
+
+
+\subsubsection{New object styles and types}
+\label{new-object-styles-and-types}
+
+This section explains how to define a new object `<style>` in the sense of \cref{styles}.
+It is *not* about how to define a new `<floatstyle>` which can be used as value for the `float style` key.
+
+\DescribeMacro{\NewObjectStyle}
+`\NewObjectStyle{<style>}{<options>}`
+defines a new environment called `<style>object` analogous to `figureobject` and `tableobject`.
+`<options>` are set for the new object style as if you had used `\objectset[<style>]{<options>}`.
+You must always specify the `type`.
+If this package is loaded without `allowstandardfloats`
+the float environment which is passed to `type` is redefined to issue a warning that `<style>object` should be used instead.
+This warning should not influence the environment's usual behavior.
+If the float environment was already passed as `type` to a previous call of `\NewObjectStyle` it is not redefined again but `<style>object` is appended to the list of replacement suggestions.
+
+If you define a new object style you may also want to define a new float type.
+The \pkg{float} package (which is automatically loaded by this package) defines the following command for doing so:
+
+\DescribeMacro{\newfloat}
+`\newfloat{<type>}{<placement>}{<ext>}[<within>]`
+\begin{itemize}
+\item `<type>` is the floating environment to be defined.
+ This value is also used as the float name which is displayed in front of the caption, therefore it should be capitalized.
+ Alternatively the name can be changed using `\floatname{<type>}{<name>}`.
+\item `<placement>` is the value to be used if the `placement` key is not given (or has an empty value).
+ This is initially `tbp` for the standard float types.
+\item `<ext>` is the extension of a file used to save the list of `<type>`s.
+ This is `lof` (list of figures) for `type=figure` and `lot` (list of tables) for `type=table`.
+ This file extension should be unique.
+\item `<within>` is a counter whose value is prepended to the `<type>` counter. The `<type>` counter is reset every time the `<within>` counter is incremented.
+\item Make sure an appropriate default float style is active when using `\newfloat`.
+ The default float style can be activated using `\floatstyle{<floatstyle>}`, see the \pkg{float} package documentation~\autocite{float}.
+ It should be `plain` for something like an image or `plaintop` for something like a table.
+ The reasoning is explained in~\autocite{texexchange_caption_position}.
+ Alternatively you can specify the float style using the `float style` key in the `<options>` of `\NewObjectStyle`.
+\end{itemize}
+
+`\NewObjectStyle` automatically defines the corresponding environment needed for `subobject` if possible, i.e.\ if the \pkg{caption} package is new enough.
+If the \pkg{caption} package is older than August~30, 2020 and you want to use subobjects you need to define the subtype manually by putting the following line *before* loading this package \autocite{texexchange_subtype_workaround}:
+\begin{examplecode}
+\AtBeginDocument{\DeclareCaptionSubType{<type>}}
+\end{examplecode}
+
+\DescribeMacro{\trivfloat}
+The \pkg{trivfloat} package provides the `\trivfloat{<type>}` command which is an easier alternative to `\newfloat`.
+If you use it you should be aware that it does not define the new float type environment immediately but at `\begin{document}`.
+This does *not* affect `\NewObjectStyle` (you can still use it directly afterwards)
+but it means that the float style active at `\begin{document}` is applied and not the float style active at `\trivfloat`.
+Therefore I recommend to pass the `float style` option to `\NewObjectStyle`,
+then it does not matter which float style was active when the float type was defined because it is restyled before each use of an object where this option applies.
+`\trivfloat` must be used before `\AtBeginDocument{\DeclareCaptionSubType{<type>}}`.
+
+\DescribeMacro{\DeclareFloatingEnvironment}
+The \pkg{newfloat} package provides the `\DeclareFloatingEnvironment[<options>]{<type>}` command which is a newer alternative to `\newfloat` and `\trivfloat`.
+With it's key=value options it is more intuitive than `\newfloat` and more flexible than `\trivfloat`.
+Unlike `\newfloat` and `\trivfloat` it automatically capitalizes `<type>` before using it as float name.
+It seems to ignore `\floatstyle` so you need to specify that in the options.
+The \pkg{newfloat} package is written by the same author like the \pkg{subcaption} package so you don't need to worry about defining subtypes manually.
+
+
+\subsubsection{New object style groups}
+\label{new-object-style-groups}
+
+Several object styles can be combined to a group.
+You can set options for all styles contained in a group using `\objectset[<group>]{<options>}`.
+
+\DescribeMacro{\NewObjectStyleGroup}
+`\NewObjectStyleGroup{<group>}{<styles*>}`
+defines a new style group consisting of the styles `<styles*>`.
+`<styles*>` is a comma separated list of styles.
+In contrast to `<styles>` it may *not* contain style groups.
+
+\DescribeMacro{\AddObjectStyleToGroup}
+`\AddObjectStyleToGroup{<group>}{<style>}`
+adds an existing style to an existing group.
+
+
+\subsubsection{Hooks}
+\label{hooks}
+
+This package provides several commands similar to `\AtBeginDocument`
+which take one argument, \TeX\ code which is executed at a later point in time.
+
+
+\DescribeMacro{\AtBeginObject}
+`\AtBeginObject{<code>}`
+ runs `<code>` every time at the begin of an \env{object} environment
+ (including \env{figureobject}, \env{tableobject} and \cmd{\includegraphicobject}).
+ This hook is inside of the group but before any options are processed.
+
+\DescribeMacro{\AtBeginSubobject}
+`\AtBeginSubobject{<code>}`
+ runs `<code>` every time at the begin of a \env{subobject} environment
+ (including \cmd{\includegraphicsubobject}).
+ This hook is inside of the group but before any options are processed.
+
+\DescribeMacro{\AtBeginGraphicObject}
+`\AtBeginGraphicObject{<code>}`
+ runs `<code>` every time in \cmd{\includegraphicobject} and \cmd{\includegraphicsubobject}.
+ This hook is after the object\slash subobject hook but before any options are processed.
+
+
+\subsection{Initialization}
+\label{initialization}
+
+This package uses the \pkg{float} package to restyle \env{table} to `plaintop` and `figure` to `plain`
+so that captions of tables appear always above the table and captions of figures always below the figure.
+The reasoning is explained in~\autocite{texexchange_caption_position}.
+If you really want to place captions differently you can do that with `\restylefloat` (see \pkg{float} package documentation~\autocite{float}) or by setting the `float style` option.
+However, I would advice to rethink why you would want to do that.
+
+Unless this package is loaded with the \pkgoptn{allowstandardfloats} option
+it redefines the \env{table} and `figure` environments to issue a warning if they are used directly.
+This warning should not influence their usual behavior, though.
+Instead of \env{table}\slash `figure` you should use \env{tableobject}\slash \env{figureobject} or \cmd{\includegraphicobject},
+otherwise this package cannot help you.
+
+Unless this package is loaded with the \pkgoptn{nographic} option
+it loads the \pkg{graphicx} package in order to include graphics.
+It also guarantees that the paper size of the generated pdf matches \LaTeX' point of view (instead of depending on the system settings).
+
+Unless this package is loaded with the \pkgoptn{noarray} option
+it loads the \pkg{array} package which defines additional column specification features like `>{<prefix>}`, `<{<suffix>}` and `!{<addcolsep>}`
+and the `\newcolumntype{<col>}[<args>]{<spec>}` command.
+It also changes the implementation of how lines (rules) are drawn
+but that is irrelevant if you use the recommendations given in the \pkg{booktabs} package documentation~\autocite[section~2 \sectionname{The layout of formal tables}]{booktabs}.
+Loading the \pkg{array} package is merely for convenience. This package does not use any of it's features.
+
+Unless this package is loaded with the \pkgoptn{nobooktabs} option
+it loads the \pkg{booktabs} package which defines commands for formatting tables, most importantly `\toprule`, `\midrule` and `\bottomrule`.
+These are used by the `table head` key unless you redefine it using `table head style`.
+
+Other packages loaded by this package are listed in \cref{used-packages}.
+
+
+\subsection{Package options}
+\label{package-options}
+
+The package options are implemented using the standard \LaTeX\ package options handling functionality as described in~\autocite{clsguide}.
+Therefore they do *not* take any values but consist of keys only.
+Instead I usually provide two separate keys, one which enables an option and another which disables the option.
+The keys with a~\radioon\ are active by default and the keys with a~\radiooff\ are inactive by default.
+
+\pkgoptndoc*{graphicx} use the \pkg{graphicx} package as backend for \cmd{\includegraphicobject}.
+\pkgoptndoc{graphbox} use the \pkg{graphbox} package as backend for \cmd{\includegraphicobject}.
+\pkgoptndoc{nographic} do not load \pkg{graphicx} or \pkg{graphbox}.
+ If you use this option \cmd{\includegraphicobject} and \cmd{\includegraphicsubobject} are not defined.
+
+ Warning: Without driver specific packages like \pkg{graphicx}, \pkg{geometry} or \pkg{hyperref} the paper size of the resulting pdf depends on the system settings, independent of what you set in \LaTeX. \autocite{texexchange_papersize}
+
+\pkgoptndoc*{array} load the \pkg{array} package.
+ There is no difference between using this package option or a separate `\usepackage{array}`.
+\pkgoptndoc{noarray} do *not* load the \pkg{array} package.
+
+\pkgoptndoc*{booktabs} load the \pkg{booktabs} package.
+ There is no difference between using this package option or a separate `\usepackage{booktabs}`.
+\pkgoptndoc{nobooktabs} do *not* load the \pkg{booktabs} package.
+ Please note that the `table head` key initially relies on the booktabs package.
+ If you want to use it with this package option you need to redefine it with `table head style`.
+
+\pkgoptndoc{longtable} load the \pkg{longtable} package.
+ There is no difference between using this package option or a separate `\usepackage{longtable}`.
+\pkgoptndoc*{nolongtable} do *not* load the \pkg{longtable} package.
+
+\pkgoptndoc{allowstandardfloats} do not redefine the \env{table} and `figure` environments.
+ Without this option they are redefined to issue a warning if they are used directly.
+ This warning should not influence their usual behavior.
+ Instead of \env{table}\slash `figure` you should use \env{tableobject}\slash \env{figureobject} or \cmd{\includegraphicobject},
+ otherwise this package cannot help you.
+\endpkgoptndoc
+
+
+\subsection{Help}
+\label{help}
+
+If you get an error message and don't understand where it comes from
+or the output is different from what you expected
+the following features may give you a better understanding of what this package is doing.
+These features are based on the \TeX\ primitive `\show`.
+
+\DescribeMacro{\show}
+`\show` shows (among other information) the parameter text and the replacement text of a macro on the terminal and in the log file.
+If you use one of the following features you most likely want to know the replacement text which is the part between `->` and the last `.` on the line.
+In errorstopmode mode (i.e.\ without `--interaction=nonstopmode` which most IDEs pass by default) \TeX\ stops after `\show` and waits until you confirm that you have read the information and it may proceed by pressing enter.
+For more information see \mycite[section~34.1]{texbytopic}.
+
+\DescribeHandler{.show value}
+The `.show value` handler can be used to show the value of a \keytype{storing key}
+(see \pkg{pgfkeys} documentation~\autocite[section~87.4.9 \sectionname{Handlers for Key Inspection}]{tikz}).
+For example:
+
+\begin{examplecode}
+\includegraphicsubobject[sep/.show value]{<filename>}
+\end{examplecode}
+
+\DescribeHandler{.show boolean}
+This package also defines a new handler called `.show boolean` which can be used to show the value of a \keytype{boolean key}.
+For example:
+
+\begin{examplecode}
+\objectset{warn other env/.show boolean}
+\end{examplecode}
+
+\DescribeMacro{\ShowObjectStylesInGroup}
+`\ShowObjectStylesInGroup{<group>}` shows all object styles which are contained in the given group.
+The styles are wrapped in curly braces so that I can iterate over them with the \LaTeX\ command `\@tfor`.
+
+\DescribeMacro{\ShowObjectStyleOptions}
+`\ShowObjectStyleOptions{<style>}` shows the options set for a specific style.
+Please note that this does *not* show directly set options (i.e.\ options set by `\objectset` without the optional argument and options in the options argument of the object).
+
+\DescribeKey{show env args}
+See also the `show env args` key of the \env{object} and \env{subobject} environments.
diff --git a/macros/latex/contrib/easyfloats/doc/content/examples.tex b/macros/latex/contrib/easyfloats/doc/content/examples.tex
new file mode 100644
index 0000000000..b712740b9b
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/doc/content/examples.tex
@@ -0,0 +1,355 @@
+% !TeX root = ../easyfloats.tex
+
+\section{Examples}
+\label{examples}
+
+Let's start with a few examples.
+Environments, commands and keys defined by this package are links (both in the code and in the text).
+Klicking on them will get you to their explanation in \cref{documentation}.
+
+\Cref{motivation} gives a motivation why this package is useful.
+There is a list of related packages in \cref{used-packages,other-packages}.
+Package names link to the rather short description in that list.
+
+
+\subsection{Table}
+\label{table}
+Use the \env{tableobject} environment for inserting tables.
+Pass caption and label as keyword arguments.
+You can't mess up the order of caption and label and you get a warning if you forget to specify them.
+You don't need two environments (one for the float, one for the table---`tableobject` can do both).
+\pkg{booktabs} (and \pkg{array}) are loaded automatically (if not disabled, see \cref{package-options}).
+
+\begin{examplecode}
+\documentclass{article}
+\usepackage{easyfloats}
+\objectset{warn no label=false}
+
+\begin{document}
+\begin{tableobject}{caption=Some catcodes, env=tabular}{cl}
+ \toprule
+ Catcode & Meaning \\
+ \midrule
+ 0 & Escape Character \\
+ 1 & Begin Group \\
+ 2 & End Group \\
+ \vdots & \quad \vdots \\
+ \bottomrule
+\end{tableobject}
+\end{document}
+\end{examplecode}
+
+You can reduce typing effort even further by using the `table head` key, see \cref{longtable}.
+
+
+\subsection{Graphic}
+\label{graphic}
+Use the \cmd{\includegraphicobject} command to insert a graphic.
+It is a wrapper around \pkg{graphicx}' `\includegraphics` command taking the same arguments.
+No need for a surrounding `figure` environment.
+I have extended the allowed optional keyword argument to also accept caption, label and more.
+`details` are appended to the caption below the figure but not in the list of figures.
+Select with the \pkgoptn{graphicx} or \pkgoptn{graphbox} package options whether you want to use the commonly used \pkg{graphicx} package or it's extension \pkg{graphbox}.
+
+\begin{examplecode}
+\documentclass{article}
+\usepackage{easyfloats}
+\usepackage{hyperref}
+\objectset[figure]{graphic width=.8\linewidth}
+
+\begin{document}
+\includegraphicobject[%
+ label = lion,
+ caption = CTAN lion drawing by Duane Bibby,
+ details = Thanks to \href{https://ctan.org/lion/files}{www.ctan.org}.,
+]{graphics/ctan_lion}
+
+\listoffigures
+\end{document}
+\end{examplecode}
+
+If you omit \key{caption} or `label` the file name is used.
+See `auto label`, `auto caption`, `auto label strip path` and `auto caption strip path`.
+
+
+\subsection{Subobjects}
+\label{subobjects-2}
+Use the \env{subobject} environment to combine two (or more) subobjects to one big object.
+The `contains subobjects` option causes the `env` option to be applied to the subobjects instead of the containing object.
+Changing the `subobject linewidth` is usually not necessary but in this example the tables fill only a small part of the width
+so they are too far apart from each other if each is centered on `.5\linewidth`.
+Pay attention to *not* insert an empty line between the subobjects, otherwise they will be placed below each other instead of side by side.
+If you want them to be placed below each other you can use the `ver` option.
+
+`\captionsetup` is explained in the \pkg{caption} package documentation~\autocite{caption}.
+
+\begin{examplecode}
+\documentclass{article}
+\usepackage{easyfloats}
+
+\objectset[table]{env=tabular}
+\captionsetup[sub]{list=true}
+
+\begin{document}
+\begin{tableobject}{contains subobjects,
+ caption = Two test tables,
+ label = tabs abc 123,
+ subobject linewidth = .25\linewidth,
+ }
+ \begin{subobject}{caption=Abc \& 123}{rl}
+ \toprule
+ abc & 123 \\
+ de & 45 \\
+ f & 6 \\
+ \bottomrule
+ \end{subobject}
+ \begin{subobject}{caption=123 \& abc}{lr}
+ \toprule
+ 123 & abc \\
+ 45 & de \\
+ 6 & f \\
+ \bottomrule
+ \end{subobject}
+\end{tableobject}
+\end{document}
+\end{examplecode}
+
+\subsection{Longtable}
+\label{longtable}
+If you are undecided whether to use floating `tabular`s or \env{longtable}s which can break across pages you can use the following approach.
+Changing between them is as easy as changing `env=longtable` to `env=tabular` once.
+The table head and foot are set by the key `table head` and are by default formatted with the \pkg{booktabs} package.
+(If you don't like this you can change the definition of `table head` with `table head style`.)
+The column specification cannot be given as a separate argument (like in the example above) but must be set with the `arg` key
+because otherwise the column specification would be after the table head.
+
+\begin{examplecode}
+\documentclass{article}
+\usepackage[longtable]{easyfloats}
+\usepackage{siunitx}
+
+\newcommand\pminfty{\multicolumn1r{$\pm\infty$}}
+
+\objectset[table]{env=longtable}
+
+\begin{document}
+\begin{tableobject}{%
+ caption = Trigonometric functions,
+ label = trifun,
+ arg = {
+ S[table-format=2.0, table-space-text-post=\si{\degree}] <{\si{\degree}} !\quad
+ *2{S[table-format=+1.2]}
+ S[table-format=+4.2]
+ },
+ table head = \multicolumn1{c!\quad}{$x$} & $\sin x$ & $\cos x$ & $\tan x$,
+}
+
+ 0 & 0.00 & 1.00 & 0.00 \\
+ 5 & 0.09 & 1.00 & 0.09 \\
+ 10 & 0.17 & 0.98 & 0.18 \\
+ 15 & 0.26 & 0.97 & 0.27 \\
+ 20 & 0.34 & 0.94 & 0.36 \\
+ 25 & 0.42 & 0.91 & 0.47 \\
+ 30 & 0.50 & 0.87 & 0.58 \\
+ 35 & 0.57 & 0.82 & 0.70 \\
+ 40 & 0.64 & 0.77 & 0.84 \\
+ 45 & 0.71 & 0.71 & 1.00 \\
+ 50 & 0.77 & 0.64 & 1.19 \\
+ 55 & 0.82 & 0.57 & 1.43 \\
+ 60 & 0.87 & 0.50 & 1.73 \\
+ 65 & 0.91 & 0.42 & 2.14 \\
+ 70 & 0.94 & 0.34 & 2.75 \\
+ 75 & 0.97 & 0.26 & 3.73 \\
+ 80 & 0.98 & 0.17 & 5.67 \\
+ 85 & 1.00 & 0.09 & 11.43 \\
+ 90 & 1.00 & 0.00 & \pminfty \\
+\end{tableobject}
+\begin{tableobject}{%
+ caption = Squared trigonometric functions,
+ label = trifun2,
+ arg = {
+ S[table-format=2.0, table-space-text-post=\si{\degree}] <{\si{\degree}} !\quad
+ *2{S[table-format=+1.2]}
+ S[table-format=+4.2]
+ },
+ table head = \multicolumn1{c!\quad}{$x$} & {$\sin^2 x$} & {$\cos^2 x$} & {$\tan^2 x$},
+}
+
+ 0 & 0.00 & 1.00 & 0.00 \\
+ 5 & 0.01 & 0.99 & 0.01 \\
+ 10 & 0.03 & 0.97 & 0.03 \\
+ 15 & 0.07 & 0.93 & 0.07 \\
+ 20 & 0.12 & 0.88 & 0.13 \\
+ 25 & 0.18 & 0.82 & 0.22 \\
+ 30 & 0.25 & 0.75 & 0.33 \\
+ 35 & 0.33 & 0.67 & 0.49 \\
+ 40 & 0.41 & 0.59 & 0.70 \\
+ 45 & 0.50 & 0.50 & 1.00 \\
+ 50 & 0.59 & 0.41 & 1.42 \\
+ 55 & 0.67 & 0.33 & 2.04 \\
+ 60 & 0.75 & 0.25 & 3.00 \\
+ 65 & 0.82 & 0.18 & 4.60 \\
+ 70 & 0.88 & 0.12 & 7.55 \\
+ 75 & 0.93 & 0.07 & 13.93 \\
+ 80 & 0.97 & 0.03 & 32.16 \\
+ 85 & 0.99 & 0.01 & 130.65 \\
+ 90 & 1.00 & 0.00 & \pminfty \\
+\end{tableobject}
+\begin{tableobject}{%
+ caption = Cubed trigonometric functions,
+ label = trifun3,
+ arg = {
+ S[table-format=2.0, table-space-text-post=\si{\degree}] <{\si{\degree}} !\quad
+ *2{S[table-format=+1.2]}
+ S[table-format=+4.2]
+ },
+ table head = \multicolumn1{c!\quad}{$x$} & {$\sin^3 x$} & {$\cos^3 x$} & {$\tan^3 x$},
+}
+
+ 0 & 0.00 & 1.00 & 0.00 \\
+ 5 & 0.00 & 0.99 & 0.00 \\
+ 10 & 0.01 & 0.96 & 0.01 \\
+ 15 & 0.02 & 0.90 & 0.02 \\
+ 20 & 0.04 & 0.83 & 0.05 \\
+ 25 & 0.08 & 0.74 & 0.10 \\
+ 30 & 0.12 & 0.65 & 0.19 \\
+ 35 & 0.19 & 0.55 & 0.34 \\
+ 40 & 0.27 & 0.45 & 0.59 \\
+ 45 & 0.35 & 0.35 & 1.00 \\
+ 50 & 0.45 & 0.27 & 1.69 \\
+ 55 & 0.55 & 0.19 & 2.91 \\
+ 60 & 0.65 & 0.13 & 5.20 \\
+ 65 & 0.74 & 0.08 & 9.86 \\
+ 70 & 0.83 & 0.04 & 20.74 \\
+ 75 & 0.90 & 0.02 & 51.98 \\
+ 80 & 0.96 & 0.01 & 182.41 \\
+ 85 & 0.99 & 0.00 & 1493.29 \\
+ 90 & 1.00 & 0.00 & \pminfty \\
+\end{tableobject}
+\end{document}
+\end{examplecode}
+
+\subsection{Local definitions in tables}
+\label{local-definitions-in-tables}
+
+If you want to define a command locally for one table you cannot put it's definition in the first cell because each cell is a separate group
+(meaning that the definition will be forgotten at the end of the cell).
+Instead I provide the `exec` key whose value is executed inside of the object but before `env`.
+If you want to tinker around with catcodes keep in mind that arguments are always read entirely before expansion and execution.
+The \eTeX\ primitive `\scantokens` can be useful to define active characters.
+If you are unfamiliar with how \TeX\ processes a file you can read up on it in \mycite[section~1]{texbytopic}.
+
+\begin{examplecode}
+\documentclass{article}
+\usepackage{easyfloats}
+\usepackage[table]{xcolor}
+
+% avoid Warning: Font shape `OMS/cmtt/m/n' undefined
+\usepackage[T1]{fontenc}
+% fontenc T1 causes unclean/pixelated font on some systems
+% and trouble with copying ligatures from pdf => change font
+% lmodern is relatively close to the default font but unmaintained
+\usepackage{lmodern}
+
+\colorlet{rowbg}{gray!50}
+
+\newcommand\charsym[1]{\texttt{#1}}
+\newcommand\charname[1]{$\langle$#1$\rangle$}
+
+\begin{document}
+\begin{tableobject}{%
+ caption = Category Codes,
+ details = Highlighted catcodes have no tokens.,
+ label = catcodes,
+ env = tabular,
+ arg = cll,
+ table head = Catcode & Meaning & Characters,
+ exec = {%
+ \catcode`* = \active
+ \scantokens{\def*{\rowcolor{rowbg}}}%
+ \catcode`= = \the\catcode`&%
+ \catcode`, = \the\catcode`&%
+ },
+}
+ * 0 = Escape character, \charsym\textbackslash \\
+ 1 = Begin grouping, \charsym\{ \\
+ 2 = End grouping, \charsym\} \\
+ 3 = Math shift, \charsym\$ \\
+ 4 = Alignment tab, \charsym\& \\
+ * 5 = End of line, \charname{return} \\
+ 6 = Parameter, \charsym\# \\
+ 7 = Superscript, \charsym\^ \\
+ 8 = Subscript, \charsym\_ \\
+ * 9 = Ignored character, \charname{null} \\
+ 10 = Space, \charname{space} and
+ \charname{tab} \\
+ 11 = Letter, \charsym{a}--\charsym{z} and
+ \charsym{A}--\charsym{Z} \\
+ 12 = Other, other characters \\
+ % "In plain TeX this is only the tie character ~"
+ % TeX by Topic, page 30
+ 13 = Active character, \charsym{\string~} \\
+ * 14 = Comment character, \charsym\% \\
+ * 15 = Invalid character, \charname{delete} \\
+\end{tableobject}
+\end{document}
+\end{examplecode}
+
+\subsection{New object style~\slash\ `tikzobject`}
+\label{new-object-style-tikzobject}
+
+You can easily define new object environments.
+For more information see \cref{new-object-styles-and-types}.
+
+\begin{examplecode}
+\documentclass{article}
+\usepackage{easyfloats}
+\usepackage{tikz}
+
+\NewObjectStyle{tikz}{type=figure, env=tikzpicture}
+% I am not using `arg=[3D]` so that I can still pass an optional argument to tikz3dobject
+\NewObjectStyle{tikz3d}{type=figure, env=tikzpicture, exec=\tikzset{3D}}
+
+\tikzset{
+ 3D/.style = {
+ x = {(-3.85mm, -3.85mm)},
+ y = {(1cm, 0cm)},
+ z = {(0cm, 1cm)},
+ },
+}
+\objectset{warn no label=false}
+
+\begin{document}
+\begin{tikzobject}{caption=2D coordinate system}
+ \newcommand\n{5}
+ \newcommand\w{.075}
+ \draw[->] (0,0) -- ++(\n,0);
+ \draw[->] (0,0) -- ++(0,\n);
+ \foreach \i in {1,...,\n-1} {
+ \draw (\i,0) +(0,\w) -- +(0,-\w);
+ \draw (0,\i) +(\w,0) -- +(-\w,0);
+ }
+\end{tikzobject}
+\begin{tikz3dobject}{caption=3D coordinate system}
+ \newcommand\n{5}
+ \newcommand\w{.075}
+ \draw[->] (0,0,0) -- ++(\n,0,0);
+ \draw[->] (0,0,0) -- ++(0,\n,0);
+ \draw[->] (0,0,0) -- ++(0,0,\n);
+ \foreach \i in {1,...,\n-1} {
+ \draw (\i,0,0) +(0,\w,0) -- +(0,-\w,0);
+ \draw (0,\i,0) +(\w,0,0) -- +(-\w,0,0);
+ \draw (0,0,\i) +(0,\w,0) -- +(0,-\w,0);
+ }
+\end{tikz3dobject}
+\end{document}
+\end{examplecode}
+
+\subsection{Nonfloating objects}
+\label{nonfloating-objects}
+If your professor absolutely won't allow floating objects you can easily disable them globally
+(for all objects based on the \env{object} environment defined by this package which is internally used by \env{tableobject} and \cmd{\includegraphicobject}).
+
+\begin{examplecode}
+\objectset{placement=H}
+\end{examplecode}
diff --git a/macros/latex/contrib/easyfloats/doc/content/installation.tex b/macros/latex/contrib/easyfloats/doc/content/installation.tex
new file mode 100644
index 0000000000..a8dbe09394
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/doc/content/installation.tex
@@ -0,0 +1,8 @@
+% !TeX root = ../easyfloats.tex
+
+\section{Installation}
+\label{installation}
+
+This package is still very new.
+If it is not yet contained in your \TeX\ distribution
+just download the \filename{sty-file} and put it next to your main document.
diff --git a/macros/latex/contrib/easyfloats/doc/content/license.tex b/macros/latex/contrib/easyfloats/doc/content/license.tex
new file mode 100644
index 0000000000..5babf2b965
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/doc/content/license.tex
@@ -0,0 +1,17 @@
+% !TeX root = ../easyfloats.tex
+
+\section{License}
+\label{license}
+
+This package and it's documentation are distributed under the \license{lppl}, version 1.3 or later.
+See \filename{license.txt}.
+The preamble of the documentation may alternatively, at your choice, be reused under the terms of the \license{wtfpl}, version 2 or later.
+
+Additionally to the rights granted by the \LaTeX\ Project Public License
+you have permission to freely distribute *unmodified* copies
+of the files \filename{easyfloats.sty} and \filename{doc/easyfloats.pdf} without other files of this work.
+The other files of this work can be found at:
+\url{https://gitlab.com/erzo/latex-easyfloats}
+
+The examples and tests are distributed under the \license{wtfpl}, version 2 or later.
+See \filename{test/license.txt}.
diff --git a/macros/latex/contrib/easyfloats/doc/content/motivation.tex b/macros/latex/contrib/easyfloats/doc/content/motivation.tex
new file mode 100644
index 0000000000..8de941b839
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/doc/content/motivation.tex
@@ -0,0 +1,378 @@
+% !TeX root = ../easyfloats.tex
+
+\section{Motivation}
+\label{motivation}
+
+In this section I will explain how to insert figures and tables in standard \LaTeX\ without this package and how this package can improve that.
+If you are only interested in how to use this package not why, see \cref{examples} for examples and \cref{documentation} for an explanation of the commands, environments and options defined by this package.
+
+\subsection{Graphics}
+\label{graphics}
+
+Inserting a graphic without using this package requires 6 lines of code (\pkg{graphicx} or \pkg{graphbox} must be loaded for `\includegraphics`):
+\begin{examplecode\starred}{\ExamplecodeNoBox\ExamplecodeLinenumbers}
+\begin{figure}
+ \centering
+ \includegraphics[graphic width=.8\linewidth]{ctan_lion}
+ \caption{CTAN lion drawing by Duane Bibby}
+ \label{ctan_lion}
+\end{figure}
+\end{examplecode\starred}
+
+\begin{description}
+\item[Lines 1 and 6]
+ open\slash close a floating environment.
+ The content of this environment can float around so that it won't cause a bad page break.
+ You don't need this if you really just want to insert a graphic exactly here (like a logo in a header)
+ but a graphic cannot break across pages so if it is too large for the end of the current page it will move to the next page leaving the end of this page empty.
+ This is a waste of paper and may confuse a reader by suggesting this might be the end of a chapter.
+ A floating environment can help you by putting the figure where it fits best.
+
+ The placement determines where a float is allowed to be placed.
+ Initially that's the top or bottom of a text page or a separate page just for floats.
+ The placement can be specified for a single floating object by passing an optional argument to the floating environment
+ or for all floating objects using the `\floatplacement` command defined by the \pkg{float} package.
+ (The floating environments `figure` and \env{table} are standard \LaTeX\ and do not require the \pkg{float} package.)
+ The allowed values for the placement are described in the description of the \env{object} environment's `placement` key.
+
+ There are people who are concerned that a figure not sitting at the exact position might confuse a reader.
+ However, a graphic naturally attracts the reader's attention.
+ Therefore it does not matter where it is located on the double page.
+ The reader will see it.
+
+ Of course the author must ensure that the figure does not float too far away.
+ If that is the case changing the size of this or another graphic,
+ `\usepackage[section]{placeins}`,
+ `\FloatBarrier` (defined by the \pkg{placeins} package),
+ moving this block of lines in the code,
+ changing the placement or
+ tweaking the parameters which govern the placing of floats \autocite[page~28]{latex2e}
+ can help.
+
+\item[Line 2]
+ centers the graphic horizontally on the line.
+
+ The `\centering` command is used instead of the `center` environment because the latter would insert additional vertical space.
+
+ \begin{examplecode\starred}{\ExamplecodeNoBox}
+ \begin{center}
+ ...
+ \end{center}
+ \end{examplecode\starred}
+ is in \LaTeX2\footnote{This will change in \LaTeX3~\autocite{ltx3env}.}
+ \makeatletter
+ (somewhat simplified\footnote{`\begin` checks that it's argument is defined, `\end` checks that it's argument matches that of `\begin` and deals with `\ignorespacesafterend` and `\@endparenv`. Since 2019/10/01 `\begin` and `\end` are robust. Since 2020/10/01 they include hooks. \autocite[section \sectionname{ltmiscen.dtx}]{source2e}})
+ \makeatother
+ equivalent to
+ \begin{examplecode\starred}{\ExamplecodeNoBox}
+ \begingroup
+ \center
+ ...
+ \endcenter
+ \endgroup
+ \end{examplecode\starred}
+
+ This means that if you accidentally try to use `\centering` as an environment instead of a command you will *not* get an error.
+ You might expect to get an error at least for `\endcentering` not being defined
+ but the \TeX\ primitive `\csname` which is used to produce the `\endcentering` token instead defines it to `\relax`, a no operation.
+
+ The output, however, will not be as desired: the group is closed before the end of the paragraph and `\centering` is forgotten before it can take effect.
+
+\item[Line 3]
+ inserts the graphic.
+ This requires the \pkg{graphicx} or \pkg{graphbox} package.
+
+ If you want all graphics to have the same width you can set the `width` globally with `\setkeys{Gin}{width=<dimen>}`.
+ However, that does not work with all options.
+ Unfortunately the \pkg{graphicx} package documentation~\autocite[section~4.6]{graphicx} is not getting more specific than that this works with \enquote{Most of the keyval keys}.
+
+\item[Line 4]
+ inserts the caption.
+
+ Captions for a figure should be placed *below* the figure.
+ Captions for a table should be placed *above* the table.
+ \autocite{texexchange_caption_position}
+
+ `\caption` can be used inside of a floating environment only.
+ If you need a caption for a non-floating object you can either use `\captionof{<type>}{<caption>}` defined by the \pkg{capt-of} or \pkg{caption} package
+ or use a floating environment with the placement `H` defined by the \pkg{float} package.
+ Although the placement can usually be set globally with `\floatplacement` that does *not* work with `H`.
+
+\item[Line 5]
+ defines a label.
+ This is not visible in the output but can be referenced using `\ref{<label>}` or `\pageref{<label>}`.
+ You might want to consider using the \pkg{cleveref} package for references.
+
+ The label must be set inside of or after the caption.
+ A label always refers to the last `\refstepcounter` inside of the current group. \autocite[section \sectionname{ltxref.dtx}]{source2e}
+ `\refstepcounter` is used for example by `\caption` and `\section`.
+ Therefore if you use `\label` after the caption it refers to the caption.
+ If you use it before the caption it refers to the current section\slash subsection\slash subsubsection.
+\end{description}
+
+There are many things that a beginner can do wrong without even getting a warning.
+Three out of this six lines are always the same (lines 1, 2 and~6).
+I don't want to always write them out.
+There is no way to easily switch floating on or off globally.
+
+\bigpar
+
+This package reduces these six lines to a single command and loads \pkg{graphicx} automatically (unless this package is loaded with the `nographic` option).
+\begin{examplecode\starred}{}
+\includegraphicobject[%
+ caption = CTAN lion drawing by Duane Bibby,
+ graphic width = .8\linewidth,
+]{ctan_lion}
+\end{examplecode\starred}
+
+The floating environment is applied automatically.
+It can be changed using the `type` key but I discourage doing so manually.
+Instead I recommend to use the separate optional `<style>` argument if necessary.
+If you do not want the object to float you can pass `placement=H`.
+This works also globally with `\objectset`.
+
+`\centering` is applied automatically.
+It can be changed using the `align` key.
+
+You can set any of the options passed to the `\includegraphics` command globally using:
+\begin{examplecode\starred}{}
+\objectset[figure]{graphic width=.8\linewidth}
+\end{examplecode\starred}
+
+Caption and label can be passed as options.
+Which one is specified first makes no difference.
+I recommend to stick with caption first in case you ever need to work without this package and to not confuse other people who are not familiar with this package.
+If you omit one of them the file name is used.
+See `auto label`, `auto caption`, `auto label strip path` and `auto caption strip path`.
+
+Whether the caption is put above or below the object is specified by the `float style`.
+
+\subsection{Tables}
+\label{tables}
+
+Inserting a table is similar to inserting a graphic except that you replace the `\includegraphics` command with an environment which creates a table, place the caption above the table not below it and use another floating environment, namely \env{table} instead of `figure`.
+
+The following example (not using this package) requires the \pkg{booktabs} package for the horizontal rules and the \pkg{caption} package to have an appropriate space below the caption.
+
+\begin{examplecode\starred}{\ExamplecodeNoBox\ExamplecodeLinenumbers}
+\begin{table}
+ \centering
+ \caption{Some catcodes}
+ \label{catcodes}
+ \begin{tabular}{cl}
+ \toprule
+ Catcode & Meaning \\
+ \midrule
+ 0 & Escape Character \\
+ 1 & Begin Group \\
+ 2 & End Group \\
+ \vdots & \quad \vdots \\
+ \bottomrule
+ \end{tabular}
+\end{table}
+\end{examplecode\starred}
+
+What I have said about floating environments, `\centering`, `\caption` and `\label` in \cref{graphics} is also valid for tables.
+New are lines 5--14.
+We now have two environments nested inside of each other.
+The outer environment (lines 1 and~15) is the floating environment.
+The inner environment (lines 5--14) is the environment which creates the table.
+The inner environment takes a column specification telling \LaTeX\ how many columns the table has and how they are supposed to be aligned.
+In this case that is `cl`: Two columns, the first centered, the second left aligned.
+For more information about column specifications see the \pkg{array} package documentation~\autocite[section~1]{array}.
+
+`\toprule`, `\midrule` and `\bottomrule` (defined by the \pkg{booktabs} package) produce horizontal lines.
+They differ in the width of the line and\slash or spacing around them.
+In contrast to the standard \LaTeX\ `\hline` command they have proper spacing around them.
+
+`&` separates columns, `\\` separates rows.
+Indentation and spaces at the beginning and end of a cell are ignored.
+
+\bigpar
+
+Using this package we don't need two environments and we don't even need to type out the rule commands if we use `table head`.
+The packages \pkg{caption}, \pkg{booktabs} and \pkg{array} are loaded automatically (unless you load this package with `nobooktabs` or `noarray`).
+\begin{examplecode\starred}{}
+\begin{tableobject}{%
+ caption = Some catcodes,
+ label = catcodes,
+ env = tabular,
+ arg = cl,
+ table head = Catcode & Meaning,
+}
+ 0 & Escape Character \\
+ 1 & Begin Group \\
+ 2 & End Group \\
+ \vdots & \quad \vdots \\
+\end{tableobject}
+\end{examplecode\starred}
+
+Also we gain the possibility to easily switch between different tabular-like environments, see \cref{longtable} and the example given for the `(<env>) arg(s) +` key in \cref{object-environment}.
+
+\subsection{Subobjects}
+\label{subobjects}
+
+There are several packages to combine several figures\slash tables into a single floating environment.
+\mycite{l2tabu} recommends using \pkg{subcaption} over \pkg{subfig} and the long deprecated \pkg{subfigure}.
+
+The \pkg{subcaption} package provides several ways to do this.
+The first one is using the `\subcaptionbox` command.
+
+\begin{examplecode\starred}{\ExamplecodeNoBox\ExamplecodeLinenumbers}
+\begin{table}
+ \centering
+ \caption{Category and character codes}
+ \label{codes}
+ \subcaptionbox{Category codes\label{catcodes}}{%
+ \begin{tabular}{cl}
+ \toprule
+ Catcode & Category \\
+ \midrule
+ 0 & Escape Character \\
+ 1 & Begin Group \\
+ 2 & End Group \\
+ \vdots & \quad \vdots \\
+ \bottomrule
+ \end{tabular}%
+ }%
+ \qquad
+ \subcaptionbox{Character codes\label{charcodes}}{%
+ \begin{tabular}{cr<{\hspace{1.3em}}}
+ \toprule
+ Character & \multicolumn1c{Charcode} \\
+ \midrule
+ \textbackslash & \number`\\ \\
+ \{ & \number`\{ \\
+ \} & \number`\} \\
+ \vdots & \vdots \phantom{0} \\
+ \bottomrule
+ \end{tabular}%
+ }%
+\end{table}
+\end{examplecode\starred}
+
+As the subobjects are inside of an argument they cannot contain code which relies on changing catcodes e.g.\ `\verb`.
+Aside from that it just doesn't seem elegant to put an environment inside of an argument.
+
+If you accidentally put the label in the second argument of `\subcaptionbox` instead of in the first it refers to the parent object instead of the subobject and you won't get an error or a warning for that.
+
+Note how I have commented out line breaks in order to avoid undesired spaces.
+
+The second way is to use the `subfigure`\slash `subtable` environment.
+Because the subobject is not inside of an argument it is possible to use `\verb`.
+
+\begin{examplecode\starred}{\ExamplecodeNoBox\ExamplecodeLinenumbers}
+\begin{table}
+ \caption{Category and character codes}
+ \label{codes}
+ \begin{subtable}{.5\linewidth}
+ \centering
+ \caption{Category codes}
+ \label{catcodes}
+ \begin{tabular}{cl}
+ \toprule
+ Catcode & Category \\
+ \midrule
+ 0 & Escape Character \\
+ 1 & Begin Group \\
+ 2 & End Group \\
+ \vdots & \quad \vdots \\
+ \bottomrule
+ \end{tabular}%
+ \end{subtable}%
+ \begin{subtable}{.5\linewidth}
+ \centering
+ \caption{Character codes}
+ \label{charcodes}
+ \begin{tabular}{cr<{\hspace{1.3em}}}
+ \toprule
+ Character & \multicolumn1c{Charcode} \\
+ \midrule
+ \verb|\| & \number`\\ \\
+ \verb|{| & \number`\{ \\
+ \verb|}| & \number`\} \\
+ \vdots & \vdots \phantom{0} \\
+ \bottomrule
+ \end{tabular}%
+ \end{subtable}%
+\end{table}
+\end{examplecode\starred}
+
+But why having different environments for subfigures and subtables?
+The floating environment specifies the type already.
+
+These environments are based on a minipage and require you to always explicitly specify the width of this minipage.
+On the one hand I don't want to always type that out.
+On the other hand I want to be able to change the width once for all subobjects for easier consistency.
+
+Caption and label must be placed correctly, see \cref{graphics}.
+Even if you restyle the floating environment to always put the caption at the top or bottom using the \pkg{float} package this does *not* apply to subobjects.
+
+It is important to comment out line breaks because the widths of the two minipages add up to the line width, a space between them would cause an overfull hbox or a line break.
+
+We need two `\centering`s, one for each subobject.
+Remember what I said about `\centering` and `center` in \cref{graphics}.
+
+\bigpar
+
+This package defines an environment called `subobject` which is a unified wrapper around `\subcaptionbox` and `subfigure`\slash `subtable`.
+Which of these two backends should be used can be specified with the `subcaptionbox` and `subpage` options.
+`subpage` is used by default so that you can usually use `\verb` in the content.
+
+`subobject` can be used inside of any `*object` environment.
+If you define a new object environment with `\NewObjectStyle` it defines a corresponding subpage environment like `subfigure`\slash `subtable` if it does not exist already and if the \pkg{caption} package is new enough.
+If the \pkg{caption} package is older than August~30, 2020 you need to define the subtype manually by putting the following line *before* loading this package \autocite{texexchange_subtype_workaround}:
+\begin{examplecode\starred}{}
+\AtBeginDocument{\DeclareCaptionSubType{<type>}}
+\end{examplecode\starred}
+
+You don't need to write out the width, `.5\linewidth` is used automatically. You can change this value for all subobjects using
+\begin{examplecode\starred}{}
+\objectset{subobject linewidth=<dimen>}
+\end{examplecode\starred}
+
+Caption and label are given as options like for `tableobject`.
+Their order does not matter.
+They are placed above or below the subobject based on the internal command `\caption@iftop` defined by the \pkg{caption} package.
+
+Spaces after `\begin{subobject}` and before and after `\end{subobject}` are ignored so you don't need to comment out the line breaks.
+\unskip\footnote{Actually, spaces after `\begin{subobject}` and before `\end{subobject}` are ignored only if `env` is empty. But if `env` is not empty I am expecting it to be a tabular-like environment where spaces are ignored at the beginning and end of a cell or a tikzpicture where spaces are ignored as well. Spaces after `\end{subobject}` are ignored regardless of `env`.}
+Just make sure you don't have an empty line between the subobject environments.
+That would *not* be ignored.
+
+`\centering` is inserted automatically. It can be changed with `subpage align`.
+
+\begin{examplecode\starred}{}
+\begin{tableobject}{caption=Category and character codes, label=codes, env=tabular, sub}
+ \begin{subobject}{caption=Category codes, label=catcodes}{cl}
+ \toprule
+ Catcode & Category \\
+ \midrule
+ 0 & Escape Character \\
+ 1 & Begin Group \\
+ 2 & End Group \\
+ \vdots & \quad \vdots \\
+ \bottomrule
+ \end{subobject}
+ \begin{subobject}{caption=Character codes, label=charcodes}{cr<{\hspace{1.3em}}}
+ \toprule
+ Character & \multicolumn1c{Charcode} \\
+ \midrule
+ \verb|\| & \number`\\ \\
+ \verb|{| & \number`\{ \\
+ \verb|}| & \number`\} \\
+ \vdots & \vdots \phantom{0} \\
+ \bottomrule
+ \end{subobject}
+\end{tableobject}
+\end{examplecode\starred}
+
+A separator for the subobjects could be defined globally using `sep`, see also `hor` and `ver`.
+
+For including a graphic from an external file this package defines a wrapper command around `subobject` and `\includegraphics` in order to reduce the typing effort:
+\begin{examplecode\starred}{}
+\begin{figureobject}{caption=Two lions, label=lions, sub}
+ \includegraphicsubobject[caption=A lion]{lion-1}
+ \includegraphicsubobject[caption=Another lion]{lion-2}
+\end{figureobject}
+\end{examplecode\starred}
diff --git a/macros/latex/contrib/easyfloats/doc/content/names.tex b/macros/latex/contrib/easyfloats/doc/content/names.tex
new file mode 100644
index 0000000000..e8f6708072
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/doc/content/names.tex
@@ -0,0 +1,18 @@
+% !TeX root = ../easyfloats.tex
+
+\section{Names}
+\label{names}
+
+You have probably heard the term *floating object* or *float* for short.
+That is mainly what this package is about.
+However, I intended to avoid the term *floating* in the name of this package because this package also allows
+to globally disable the floating of those objects.
+Therefore I decided to name this package *objects*.
+
+This name, however, has been rejected by \TeX\ Live as being too generic.
+And they are right, especially for people with an object oriented programming background that name might be misleading.
+\TeX\ Live has informed me that floating objects are still called floats even if they are technically not floating.
+Therefore I have decided to rename this package to *easyfloats*.
+
+I have *not* changed the user interface because the package has already been online for more than half a year on my gitlab repository and I don't know how many people are using the package already.
+Therefore all commands and environments defined by this package still carry the old name *object* in them.
diff --git a/macros/latex/contrib/easyfloats/doc/content/other-packages.tex b/macros/latex/contrib/easyfloats/doc/content/other-packages.tex
new file mode 100644
index 0000000000..609e5fb33b
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/doc/content/other-packages.tex
@@ -0,0 +1,51 @@
+% !TeX root = ../easyfloats.tex
+
+\section{Other packages}
+\label{other-packages}
+
+Other useful packages for dealing with figures or tables:
+\pkgdoc{placeins}
+ When loaded with the `section` package option it prevents floats from floating to another section.
+ It provides the `\FloatBarrier` command which prevents floats from floating past a certain point.
+\pkgdoc{flafter}
+ ensures that floats are not placed before their inclusion in the source code.
+ (With the placement=t it is possible that they are placed on the top of the same page.)
+\pkgdoc{booktabs}
+ for formatting tables
+\pkgdoc{xcolor}
+ When loaded with the package option \pkgoptn{table} it provides commands for coloring tables.
+
+ `\rowcolor{<color>}` sets a background color for a single row. See \cref{local-definitions-in-tables}.
+
+ `\rowcolors{<firstrow>}{<oddcolor>}{<evencolor>}` can be used with the `exec` key and sets alternating row colors for the entire table.
+
+\pkgdoc{array}
+ extends the column specification syntax and defines the `\newcolumntype` command to define custom column types.
+ Also changes the approach how rules are drawn but that is irrelevant if you apply \pkg{booktabs}' guidelines~\autocite[section~2 \sectionname{The layout of formal tables}]{booktabs}.
+\pkgdoc{siunitx}
+ for typesetting numbers and units.
+ It provides the `S` column to align numbers at their decimal separator.
+\pkgdoc{tabularx}
+ A table where the columns adapt to the width of the table, not the other way around.
+ Unlike `tabular*` the space goes into the columns, not between the columns.
+\pkgdoc{longtable}
+ provides tables where a pagebreak is allowed,
+ see \cref{longtable}
+\pkgdoc{hyperref}
+ automatically creates links in the pdf document for example from references to floating objects.
+ With the package option `pdfusetitle` it automatically sets the pdf title and author based on `\title` and `\author`.
+\pkgdoc{cleveref}
+ to reference an object.
+ In contrast to the standard `\ref` and `\pageref`, `\cref` and `\cpageref` automatically detect the type of object and can handle multiple references at once.
+ With the `nameinlink` package option the object type in front of the number becomes part of the link created by hyperref (i.e.\ the link is \enquote{figure 1} instead of \enquote{1} and \enquote{figure } being before the link.)
+ With the `noabbrev` option references are not abbreviated (by default references are abbreviated but only the lower case variants, not the upper case variants which seems inconsistent to me. Abbreviating at the beginning of a sentence is considered bad style~\autocite{texexchange_abbrev_bad_style}.)
+\pkgdoc{biblatex}
+ If you input graphics you need to specify the source.
+ Biblatex creates an entire bibliography for you.
+\pkgdoc{tikz}
+ is an amazingly powerful package to create your own graphics in \LaTeX.
+\pkgdoc{newfloat} provides a more modern command to define new floating environments than the \pkg{float} package.
+\endpkgdoc
+
+
+For more information about floats see \url{https://latexref.xyz/Floats.html} (it seems this is an html version of the above quoted pdf~\autocite{latex2e}).
diff --git a/macros/latex/contrib/easyfloats/doc/content/titlepage.tex b/macros/latex/contrib/easyfloats/doc/content/titlepage.tex
new file mode 100644
index 0000000000..2dd36aa6c8
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/doc/content/titlepage.tex
@@ -0,0 +1,17 @@
+% !TeX root = ../easyfloats.tex
+
+\maketitle
+\thispagestyle{empty}
+\vfill
+\begin{abstract}
+In standard \LaTeX\ inserting objects like figures or tables requires too much knowledge for beginners and too much typing effort and hardcoding for people like me.
+This package aims to make insertion of figures and tables easier for both beginners and experts.
+Despite the term *floats* in it's name it also allows to disable floating of such objects.
+\end{abstract}
+\vfill
+\vspace{20em}
+\url{https://gitlab.com/erzo/latex-easyfloats}
+\clearpage
+
+\tableofcontents
+\pagebreak
diff --git a/macros/latex/contrib/easyfloats/doc/content/used-packages.tex b/macros/latex/contrib/easyfloats/doc/content/used-packages.tex
new file mode 100644
index 0000000000..90efa04688
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/doc/content/used-packages.tex
@@ -0,0 +1,29 @@
+% !TeX root = ../easyfloats.tex
+
+\section{Used packages}
+\label{used-packages}
+
+This package uses the following packages (but depending on the package options it may load more or less packages, see \cref{package-options}):
+\pkgdoc{float}
+ for `placement=H` and `float style`.
+ It also gives you the possibility to define new float types.
+\pkgdoc{caption}
+ In the standard document classes there is no distance at all between a table and it's caption above.
+ The caption package fixes this.
+ It also defines the `\phantomcaption` command which I am using in case that no caption is given.
+ (The documentation of `\phantomcaption` is in the \pkg{subcaption} package.)
+ It also gives you the possibility to customize the layout of captions but I am not changing the default layout.
+ And it is a dependency of the \pkg{subcaption} package.
+\pkgdoc{subcaption}
+ for \hyperref[subobject-environment]{subobjects}
+\pkgdoc{graphicx}/\pkgdoc{graphbox}
+ for inserting graphics
+ (see \cmd{\includegraphicobject})
+\pkgdoc{pgfkeys}
+ for parsing key=value lists
+\pkgdoc{etoolbox}
+ is a collection of small helpers for programming.
+\pkgdoc{environ}
+ to define environments which save their content in a macro.
+ I am using this for the `subcaptionbox` backend of the \env{subobject} environment.
+\endpkgdoc
diff --git a/macros/latex/contrib/easyfloats/doc/easyfloats.bib b/macros/latex/contrib/easyfloats/doc/easyfloats.bib
new file mode 100644
index 0000000000..4a850db306
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/doc/easyfloats.bib
@@ -0,0 +1,141 @@
+@book{texbook,
+ title = {The \TeX book},
+ author = {Donald E. Knuth},
+ year = {1986},
+ isbn = {0-201-13448-9},
+ publisher = {Addison-Wesley},
+}
+
+@book{texbytopic,
+ title = {\TeX\ by Topic},
+ author = {Victor Eijkhout},
+ year = {2007},
+ url = {https://ctan.org/pkg/texbytopic},
+}
+
+@manual{latex2e,
+ title = {\LaTeXe: An unofficial reference manual},
+ url = {https://ctan.org/pkg/latex2e-help-texinfo},
+ date = {2018-10},
+ language = {english},
+}
+
+@manual{clsguide,
+ title = {\LaTeXe\space for class and package writers},
+ author = {The \LaTeX3 Project},
+ url = {https://ctan.org/pkg/clsguide},
+ date = {2006-02-15},
+}
+
+@manual{source2e,
+ title = {The \LaTeXe\ Sources},
+ author = {Johannes Braams
+ and David Carlisle
+ and Alan Jeffrey
+ and Leslie Lamport
+ and Frank Mittelbach
+ and Chris Rowley
+ and Rainer Schöpf},
+ url = {https://ctan.org/pkg/source2e},
+ date = {2020-10-01},
+ language = {english},
+}
+
+@manual{l2tabu,
+ title = {Das \LaTeXe-Sündenregister},
+ author = {Mark Trettin and Marc Ensenbach},
+ url = {https://ctan.org/pkg/l2tabu},
+ date = {2016-02-03},
+ language = {german},
+ addendum = {An English translation of an older version is available at \url{https://ctan.org/pkg/l2tabu-english}},
+}
+
+% ------- Joseph Wright's blog -------
+
+@online{ltx3env,
+ url = {https://www.texdev.net/2011/01/09/latex3-and-document-environments/},
+ urldate = {2020-07-17},
+ author = {Joseph Wright},
+ title = {\LaTeX3 and document environments},
+}
+
+% ------- tex exchange -------
+
+@online{texexchange_abbrev_bad_style,
+ url = {https://tex.stackexchange.com/questions/256849/cleveref-change-behaviour-of-cref-to-use-the-abbreviated-form#comment791998_256849},
+ author = {Toby Cubitt},
+ date = {2016-08-10T18:29:00},
+}
+
+@online{texexchange_caption_position,
+ title = {Why should a table caption be placed above the table?},
+ url = {https://tex.stackexchange.com/questions/3243/why-should-a-table-caption-be-placed-above-the-table},
+ urldate = {2020-07-17},
+}
+
+@online{texexchange_make_at,
+ url = {https://tex.stackexchange.com/questions/201348/why-doesnt-makeatletter-work-inside-newcommand},
+ author = {Manuel},
+ date = {2014-09-16},
+}
+
+@online{texexchange_papersize,
+ url = {https://tex.stackexchange.com/questions/404673/paperwidth-too-large/404693#comment1008643_404673},
+ author = {David Carlisle},
+ date = {2017-12-05},
+}
+
+@online{texexchange_subtype_workaround,
+ url = {https://tex.stackexchange.com/a/63967},
+ author = {user2574},
+ date = {2012-07-19},
+}
+
+% ------- package documentations -------
+
+@manual{array,
+ title = {A new implementation of \LaTeX's tabular and array environment},
+ author = {Frank Mittelbach and David Carlisle},
+ date = {2020-10-01},
+ url = {https://ctan.org/pkg/array},
+}
+
+@manual{booktabs,
+ title = {Publication quality tables in \LaTeX},
+ author = {Simon Fear},
+ date = {2016-04-29},
+ url = {https://ctan.org/pkg/booktabs},
+}
+
+@manual{tikz,
+ title = {\TikZ~\& PGF Manual},
+ author = {Till Tantau},
+ date = {2019-05-09},
+ url = {https://ctan.org/pkg/pgf},
+}
+
+@manual{graphicx,
+ title = {Packages in the `graphics' bundle},
+ author = {D. P. Carlisle},
+ date = {2017-06-01},
+ url = {https://ctan.org/pkg/graphicx},
+}
+
+@manual{float,
+ title = {An Improved Environment for Floats},
+ author = {Anselm Lingnau},
+ date = {2001-11-08},
+ url = {https://ctan.org/pkg/float},
+}
+@manual{caption,
+ title = {Customizing captions of floating environments},
+ author = {Axel Sommerfeldt},
+ date = {2020-09-12},
+ url = {https://ctan.org/pkg/caption},
+}
+@manual{subcaption,
+ title = {The subcaption package},
+ author = {Axel Sommerfeldt},
+ date = {2020-08-24},
+ url = {https://ctan.org/pkg/subcaption},
+}
diff --git a/macros/latex/contrib/easyfloats/doc/easyfloats.pdf b/macros/latex/contrib/easyfloats/doc/easyfloats.pdf
new file mode 100644
index 0000000000..56ea0de9aa
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/doc/easyfloats.pdf
Binary files differ
diff --git a/macros/latex/contrib/easyfloats/doc/easyfloats.tex b/macros/latex/contrib/easyfloats/doc/easyfloats.tex
new file mode 100644
index 0000000000..6e77baccc4
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/doc/easyfloats.tex
@@ -0,0 +1,63 @@
+% !TeX program = pdflatex
+% !TeX option = --shell-escape
+
+% underline links generated with the keyword api defined in preamble/keydoc.tex
+% does *not* affect \ref, \cite, table of contents etc.
+\newif\ifunderlinelinks
+\underlinelinkstrue
+
+\documentclass[a4paper]{ltxdoc}
+
+\usepackage{dtxdescribe}
+\usepackage{parskip}
+\usepackage{csquotes}
+
+\input{preamble/bibliography}
+\input{preamble/macros}
+\input{preamble/examplecode}
+\input{preamble/markdown}
+\input{preamble/link}
+\input{preamble/keydoc}
+\input{preamble/description-links}
+\input{preamble/pdfstring}
+
+\usepackage[hidelinks, pdfusetitle]{hyperref}
+\usepackage[nameinlink, noabbrev]{cleveref}
+
+\newlicense{lppl}{\LaTeX\ Project Public License}{https://www.latex-project.org/lppl/}
+\newlicense{wtfpl}{WTFPL}{http://www.wtfpl.net/}
+
+\makeindex
+
+\title{An easier interface to insert figures, tables and other objects in \LaTeX}
+\author{Erik Zöllner}
+\date{December~20, 2020}
+\package{\jobname}
+\version{v1.0.0}
+
+\newcommand{\myinput}[1]{\input{#1}\unskip}
+
+\input{links}
+\begin{document}
+ \myinput{undescribed-keywords}
+ \myinput{content/titlepage}
+ \myinput{content/examples}
+ \myinput{content/names}
+ \myinput{content/documentation}
+ \myinput{content/installation}
+ \myinput{content/bug-reports-and-contributions}
+ \myinput{content/license}
+
+ \appendix
+ \addtocontents{toc}{\protect\setcounter{tocdepth}{1}}
+ \myinput{content/motivation}
+ \myinput{content/used-packages}
+ \myinput{content/other-packages}
+
+ \section{\refname}
+ Works cited in this documentation (ordered by appearance in this document,
+ if there are several versions on CTAN I am referring to the English pdf):
+ \printbibliography[heading=none]
+
+ \addtocontents{toc}{\protect\setcounter{tocdepth}{3}}
+\end{document}
diff --git a/macros/latex/contrib/easyfloats/doc/lexer/latex_atletter.py b/macros/latex/contrib/easyfloats/doc/lexer/latex_atletter.py
new file mode 100644
index 0000000000..41670d07a8
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/doc/lexer/latex_atletter.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+
+# Copyright © 2020 E. Zöllner
+# Alternatively to the terms of the LPPL, at your choice,
+# you can redistribute and/or modify this file under the
+# terms of the Do What The Fuck You Want To Public License, Version 2,
+# as published by Sam Hocevar. See http://www.wtfpl.net/about/.
+
+from pygments.lexers.markup import TexLexer
+
+re_cmd = r'\\([a-zA-Z@]+|.)'
+
+tokens_root = TexLexer.tokens['root']
+t = next(t for t in tokens_root if 'command' in t)
+i = tokens_root.index(t)
+t = (re_cmd,) + t[1:]
+tokens_root[i] = t
diff --git a/macros/latex/contrib/easyfloats/doc/links.tex b/macros/latex/contrib/easyfloats/doc/links.tex
new file mode 100644
index 0000000000..d304bf308b
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/doc/links.tex
@@ -0,0 +1,44 @@
+\newurllink{etoolbox}{https://ctan.org/pkg/etoolbox}
+\newurllink{environ}{https://ctan.org/pkg/environ}
+\newurllink{placeins}{https://ctan.org/pkg/placeins}
+\newurllink{flafter}{https://tex.stackexchange.com/questions/15706/force-floats-to-be-typeset-after-their-occurrence-in-the-source-text}
+\newurllink{siunitx}{https://ctan.org/pkg/siunitx}
+\newurllink{tabularx}{https://ctan.org/pkg/tabularx}
+\newurllink{cleveref}{https://ctan.org/pkg/cleveref}
+\newurllink{biblatex}{https://ctan.org/pkg/biblatex}
+\newlabellink{storing key}{key-types}
+\newlabellink{executed key}{key-types}
+\newlabellink{boolean key}{key-types}
+\newlabellink{forwarding key}{key-types}
+\newlabellink{unknown key handler}{key-types}
+\newurllink{float}{https://ctan.org/pkg/float}
+\newurllink{graphicx}{https://ctan.org/pkg/graphicx}
+\newurllink{graphics}{https://ctan.org/pkg/graphicx}
+\newurllink{graphbox}{https://ctan.org/pkg/graphbox}
+\newurllink{tikz}{https://www.ctan.org/pkg/pgf}
+\newurllink{array}{https://ctan.org/pkg/array}
+\newurllink{booktabs}{https://ctan.org/pkg/booktabs}
+\newurllink{xcolor}{https://ctan.org/pkg/xcolor}
+\newurllink{longtable}{https://ctan.org/pkg/longtable}
+\newurllink{caption}{https://ctan.org/pkg/caption}
+\newurllink{subcaption}{https://ctan.org/pkg/subcaption}
+\newurllink{newfloat}{https://ctan.org/pkg/newfloat}
+\newurllink{pgfkeys}{https://ctan.org/pkg/pgfkeys}
+\newurllink{hyperref}{https://ctan.org/pkg/hyperref}
+\newurllink{geometry}{https://ctan.org/pkg/geometry}
+\newurllink{trivfloat}{https://ctan.org/pkg/trivfloat}
+\newurllink{capt-of}{https://ctan.org/pkg/capt-of}
+\newurllink{subfigure}{https://ctan.org/pkg/subfigure}
+\newurllink{subfig}{https://ctan.org/pkg/subfig}
+\newurllink{latex2e}{https://ctan.org/pkg/latex2e-help-texinfo}
+\newurllink{clsguide}{https://ctan.org/pkg/clsguide}
+\newurllink{source2e}{https://ctan.org/pkg/source2e}
+\newurllink{l2tabu}{https://ctan.org/pkg/l2tabu}
+\newurllink{texbytopic}{https://ctan.org/pkg/texbytopic}
+\newurllink{eTeX}{https://ctan.org/pkg/etex}
+\newurllink{ltx3env}{https://www.texdev.net/2011/01/09/latex3-and-document-environments/}
+\newurllink{texexchange_abbrev_bad_style}{https://tex.stackexchange.com/questions/256849/cleveref-change-behaviour-of-cref-to-use-the-abbreviated-form#comment791998_256849}
+\newurllink{texexchange_caption_position}{https://tex.stackexchange.com/questions/3243/why-should-a-table-caption-be-placed-above-the-table}
+\newurllink{texexchange_make_at}{https://tex.stackexchange.com/questions/201348/why-doesnt-makeatletter-work-inside-newcommand}
+\newurllink{texexchange_papersize}{https://tex.stackexchange.com/questions/404673/paperwidth-too-large/404693#comment1008643_404673}
+\newurllink{texexchange_subtype_workaround}{https://tex.stackexchange.com/a/63967}
diff --git a/macros/latex/contrib/easyfloats/doc/preamble/bibliography.tex b/macros/latex/contrib/easyfloats/doc/preamble/bibliography.tex
new file mode 100644
index 0000000000..ad24a2b445
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/doc/preamble/bibliography.tex
@@ -0,0 +1,35 @@
+% !TeX root = ../easyfloats.tex
+
+% Copyright © 2020 E. Zöllner
+% Alternatively to the terms of the LPPL, at your choice,
+% you can redistribute and/or modify this file under the
+% terms of the Do What The Fuck You Want To Public License, Version 2,
+% as published by Sam Hocevar. See http://www.wtfpl.net/about/.
+
+\usepackage[%
+ sorting=none, % none=citation order
+]{biblatex}
+
+\setcounter{biburllcpenalty}{8000}
+\setcounter{biburlucpenalty}{8000}
+\setcounter{biburlnumpenalty}{8000}
+
+\addbibresource{\jobname.bib}
+
+\SetCiteCommand\autocite
+
+\newcommand{\mycite}[2][]{%
+ \citetitle{#2}~\autocite[#1]{#2}%
+}
+
+%https://tex.stackexchange.com/a/108349
+\DeclareCiteCommand{\citetitle}
+ {\boolfalse{citetracker}%
+ \boolfalse{pagetracker}%
+ \usebibmacro{prenote}}
+ {\ifciteindex
+ {\indexfield{indextitle}}
+ {}%
+ \printtext[bibhyperref]{\printfield[citetitle]{labeltitle}}}
+ {\multicitedelim}
+ {\usebibmacro{postnote}}
diff --git a/macros/latex/contrib/easyfloats/doc/preamble/description-links.tex b/macros/latex/contrib/easyfloats/doc/preamble/description-links.tex
new file mode 100644
index 0000000000..6eac79bc1c
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/doc/preamble/description-links.tex
@@ -0,0 +1,224 @@
+% !TeX root = ../easyfloats.tex
+
+% Copyright © 2020 E. Zöllner
+% Alternatively to the terms of the LPPL, at your choice,
+% you can redistribute and/or modify this file under the
+% terms of the Do What The Fuck You Want To Public License, Version 2,
+% as published by Sam Hocevar. See http://www.wtfpl.net/about/.
+
+% Links all \cmd, \env and \handler to the corresponding \Describe*.
+% Links all \pkg to a reference defined with \newurllink (see link.tex)
+% Defines \pkgoptndoc to document package otions and links all \pkgoptn to it.
+%
+% \pkgoptndoc{<packageoption>}
+% \pkgoptndoc*{<packageoption>}
+% The starred version is for default package options.
+% The non-starred version is for options disabled by default.
+% Empty lines before a \pkgoptndoc are relevant:
+% Without an empty line they are considered to belong together.
+% With an empty line they do not and \pkgoptndoc@afterpar is inserted as separator.
+% A list of \pkgoptndoc must be closed with \endpkgoptndoc.
+%
+% Defines
+% \NoDescribeMacro{<cs>}
+% \NoDescribeEnv{<environment>}
+% to declare undescribed control sequences or environments
+% which shall not produce a warning when being referenced.
+%
+% Warning: \cmd and \DescribeMacro are not intended for use with control characters.
+%
+% depends on
+% \NewKeyword[\unexpanded]{<keywordtype>}{<keyword>}{<formatmacro-bg>}{<formatmacro-fg>}{<text>}
+% \NoKeyword{<keywordtype>}{<keyword>}{<formatmacro-bg>}{<formatmacro-fg>}
+% \LinkKeyword{<keywordtype>}{<keyword>}<formatmacro-bg><formatmacro-fg>{<text>}
+% from preamble/keydoc.tex
+
+\makeatletter
+
+% --------- \cmd & \(No)DescribeMacro ----------
+
+\newcommand{\DlCmdLabelName}[1]{\detokenize{#1}}
+\newcommand{\Cmd}[1]{\expandafter{\detokenize{#1}\unskip}}
+\newcommand{\CmdBg}{\formatcode}
+\let\DlOriginalDescribeMacro=\DescribeMacro
+\renewcommand{\DescribeMacro}[1]{%
+ \begingroup
+ \def\cmd##1{\formatcodeinmarginpar{\Cmd{##1}}}%
+ \DlOriginalDescribeMacro{#1}%
+ \endgroup
+ \NewKeyword[\unexpanded]{cs}{\DlCmdLabelName{#1}}{\CmdBg}{\Cmd}{}%
+ \AbbrevKeyword[\unexpanded]{}{\DlCmdLabelName{#1}} {cs}{\DlCmdLabelName{#1}}%
+ \ignorespaces
+}
+\newcommand{\NoDescribeMacro}[1]{%
+ \NoKeyword[\unexpanded]{cs}{\DlCmdLabelName{#1}}{\CmdBg}{\Cmd}%
+ \AbbrevKeyword[\unexpanded]{}{\DlCmdLabelName{#1}} {cs}{\DlCmdLabelName{#1}}%
+ \ignorespaces
+}
+\renewrobustcmd{\cmd}[1]{%
+ \LinkKeyword{cs}{\detokenize{#1}}\CmdBg\Cmd{#1}%
+}
+
+
+% --------- \env & \(No)DescribeEnv ----------
+
+\let\DlOriginalDescribeEnv=\DescribeEnv
+\renewcommand{\DescribeEnv}[1]{%
+ \DlOriginalDescribeEnv{#1}%
+ \NewKeyword{env}{#1}{\DlEnvBg}{\DlOriginalEnv}{}%
+ \AbbrevKeyword{}{#1} {env}{#1}%
+ \ignorespaces
+}
+\newcommand{\NoDescribeEnv}[1]{%
+ \NoKeyword{env}{#1}{\DlEnvBg}{\DlOriginalEnv}%
+ \AbbrevKeyword{}{#1} {env}{#1}%
+ \ignorespaces
+}
+\let\DlOriginalEnv=\env
+\renewcommand{\env}[1]{\LinkKeyword{env}{#1}\DlEnvBg\DlOriginalEnv{#1}}
+\newcommand{\DlEnvBg}{\formatcode}
+
+
+% --------- \handler & \DescribeHandler ----------
+
+\let\DlOriginalDescribeHandler=\DescribeHandler
+\renewcommand{\DescribeHandler}[1]{%
+ \DlOriginalDescribeHandler{#1}%
+ \NewKeyword{handler}{#1}{\DlHandlerBg}{\DlOriginalHandler}{}%
+ \AbbrevKeyword{}{#1} {handler}{#1}%
+ \ignorespaces
+}
+\let\DlOriginalHandler=\handler
+\renewcommand{\handler}[1]{\LinkKeyword{handler}{#1}\DlHandlerBg\DlOriginalHandler{#1}}
+\newcommand{\DlHandlerBg}{\formatcode}
+
+\newcommand{\NoDescribeHandler}[1]{%
+ \NoKeyword{handler}{#1}{\DlHandlerBg}{\DlOriginalHandler}%
+ \AbbrevKeyword{}{#1} {handler}{#1}%
+ \ignorespaces
+}
+
+
+% --------- \NoDescribeKey, \NoDescribeVal ----------
+
+\newcommand{\NoDescribeKey}[1]{%
+ \NoKeyword{key}{#1}{\keydoc@key@bg}{\keydoc@original@key}%
+ \AbbrevKeyword{}{#1} {key}{#1}%
+ \ignorespaces
+}
+\newcommand{\NoDescribeVal}[1]{%
+ \NoKeyword{}{#1}{\formatcode}{\val}%
+ \ignorespaces
+}
+
+
+% --------- \DescribeMeta ----------
+
+\newcommand{\DescribeMeta}[1]{%
+ \NewKeyword{meta}{#1}{\formatcode}{\val}{}%
+ \ignorespaces
+}
+
+\let\meta@nolink=\meta
+\renewcommand{\meta}[1]{%
+ \IfKeywordUndefined{meta}{#1}%
+ {\@firstofone}%
+ {\LinkUnformattedKeyword{meta}{#1}}%
+ {\meta@nolink{#1}}%
+}
+
+
+% --------- \pkgoptn & \pkgoptndoc ----------
+
+\let\DlOriginalPkgoptn=\pkgoptn
+\renewcommand{\pkgoptn}[1]{\LinkKeyword{pkgoptn}{#1}\DlPkgoptnBg\DlOriginalPkgoptn{#1}}
+\newcommand{\DlPkgoptnBg}{\formatcode}
+
+\newcommand{\begin@pkgoptndoc}{\begin{itemize}}
+\def \endpkgoptndoc {\end{itemize}}
+\newcommand{\pkgoptndoc@beforepkg@normal}{\item[\radiooff]}
+\newcommand{\pkgoptndoc@beforepkg@default}{\item[\radioon]}
+% inserted before \pkgoptndoc if it was preceded by an empty line
+\newcommand{\pkgoptndoc@afterpar}{\bigpar}
+
+\newif\if@inpkgoptndoc
+
+\newcommand{\pkgoptndoc}{%
+ \unless\if@inpkgoptndoc
+ \begin@pkgoptndoc
+ \@inpkgoptndoctrue
+ \else
+ \ifvmode
+ \pkgoptndoc@afterpar
+ \fi
+ \fi
+ \@ifstar
+ {\pkgoptndoc@beforepkg@default\@pkgoptndoc@do}%
+ {\pkgoptndoc@beforepkg@normal\@pkgoptndoc@do}%
+}
+\newcommand{\@pkgoptndoc@do}[1]{%
+ \NewKeyword{pkgoptn}{#1}{\DlPkgoptnBg}{\DlOriginalPkgoptn}{#1}%
+ \AbbrevKeyword{}{#1} {pkgoptn}{#1}%
+}
+
+\newcommand{\NoDescribePkgoptn}[1]{%
+ \NoKeyword{pkgoptn}{#1}{\DlPkgoptnBg}{\DlOriginalPkgoptn}%
+ \AbbrevKeyword{}{#1} {pkgoptn}{#1}%
+ \ignorespaces
+}
+
+
+% --------- \pkg & \pkgdoc, \NoDescribePkg ----------
+
+\let\DlOriginalPkg=\pkg
+\newcommand{\DlPkgBg}[1]{#1}
+\renewcommand{\pkg}[1]{\LinkKeyword{pkg}{#1}\DlPkgBg\DlOriginalPkg{#1}}
+\newcommand{\pkgdoc}[1]{%
+ \unless\if@inpkgdoc
+ \begin@pkgdoc
+ \@inpkgdoctrue
+ \fi
+ \pkgdoc@beforepkg
+ \NewKeyword{pkg}{#1}{\DlPkgBg}{\DlOriginalPkg}{\link[#1]{#1}}%
+ %\AbbrevKeyword{}{#1} {pkg}{#1}%
+ \let\pkgdoc@beforepkg=\pkgdoc@beforepkg@bak
+ \pkgdoc@lookahead
+}
+\newcommand{\pkgdoc@lookahead}{%
+ \futurelet \pkgdoc@nexttoken \pkgdoc@lookahead@check
+}
+\newcommand{\pkgdoc@lookahead@check}{%
+ \ifcat \noexpand\pkgdoc@nexttoken \space
+ \let\pkgdoc@lookahead@do=\pkgdoc@lookahead
+ \let\pkgdoc@lookahead@gobble=\@firstofone
+ \else\ifx \pkgdoc@nexttoken /%
+ \pkgdoc@pkgsep
+ \let\pkgdoc@beforepkg=\relax
+ \let\pkgdoc@lookahead@do=\pkgdoc@lookahead
+ \let\pkgdoc@lookahead@gobble=\@gobble
+ \else\ifx \pkgdoc@nexttoken \pkgdoc
+ \let\pkgdoc@lookahead@do=\relax
+ \let\pkgdoc@lookahead@gobble=\@empty
+ \else
+ \pkgdoc@descriptionsep
+ \let\pkgdoc@lookahead@do=\relax
+ \let\pkgdoc@lookahead@gobble=\@empty
+ \fi \fi \fi
+ \expandafter \pkgdoc@lookahead@do \pkgdoc@lookahead@gobble
+}
+
+\newcommand{\begin@pkgdoc}{\begin{itemize}}
+\def \endpkgdoc {\end{itemize}}
+\newif\if@inpkgdoc
+\newcommand{\pkgdoc@beforepkg}{\item}
+\newcommand{\pkgdoc@pkgsep}{/}
+\newcommand{\pkgdoc@descriptionsep}{ }
+\let\pkgdoc@beforepkg@bak=\pkgdoc@beforepkg
+
+\newcommand{\NoDescribePkg}[1]{%
+ \NoKeyword{pkg}{#1}{\DlPkgBg}{\DlOriginalPkg}%
+ %\AbbrevKeyword{}{#1} {pkg}{#1}%
+ \ignorespaces
+}
+
+\makeatother
diff --git a/macros/latex/contrib/easyfloats/doc/preamble/examplecode.tex b/macros/latex/contrib/easyfloats/doc/preamble/examplecode.tex
new file mode 100644
index 0000000000..79d3c7f424
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/doc/preamble/examplecode.tex
@@ -0,0 +1,778 @@
+% !TeX root = ../easyfloats.tex
+
+% Copyright © 2020 E. Zöllner
+% Alternatively to the terms of the LPPL, at your choice,
+% you can redistribute and/or modify this file under the
+% terms of the Do What The Fuck You Want To Public License, Version 2,
+% as published by Sam Hocevar. See http://www.wtfpl.net/about/.
+
+% Defines an environment to typeset LaTeX code:
+% \begin{examplecode}
+% \let\do=\@makeother
+% \dospecials
+% \end{examplecode}
+% @ is treated as letter.
+%
+% A starred version takes one argument, TeX code to be executed inside of the group.
+% It can be used to change catcodes or to define escape characters.
+% \begin{examplecode*}{\ExamplecodeEscapeinside $ $}
+% a long$\\$long line
+% \end{examplecode*}
+%
+% \ExamplecodeEscapeinside takes two arguments
+% characters between which the code is executed normally.
+%
+% \ExamplecodeNoBox
+% disables the tcolorbox
+%
+% \ExamplecodeLinenumbers
+% enables line numbers
+%
+% \\ is redefined to cause a linebreak marked with \ExamplecodePostBreakText.
+
+
+
+\makeatletter
+% ---------- settings ---------
+
+\usepackage{xcolor}
+\usepackage{tcolorbox}
+\tcbuselibrary{breakable,skins}
+\usepackage{latexsym}
+\usepackage{textcomp}
+
+
+% taken from /usr/lib/python3/dist-packages/pygments/styles/default.py
+\definecolor{math}{RGB}{"BA,"21,"21}
+\definecolor{aligntab}{RGB}{"00,"80,"00}
+\definecolor{parameter}{RGB}{"19,"17,"7C}
+\colorlet{superscript}{black}
+\colorlet{subscript}{superscript}
+\colorlet{brace}{aligntab}
+\colorlet{controlsequence}{aligntab}
+\definecolor{comment}{RGB}{"40,"80,"80}
+\definecolor{codebackground}{rgb}{0.9,0.9,1}
+\colorlet{codeborder}{codebackground!50!black}
+\colorlet{codelinkcolor}{white}
+
+\newtcolorbox{examplecodebox}{breakable, skin=enhanced,
+ colback = codebackground,
+ colframe = codeborder,
+ size = fbox, % normal|title|small|fbox|tight|minimal
+ %left = 0pt, right = 0pt,
+ %top = 0pt, bottom = 0pt,
+ %boxrule = 1pt,
+ %arc = 3pt,
+}
+\newcommand{\ExamplecodeNoBox}{%
+ \let\examplecodebox=\par
+ \let\endexamplecodebox=\par
+}
+
+\newcommand{\NewExamplecodeFormatMandatoryArgument}[2]{% #1: control sequence, #2: replacement text where ##1 is the unprocessed argument
+ \expandafter\newcommand\csname @examplecode@formatarg\detokenize{#1}\endcsname[1]{\ExamplecodeProcessBeginGroup{\{}#2\ExamplecodeProcessEndGroup{\}}\ExamplecodeAllowLinebreakBeforeNext\@examplecode@loop}%
+}
+\newcommand{\NewExamplecodeFormatOptionalArgument}[4]{% #1: control sequence, #2: bracket open, #3: bracket close, #4: replacement text where ##1 is the unprocessed argument
+ \expandafter\def\csname @examplecode@formatoptarg\detokenize{#1}#2\endcsname##1#3{\ExamplecodeProcessBracket{#2}#4\ExamplecodeProcessBracket{#3}\ExamplecodeAllowLinebreakBeforeNext\@examplecode@loop}%
+}
+\NewExamplecodeFormatMandatoryArgument\begin{\ExamplecodeProcessEnv{#1}\ExamplecodeSetCmd{#1}}
+\NewExamplecodeFormatMandatoryArgument\end{\ExamplecodeProcessEnv{#1}\ExamplecodeNoCmd}
+\NewExamplecodeFormatMandatoryArgument\usepackage{\ExamplecodeProcessPkg{#1}\ExamplecodeNoCmd}
+\NewExamplecodeFormatMandatoryArgument{object}{\ExamplecodeParseKeys{/object}#1\ExamplecodeEndParseKeys\ExamplecodeNoCmd}
+\NewExamplecodeFormatMandatoryArgument{tableobject}{\ExamplecodeParseKeys{/object}#1\ExamplecodeEndParseKeys\ExamplecodeNoCmd}
+\NewExamplecodeFormatMandatoryArgument{figureobject}{\ExamplecodeParseKeys{/object}#1\ExamplecodeEndParseKeys\ExamplecodeNoCmd}
+\NewExamplecodeFormatMandatoryArgument{subobject}{\ExamplecodeParseKeys{/object}#1\ExamplecodeEndParseKeys\ExamplecodeNoCmd}
+\NewExamplecodeFormatMandatoryArgument\objectset{\ExamplecodeParseKeys{/object}#1\ExamplecodeEndParseKeys\ExamplecodeNoCmd}
+\NewExamplecodeFormatOptionalArgument\includegraphicobject[]{\ExamplecodeParseKeys{}#1\ExamplecodeEndParseKeys\ExamplecodeNoCmd}
+\NewExamplecodeFormatOptionalArgument\includegraphicsubobject[]{\ExamplecodeParseKeys{}#1\ExamplecodeEndParseKeys\ExamplecodeNoCmd}
+\NewExamplecodeFormatMandatoryArgument\NewObjectStyle{\ExamplecodeParse\relax\relax\ExamplecodeEndParseKeys#1\ExamplecodeEndParseKeys\ExamplecodeSetCmd{\NewObjectStyle2}}
+\NewExamplecodeFormatMandatoryArgument{\NewObjectStyle2}{\ExamplecodeParseKeys{/object}#1\ExamplecodeEndParseKeys\ExamplecodeNoCmd}
+
+% custom styles defined in example
+\NewExamplecodeFormatMandatoryArgument{tikzobject}{\ExamplecodeParseKeys{/object}#1\ExamplecodeEndParseKeys\ExamplecodeNoCmd}
+\NewExamplecodeFormatMandatoryArgument{tikz3dobject}{\ExamplecodeParseKeys{/object}#1\ExamplecodeEndParseKeys\ExamplecodeNoCmd}
+
+\newcommand{\ExamplecodeFormatMeta}[1]{{\normalfont\meta{#1}}}
+
+\newcommand{\ExamplecodePrint}[1]{#1}
+
+\newcommand{\ExamplecodePostBreakSymbol}{\footnotesize$\hookrightarrow$\quad}
+\newcommand{\ExamplecodeIndentation}{}% don't change this, it is overwritten later to always contain the indentation of the current line
+\newcommand{\ExamplecodePostBreakText}{\hbox{\ExamplecodeIndentation\ExamplecodePostBreakSymbol}}
+\newcommand{\ExamplecodeAllowLinebreak}{\discretionary{}{\ExamplecodePostBreakText}{}}
+\newcommand{\ExamplecodeAllowLinebreakBeforeNext}{\@examplecode@allowlinebreakbeforenexttrue}
+\newcommand{\ExamplecodeLinebreak}{\newline\ExamplecodePostBreakText}
+
+\newcommand{\ExamplecodeFormatCmd}[1]{{\leavevmode\color{controlsequence}\LinkUnformattedKeyword{cs}{\detokenize{#1}}{\string#1}}\ExamplecodeAllowLinebreakBeforeNext} % catcode 0/16
+\newcommand{\ExamplecodeFormatEnv}[1]{\LinkUnformattedKeyword{env}{#1}{#1}}
+\newcommand{\ExamplecodeFormatPkg}[1]{\LinkUnformattedKeyword{pkg}{#1}{#1}}
+
+\newcommand{\ExamplecodeFormatBeginGroup}[1]{\textcolor{brace}{#1}} % catcode 1
+\newcommand{\ExamplecodeFormatEndGroup}[1]{\textcolor{brace}{#1}\ExamplecodeAllowLinebreakBeforeNext} % catcode 2
+\newcommand{\ExamplecodeFormatMathShift}[1]{\textup{#1}} % catcode 3, see \ExamplecodeFormatMath
+\newcommand{\ExamplecodeFormatAlignmentTab}[1]{\textcolor{aligntab}{#1}} % catcode 4
+% catcode 5: \ExamplecodeEndOfLine
+\newcommand{\ExamplecodeFormatParameter}[1]{\textcolor{parameter}{#1}} % catcode 6
+\newcommand{\ExamplecodeFormatSuperscript}[1]{\textcolor{superscript}{#1}} % catcode 7
+\newcommand{\ExamplecodeFormatSubscript}[1]{\textcolor{subscript}{#1}} % catcode 8
+% catcode 9: ignored
+% catcode 10: \ExamplecodeSpace, \ExamplecodeTab
+\newcommand{\ExamplecodeFormatText}[1]{%
+ \ifx`#1%
+ \textasciigrave
+ \else\ifx'#1%
+ \textquotesingle
+ \else
+ #1%
+ \fi\fi
+} % catcode 11, 12
+\newcommand{\ExamplecodeFormatBracket}[1]{#1} % catcode 11
+% catcode 13: active (uses \ExamplecodeFormatCmd, too)
+
+% in contrast to the other format macros this does
+% *not* take an argument. Instead it applies the
+% format for the rest of the group.
+\newcommand{\ExamplecodeFormatComment}{%
+ \leavevmode
+ \color{comment}%
+ \itshape
+ \let\color=\@gobble
+} % catcode 14
+\newcommand{\ExamplecodeFormatMath}{%
+ \leavevmode
+ \color{math}%
+ \itshape
+ \let\color=\@gobble
+ \ExamplecodeForbidLinebreaks
+}
+\newcommand{\ExamplecodeForbidLinebreaks}{%
+ \let\discretionary=\@thirdofthree
+} % catcode 3
+
+% catcode 15: invalid
+
+\newcommand{\ExamplecodeSpaceSymbol}{\space}
+\newcommand{\ExamplecodeTabSymbol}{\qquad}
+\newcommand{\ExamplecodeIndentationSpace}{\EnsureHMode\nobreak\space}
+\newcommand{\ExamplecodeIndentationTab}{\EnsureHMode\nobreak\qquad}
+\newcommand{\ExamplecodeNormalSpace}{\discretionary{}{\ExamplecodePostBreakText}{\hbox{\ExamplecodeSpaceSymbol}}}
+\newcommand{\ExamplecodeNormalTab}{\discretionary{}{\ExamplecodePostBreakText}{\hbox{\ExamplecodeTabSymbol}}}
+\newcommand{\ExamplecodeEndOfLine}{\EnsureHMode\par}
+
+
+\newcommand{\ExamplecodeTabsize}{4}
+
+
+\newcommand{\ExamplecodeAllowLinebreakAfter}[1]{\expandafter\def\csname @examplecode@breakafter@#1\endcsname{\ExamplecodeAllowLinebreakBeforeNext}}
+\ExamplecodeAllowLinebreakAfter]
+
+
+% ---------- process ---------
+
+\newif\ifExamplecodeInAlign
+
+\newcommand{\ExamplecodeProcessCmd}[1]{\ExamplecodePrint{\ExamplecodeFormatCmd{#1}}} % catcode 0/16
+\newcommand{\ExamplecodeProcessEnv}[1]{\ExamplecodePrint{\ExamplecodeFormatEnv{#1}}}
+\newcommand{\ExamplecodeProcessPkg}[1]{\ExamplecodePrint{\ExamplecodeFormatPkg{#1}}}
+\newcommand{\ExamplecodeProcessBeginGroup}[1]{\ExamplecodePrint{\ExamplecodeFormatBeginGroup{#1}}} % catcode 1
+\newcommand{\ExamplecodeProcessEndGroup}[1]{\ExamplecodePrint{\ExamplecodeFormatEndGroup{#1}}} % catcode 2
+\newcommand{\ExamplecodeProcessMathShift}[1]{\ExamplecodePrint{\ExamplecodeFormatMathShift{#1}}} % catcode 3
+\newcommand{\ExamplecodeProcessBeginMath}{\ExamplecodePrint{\begingroup\ExamplecodeFormatMath}} % catcode 3
+\newcommand{\ExamplecodeProcessEndMath}{\ExamplecodePrint{\endgroup}}
+\newcommand{\ExamplecodeProcessAlignmentTab}[1]{\ExamplecodePrint{%
+ \ifExamplecodeInAlign
+ \endgroup
+ \fi
+ \ExamplecodeAllowLinebreak
+ \begingroup
+ \ExamplecodeInAligntrue
+ \ExamplecodeForbidLinebreaks
+ \ExamplecodeFormatAlignmentTab{#1}%
+}} % catcode 4
+\newcommand{\ExamplecodeProcessEndOfLine}{\ExamplecodePrint{%
+ \ifExamplecodeInAlign
+ \endgroup
+ \fi
+ \ExamplecodeEndOfLine
+}} % catcode 5
+\newcommand{\ExamplecodeProcessParameter}[1]{\ExamplecodePrint{\ExamplecodeFormatParameter{#1}}} % catcode 6
+\newcommand{\ExamplecodeProcessSuperscript}[1]{\ExamplecodePrint{\ExamplecodeFormatSuperscript{#1}}} % catcode 7
+\newcommand{\ExamplecodeProcessSubscript}[1]{\ExamplecodePrint{\ExamplecodeFormatSubscript{#1}}} % catcode 8
+% catcode 9: ignored
+\newcommand{\ExamplecodeProcessSpace}{\ExamplecodePrint{\ExamplecodeSpace}\ExamplecodeAppendIndentation{\ExamplecodeSpace}} % catcode 10
+\newcommand{\ExamplecodeProcessTab}{\ExamplecodePrint{\ExamplecodeTab}\ExamplecodeAppendIndentation{\ExamplecodeTab}} % catcode 10
+\newcommand{\ExamplecodeProcessText}[1]{\ExamplecodePrint{\ExamplecodeFormatText{#1}}} % catcode 11, 12
+\newcommand{\ExamplecodeProcessBracket}[1]{\ExamplecodePrint{\ExamplecodeFormatBracket{#1}}} % catcode 11
+% catcode 13: active (uses \ExamplecodeProcessCmd, too)
+\newcommand{\ExamplecodeProcessBeginComment}{\ExamplecodePrint{\begingroup\ExamplecodeFormatComment}} % catcode 14
+\newcommand{\ExamplecodeProcessEndComment}{\ExamplecodePrint{\endgroup}}
+% catcode 15: invalid
+
+\newcommand{\ExamplecodeProcessCleanup}{\ExamplecodePrint{%
+ \ifExamplecodeInAlign
+ \endgroup
+ \fi
+}}
+
+\newcommand{\ExamplecodeProcessMeta}[1]{\ExamplecodePrint{\ExamplecodeFormatMeta{#1}}}
+
+
+% ---------- key=value options ---------
+
+\newcommand{\ExamplecodeParseKeys}[1]{% #1: key path
+ \ExamplecodeParse
+ {\@examplecode@prepare@parsekeys{#1}}%
+ {\@examplecode@cleanup@parsekeys}%
+ \ExamplecodeEndParseKeys
+}
+\newcommand{\@examplecode@prepare@parsekeys}[1]{% #1: key path
+ \let\@examplecode@print@original=\ExamplecodePrint
+ \ExamplecodeNoCmd
+ \def\@examplecode@key@cmd{\key@withopt@unformatted}%
+ \def\@examplecode@keypath{#1}%
+ \let\@examplecode@pathsep=\@empty
+ \def\ExamplecodeProcessText##1{% ##1: current token
+ \ifx,##1%
+ \ifExamplecodeInAlign
+ \endgroup
+ \fi
+ \@examplecode@endkey
+ \let\@examplecode@beginkey=\@examplecode@beginkey@bak
+ \@examplecode@print@original{\ExamplecodeFormatText{##1}}%
+ \else\ifx=##1%
+ \@examplecode@endkey
+ \let\@examplecode@beginkey=\relax
+ \@examplecode@print@original{\ExamplecodeFormatText{##1}}%
+ \else\ifx/##1%
+ \@examplecode@beginkey
+ \@examplecode@appendpathsep{##1}%
+ \else\ifx.##1%
+ \unless \ifx \@examplecode@pathsep \@empty
+ \@examplecode@endkey
+ \expandafter\@examplecode@print@original\expandafter{\expandafter\ExamplecodeFormatText\expandafter{\@examplecode@pathsep}}%
+ \fi
+ \@examplecode@beginkey
+ \ifx \@examplecode@key \@empty
+ \def\@examplecode@key@cmd[####1]####2{\LinkUnformattedKeyword{handler}{####2}{####2}}%
+ \fi
+ \@examplecode@appendkey{##1}%
+ \else
+ \@examplecode@beginkey
+ \@examplecode@appendkey{##1}%
+ \fi \fi \fi \fi
+ }%
+ \def\@examplecode@appendkey##1{%
+ \ExamplecodePrint{\ExamplecodeFormatText{##1}}%
+ }%
+ \def\@examplecode@appendpathsep##1{%
+ \ExamplecodePrint{\ExamplecodeFormatText{##1}}%
+ }%
+ \def\ExamplecodeProcessBeginComment{%
+ \@examplecode@endkey
+ \begingroup
+ \let\@examplecode@beginkey=\relax
+ \let\@examplecode@beginkey@bak=\relax
+ \@examplecode@print@original{\begingroup\ExamplecodeFormatComment}%
+ \let\ExamplecodePrint=\@examplecode@print@original
+ }%
+ \def\ExamplecodeProcessEndComment{%
+ \@examplecode@print@original{\endgroup}%
+ \endgroup
+ }%
+ \def\ExamplecodeProcessBeginGroup##1{%
+ \begingroup
+ \let\@examplecode@beginkey=\relax
+ \let\@examplecode@beginkey@bak=\relax
+ \ExamplecodePrint{\ExamplecodeFormatBeginGroup{##1}}%
+ }%
+ \def\ExamplecodeProcessEndGroup##1{%
+ \ExamplecodePrint{\ExamplecodeFormatEndGroup{##1}}%
+ \endgroup
+ }%
+}
+\newcommand{\@examplecode@cleanup@parsekeys}{%
+ \@examplecode@endkey
+ \ExamplecodeProcessCleanup
+}
+\newcommand{\@examplecode@beginkey}{%
+ \begingroup
+ \def\@examplecode@key{}%
+ \let\@examplecode@keyspace=\@empty
+ \def\@examplecode@appendkey##1{%
+ \unless \ifx \@examplecode@keyspace \@empty
+ \appto\@examplecode@key{ }%
+ \let\@examplecode@keyspace=\@empty
+ \fi
+ \@examplecode@applypathsep
+ \appto\@examplecode@key{##1}%
+ }%
+ \def\@examplecode@appendpathsep##1{%
+ \unless \ifx \@examplecode@keyspace \@empty
+ \appto\@examplecode@key{ }%
+ \let\@examplecode@keyspace=\@empty
+ \fi
+ \appto\@examplecode@pathsep{##1}%
+ }%
+ \def\@examplecode@applypathsep{%
+ \unless \ifx \@examplecode@pathsep \@empty
+ \eappto\@examplecode@key{\@examplecode@pathsep}%
+ \let\@examplecode@pathsep=\@empty
+ \fi
+ }%
+ \def\ExamplecodePrint##1{%
+ \@examplecode@endkey
+ \@examplecode@print@original{##1}%
+ }%
+ \def\ExamplecodeProcessSpace{%
+ \@examplecode@applypathsep
+ \appto\@examplecode@keyspace{\ExamplecodeSpace}%
+ }%
+ \let\@examplecode@beginkey=\relax
+ \def\@examplecode@endkey{%
+ \edef\@examplecode@do{\noexpand\@examplecode@print@original{%
+ \expandafter\noexpand\@examplecode@key@cmd[\@examplecode@keypath]{\@examplecode@key}%
+ \expandonce{\@examplecode@pathsep}%
+ \expandonce{\@examplecode@keyspace}%
+ }}%
+ \@examplecode@do
+ \endgroup
+ }%
+}
+\let\@examplecode@beginkey@bak=\@examplecode@beginkey
+\newcommand{\@examplecode@endkey}{}
+
+\newcommand{\ExamplecodeEndParseKeys}{\PackageError{examplecode}{This should never be expanded}{}}
+
+
+% ---------- parsing command ---------
+
+\newcommand{\ExamplecodeParse}[3]{% #1: prepare, #2: cleanup, #3: end token
+ \begingroup
+ #1%
+ \let\@examplecode@endtoken=#3%
+ \def\@examplecode@checkend##1{#2\@examplecode@beforeline\endgroup}%
+ \@examplecode@loop
+}
+
+% WARNING: reads end token before changing catcodes
+% compares end token with \ifx in case it is a control sequence
+% => does not find end token if it's catcode is changed
+% => \xc`...` does not work directly but inside of macro
+\newcommand{\@xc@prepare}{%
+ \def\ExamplecodeNormalSpace{\ExamplecodeSpaceSymbol}%
+ \def\ExamplecodeNormalTab{\ExamplecodeTabSymbol}%
+ \@examplecode@setcatcodes
+ \@examplecode@state@normal
+ \let\ExamplecodeAllowLinebreak=\relax
+ \gdef\@xc@code{}%
+ \def\ExamplecodePrint{\gappto\@xc@code}%
+}%
+\newcommand{\@xc@afterend}{%
+ \formatcode{\@xc@code}%
+}
+\newcommand{\xc}{%
+ \ExamplecodeParse{%
+ \@xc@prepare
+ }{%
+ \ExamplecodeProcessCleanup
+ \@xc@afterend
+ }%
+}
+\newcommand{\xckey}{%
+ \ExamplecodeParse{%
+ \@xc@prepare
+ \@examplecode@prepare@parsekeys{}%
+ }{%
+ \@examplecode@cleanup@parsekeys
+ \@xc@afterend
+ }%
+}
+
+
+% ---------- escape inside ---------
+
+\newcommand{\ExamplecodeEscapeinside}[2]{% #1: begin token, #2: end token
+ \def\@examplecode@escapeinside#1##1#2{##1\@examplecode@loop}%
+ \let\@examplecode@escapeinside@startchar=#1%
+}
+
+
+% ---------- line numbers ---------
+
+\newcounter{ExamplecodeLinecounter}
+\newcommand{\ExamplecodeLinenumbers}{%
+ \setcounter{ExamplecodeLinecounter}{1}%
+ \let\@examplecode@beforeline@hook=\@examplecode@insertlinenumber
+}
+\newcommand\@examplecode@insertlinenumber{%
+ \makebox[0pt][r]{{\ExamplecodeFormatLinenumber{\theExamplecodeLinecounter}}\quad}%
+ \stepcounter{ExamplecodeLinecounter}%
+}
+\newcommand\ExamplecodeFormatLinenumber[1]{%
+ \normalfont
+ \footnotesize
+ #1%
+}
+
+
+% ---------- parsing environment ---------
+
+\newenvironment{examplecode}{%
+ \csname examplecode*\endcsname{}%
+}{%
+ \csname endexamplecode*\endcsname{}%
+}
+\newenvironment{examplecode*}[1]{%
+ \let\@examplecode@envname=\@currenvir
+ \@examplecode@setcatcodes
+ \let\@examplecode@endtoken=\end
+ #1%
+ \begin{examplecodebox}%
+ \colorlet{linkcolor}{codelinkcolor}%
+ \raggedright
+ \ttfamily
+ \leavevmode
+ \parskip=0pt
+ \parindent=0pt\relax
+ \let\\=\ExamplecodeLinebreak
+ \@examplecode@state@firstindent
+ \@examplecode@gobblefirsteol
+}{%
+ \end{examplecodebox}%
+}
+
+\newenvironment{examplecodekey}{%
+ \csname examplecodekey*\endcsname{}%
+}{%
+ \csname endexamplecodekey*\endcsname{}%
+}
+\newenvironment{examplecodekey*}[1]{%
+ \csname examplecode*\endcsname{%
+ \@examplecode@prepare@parsekeys{}%
+ #1%
+ }%
+}{%
+ \@examplecode@cleanup@parsekeys
+ \csname endexamplecode*\endcsname
+}
+
+
+\newcommand{\@examplecode@setcatcodes}{%
+ \@makeother\^^M% end of line
+ \@makeother\^^I% tab
+ \@makeother\ % space
+ \@makeother\%%
+ \makeatletter
+ % changed
+ \@makeother*%
+ \@makeother`%
+}
+\begingroup
+\@makeother\^^M %
+\@makeother\^^I %
+\@firstofone{%
+\endgroup%
+\let\EolOther=^^M%
+\let\TabOther=^^I%
+}
+\begingroup\@makeother\%\@firstofone{\endgroup\let\PercentOther=%}
+
+\newcommand{\@examplecode@error@catcodes@indentation}{\PackageError{examplecode}{failed to change catcodes, indentation will be screwed up}{}}
+\newcommand{\@examplecode@error@mixedtabsandspaces}{\PackageWarning{examplecode}{mixed use of tabs and spaces}}
+
+\newcount\@examplecode@count@outerindent
+\newcount\@examplecode@count@gobbledindent
+\newif\if@examplecode@allowlinebreakbeforenext
+
+\newcommand{\EnsureHMode}{\leavevmode\@examplecode@beforeline\let\EnsureHMode\relax}%
+\let\@EnsureHMode@bak=\EnsureHMode
+
+
+\newcommand{\@examplecode@beforeline}{%
+ \@examplecode@beforeline@hook
+ \let\@examplecode@beforeline=\relax
+}
+\let\@examplecode@beforeline@bak=\@examplecode@beforeline
+\let\@examplecode@beforeline@hook=\relax
+
+\newcommand{\@examplecode@state@firstindent}{%
+ \@examplecode@beforeline
+ \let\@examplecode@check@spaces=\@examplecode@check@firstindent
+}
+\newcommand{\@examplecode@state@gobbleindent}{%
+ \let\@examplecode@beforeline=\@examplecode@beforeline@bak
+ \let\@examplecode@state@normal=\@examplecode@state@normal@bak
+ \ifnum \@examplecode@count@outerindent > 0
+ \@examplecode@count@gobbledindent=0
+ \let\@examplecode@check@spaces=\@examplecode@check@gobbleindent
+ \else
+ \@examplecode@state@indent
+ \fi
+ \let\EnsureHMode=\@EnsureHMode@bak
+}
+\newcommand{\@examplecode@state@indent}{%
+ \let\@examplecode@check@spaces=\@examplecode@check@normalspaces
+ \let\ExamplecodeSpace=\ExamplecodeIndentationSpace
+ \let\ExamplecodeTab=\ExamplecodeIndentationTab
+ \def\ExamplecodeAppendIndentation##1{\eappto\ExamplecodeIndentation{\expandonce{##1}}}%
+ \let\ExamplecodeIndentation=\@empty
+}
+\newcommand{\@examplecode@state@normal}{%
+ \@examplecode@beforeline
+ \let\@examplecode@check@spaces=\@examplecode@check@normalspaces
+ \let\ExamplecodeSpace=\ExamplecodeNormalSpace
+ \let\ExamplecodeTab=\ExamplecodeNormalTab
+ \let\@examplecode@state@normal=\relax
+ \let\ExamplecodeAppendIndentation=\@gobble
+}
+\let\@examplecode@state@normal@bak=\@examplecode@state@normal
+
+
+\newcommand{\@examplecode@gobblefirsteol}[1]{%
+ \ifx \EolOther #1\relax
+ \else
+ \PackageError{examplecode}{unexpected code on same line after \string\begin{examplecode}}{}%
+ \detokenize{#1}%
+ \fi
+ \@examplecode@loop
+}
+
+\newcommand{\@examplecode@loop}{%
+ \futurelet \@examplecode@nexttoken \@examplecode@check
+}
+\newcommand{\@examplecode@check}{%
+ \ifx \@examplecode@nexttoken \@examplecode@endtoken
+ \expandafter \@examplecode@checkend
+ \else
+ \if@examplecode@allowlinebreakbeforenext
+ \ExamplecodeAllowLinebreak
+ \@examplecode@allowlinebreakbeforenextfalse
+ \fi
+ \expandafter \@examplecode@check@ii
+ \fi
+}
+
+\newcommand{\@examplecode@check@ii}{%
+ \ifcat \noexpand\@examplecode@nexttoken \relax
+ \def\@examplecode@do{\@examplecode@handle@cs}%
+ \else
+ \def\@examplecode@do{\@examplecode@check@spaces}%
+ \fi
+ \@examplecode@do
+}
+\newcommand{\@examplecode@handle@cs}[1]{%
+ \ExamplecodeSetCmd{#1}%
+ \@examplecode@state@normal
+ \ExamplecodeProcessCmd{#1}%
+ \@examplecode@loop
+}
+\newcommand{\ExamplecodeSetCmd}[1]{\edef\@examplecode@cs{\detokenize{#1}}}
+\newcommand{\ExamplecodeNoCmd}{\def\@examplecode@cs{}}
+\ExamplecodeNoCmd
+
+\newcommand{\@examplecode@check@normalspaces}{%
+ \ifcat \noexpand\@examplecode@nexttoken \space
+ \def\@examplecode@do##1{\ExamplecodeProcessSpace\@examplecode@loop##1}%
+ \else\if \noexpand\@examplecode@nexttoken \space
+ \def\@examplecode@do##1{\ExamplecodeProcessSpace\@examplecode@loop}%
+ \else\ifx \@examplecode@nexttoken \TabOther
+ \def\@examplecode@do##1{\ExamplecodeProcessTab\@examplecode@loop}%
+ \else
+ \def\@examplecode@do{\@examplecode@check@iv}%
+ \fi \fi \fi
+ \@examplecode@do
+}
+% count the indentation of the first line
+\newcommand{\@examplecode@check@firstindent}{%
+ \ifcat \noexpand\@examplecode@nexttoken \space
+ \@examplecode@error@catcodes@indentation
+ \advance\@examplecode@count@outerindent by 1
+ \def\@examplecode@do##1{\@examplecode@loop##1}%
+ \else\if \noexpand\@examplecode@nexttoken \space
+ \advance\@examplecode@count@outerindent by 1
+ \def\@examplecode@do##1{\@examplecode@loop}%
+ \else\ifx \@examplecode@nexttoken \TabOther
+ \advance\@examplecode@count@outerindent by \ExamplecodeTabsize
+ \def\@examplecode@do##1{\@examplecode@loop}%
+ \else
+ \def\@examplecode@do{\@examplecode@check@iv}%
+ \fi \fi \fi
+ \@examplecode@do
+}
+% gobble indentation as far as the first line was indented
+\newcommand{\@examplecode@check@gobbleindent}{%
+ \ifcat \noexpand\@examplecode@nexttoken \space
+ \@examplecode@error@catcodes@indentation
+ \@examplecode@gobbleindent{1}%
+ \def\@examplecode@do##1{\@examplecode@loop##1}%
+ \else\if \noexpand\@examplecode@nexttoken \space
+ \@examplecode@gobbleindent{1}%
+ \def\@examplecode@do##1{\@examplecode@loop}%
+ \else\ifx \@examplecode@nexttoken \TabOther
+ \@examplecode@gobbleindent{\ExamplecodeTabsize}%
+ \def\@examplecode@do##1{\@examplecode@loop}%
+ \else
+ \def\@examplecode@do{\@examplecode@check@iv}%
+ \fi \fi \fi
+ \@examplecode@do
+}
+\newcommand{\@examplecode@gobbleindent}[1]{%
+ \advance\@examplecode@count@gobbledindent by #1
+ \ifnum \@examplecode@count@gobbledindent = \@examplecode@count@outerindent
+ \@examplecode@state@indent
+ \else\ifnum \@examplecode@count@gobbledindent > \@examplecode@count@outerindent
+ \@examplecode@error@mixedtabsandspaces
+ \@examplecode@state@indent
+ \fi \fi
+}
+\newcommand{\@examplecode@check@iv}{%
+ \def\@examplecode@do{\@examplecode@check@v}%
+ \unless\ifx \@examplecode@escapeinside@startchar \relax
+ \if \noexpand\@examplecode@nexttoken \noexpand\@examplecode@escapeinside@startchar
+ \def\@examplecode@do{\@examplecode@escapeinside}%
+ \fi
+ \fi
+ \@examplecode@do
+}
+\newcommand{\@examplecode@check@v}{%
+ \ifcat \noexpand\@examplecode@nexttoken \bgroup% catcode 1
+ \def\@examplecode@do{\@examplecode@handlebgroup}%
+ \else\ifcat \noexpand\@examplecode@nexttoken \egroup% catcode 2
+ \def\@examplecode@do{\expandafter\@examplecode@handlespecialtoken\expandafter\ExamplecodeProcessEndGroup\string}%
+ \else\ifcat \noexpand\@examplecode@nexttoken $% catcode 3
+ \def\@examplecode@do{\@examplecode@handlemathshift}%
+ \else\ifcat \noexpand\@examplecode@nexttoken &% catcode 4
+ \def\@examplecode@do{\@examplecode@handlespecialtoken\ExamplecodeProcessAlignmentTab}%
+ \else\ifx \@examplecode@nexttoken \EolOther% catcode 5
+ \@examplecode@endcomment
+ \def\@examplecode@do##1{%
+ \ExamplecodeProcessEndOfLine
+ \@examplecode@state@gobbleindent
+ \@examplecode@loop
+ }%
+ \else\ifcat \noexpand\@examplecode@nexttoken ##% catcode 6
+ \def\@examplecode@do{\@examplecode@handleparameter}%
+ \else\ifcat \noexpand\@examplecode@nexttoken ^% catcode 7
+ \def\@examplecode@do{\@examplecode@handlespecialtoken\ExamplecodeProcessSuperscript}%
+ \else\ifcat \noexpand\@examplecode@nexttoken _% catcode 8
+ \def\@examplecode@do{\@examplecode@handlespecialtoken\ExamplecodeProcessSubscript}%
+ % catcode 9: ignored characters
+ % catcode 10: space, handled in \@examplecode@check@spaces
+ % catcode 11: letter, handled in \else
+ % catcode 12: other, handled in \else
+ \else\ifx \@examplecode@nexttoken <%
+ \def\@examplecode@do{\@examplecode@handlepossiblemeta}%
+ % catcode 13: active, handled in \@examplecode@check@ii (after \futurelet it's indistinguishable from a control sequence)
+ \else\ifx \@examplecode@nexttoken \PercentOther% catcode 14
+ \@examplecode@state@normal
+ \ExamplecodeProcessBeginComment
+ \def\@examplecode@endcomment{\ExamplecodeProcessEndComment}%
+ \def\@examplecode@do{\@examplecode@handlenormaltoken}%
+ % catcode 15: invalid characters
+ \else% catcode 11, 12
+ \def\@examplecode@do{\@examplecode@handlenormaltoken}%
+ \fi \fi \fi \fi \fi \fi \fi \fi \fi \fi
+ \@examplecode@do
+}
+\newcommand{\@examplecode@endcomment}{}
+\newcommand{\@examplecode@handlebgroup}{%
+ \ifcsundef{@examplecode@formatarg\@examplecode@cs}{%
+ \expandafter\@examplecode@handlespecialtoken\expandafter\ExamplecodeProcessBeginGroup\string
+ }{%
+ \csname @examplecode@formatarg\@examplecode@cs\endcsname
+ }%
+}
+\newcommand{\@examplecode@handlenormaltoken}[1]{%
+ \@examplecode@state@normal
+ \ifcsundef{@examplecode@formatoptarg\@examplecode@cs#1}{%
+ \csname @examplecode@breakafter@#1\endcsname
+ \ExamplecodeProcessText{#1}%
+ \@examplecode@loop
+ }{%
+ \csname @examplecode@formatoptarg\@examplecode@cs#1\endcsname
+ }%
+}
+\newcommand{\@examplecode@handlespecialtoken}[2]{%
+ \@examplecode@state@normal
+ #1{\string#2}%
+ \@examplecode@loop
+}
+
+\newcommand{\@examplecode@handlemathshift}[1]{%
+ \@examplecode@math@begin
+ \ExamplecodeProcessMathShift{\string#1}%
+ \@examplecode@math@end
+ \@examplecode@loop
+}
+\newcommand{\@examplecode@math@begin}{%
+ \@examplecode@state@normal
+ \begingroup
+ \let\@examplecode@handlemeta=\@examplecode@handlenormaltoken
+ \ExamplecodeProcessBeginMath
+ \let\@examplecode@math@begin=\relax
+ \def\@examplecode@math@end{\def\@examplecode@math@end{\ExamplecodeProcessEndMath\endgroup}}%
+}
+
+\newcommand{\@examplecode@handleparameter}[1]{%
+ \edef\@examplecode@parameter{\string#1}%
+ \@examplecode@parameterloop
+}
+\newcommand{\@examplecode@parameterloop}{%
+ \futurelet \@examplecode@nexttoken \@examplecode@parametercheck
+}
+\newcommand{\@examplecode@parametercheck}{%
+ \ifcat \noexpand\@examplecode@nexttoken ##%
+ \def\@examplecode@do##1{%
+ \edef\@examplecode@parameter{\@examplecode@parameter\string##1}%
+ \@examplecode@parameterloop
+ }%
+ \else\ifcat \noexpand\@examplecode@nexttoken 1%
+ \def\@examplecode@do##1{%
+ \edef\@examplecode@parameter{\@examplecode@parameter##1}%
+ \expandafter\ExamplecodeProcessParameter\expandafter{\@examplecode@parameter}%
+ \@examplecode@loop
+ }%
+ \else
+ \def\@examplecode@do{%
+ \expandafter\ExamplecodeProcessParameter\expandafter{\@examplecode@parameter}%
+ \@examplecode@check
+ }%
+ \fi \fi
+ \@examplecode@do
+}
+
+\newcommand{\@examplecode@handlepossiblemeta}[1]{%
+ \def\@examplecode@tmp{#1}%
+ \futurelet \@examplecode@nexttoken \@examplecode@checkmeta
+}
+\newcommand{\@examplecode@checkmeta}{%
+ \ifcat \@examplecode@nexttoken a%
+ \def\@examplecode@do{\@examplecode@handlemeta}%
+ \else
+ \def\@examplecode@do{\@examplecode@handlenormaltoken}%
+ \fi
+ \expandafter\@examplecode@do\@examplecode@tmp
+}
+\def\@examplecode@handlemeta<#1>{%
+ \ExamplecodeProcessMeta{#1}%
+ \@examplecode@loop
+}
+
+\newcommand{\@examplecode@checkend}[2]{%
+ \def\@examplecode@arg{#2}%
+ \ifx \@examplecode@arg \@examplecode@envname
+ \expandafter \@firstoftwo
+ \else
+ \expandafter \@secondoftwo
+ \fi{%
+ \end{#2}%
+ }{%
+ \@examplecode@state@normal
+ \ExamplecodeProcessCmd{#1}%
+ \ExamplecodeProcessBeginGroup{\{}%
+ \ExamplecodeProcessEnv{#2}%
+ \ExamplecodeProcessEndGroup{\}}%
+ \@examplecode@loop
+ }%
+}%
+\makeatother
diff --git a/macros/latex/contrib/easyfloats/doc/preamble/keydoc.tex b/macros/latex/contrib/easyfloats/doc/preamble/keydoc.tex
new file mode 100644
index 0000000000..3116266bef
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/doc/preamble/keydoc.tex
@@ -0,0 +1,754 @@
+% !TeX root = ../easyfloats.tex
+
+% Copyright © 2020 E. Zöllner
+% Alternatively to the terms of the LPPL, at your choice,
+% you can redistribute and/or modify this file under the
+% terms of the Do What The Fuck You Want To Public License, Version 2,
+% as published by Sam Hocevar. See http://www.wtfpl.net/about/.
+
+\usepackage{etoolbox}
+\usepackage{pgfkeys}
+
+% Defines a macro to document a macro or environment key:
+% \keydoc{<keyname> = <allowedvalues>}{<keytype>}
+% \keydoc[<options>]{<keyname> = <allowedvalues>}{<keytype>}
+% Following text is assumed to be a description of the key.
+% If it is instead followed by another \keydoc it is assumed
+% that this key has no description.
+% If a description applies to two keys separate the \keydocs
+% by a slash.
+% Do *not* put an empty line between a \keydoc and it's description.
+% Spaces after (the second argument of) \keydoc are ignored.
+% <options> is a comma separated list of the following possible key=value pairs:
+% - target = the full key to another key.
+% The name of this key is made into a link to target.
+% This is used by \forwardingkeydoc.
+% - initial value
+% - default value
+% Values are separated by pipes.
+% Wildcards are put in angular brackets.
+%
+% The description of a \keydoc is assumed to reach up to the
+% next \keydoc, \section, \subsection or \subsubsection.
+% If that is not the case you must explicitly end it with
+% \endkeydoc
+% If the description of a \keydoc is ended by a \*section macro
+% there must be a \par (aka an empty line) before that \*section.
+% Otherwise \keydoc@descriptionsep will be inserted.
+%
+% There is a special macro for forwarding keys:
+% \forwardingkeydoc[<options>]{<keyname>}
+% In contrast to \keydoc, the target option can be a path, name or full key.
+% If target is not given it is tried to generate it by expanding
+% \TargetKey{<keypath>}{<keyname>}
+% This macro is given the path (without trailing slash) and name
+% of the key to be described and is expected to expand to a full key.
+% You must define it yourself if you want to leave out the optional argument.
+%
+% \forwardingkeydoc uses internally a more generalized macro:
+% \correspondingkeydoc[<options>]{<keyname>}{<keytype>}
+% target is as flexible as for \forwardingkeydoc
+% but it also takes a <keytype> like \keydoc.
+%
+% Examples for a key pattern can be specified with
+% \keylinktarget{<keyexample>}
+% It must be specified directly following the \keydoc it refers to.
+%
+% \key is redefined to link to \keydoc.
+% However, different environments can have different keys
+% with the same name. In that case a path must be set to
+% distinguish these keys:
+% \keydocpath{<path>}
+% Sets the path for all following \keydoc in the same group.
+% Unambiguous keys can be referenced without a path:
+% \key{sub}
+% For ambiguous keys the path must given as an optional argument:
+% \key[/object]{label}
+% Paths may *not* include a trailing slash.
+%
+% Internals:
+% \begin@keydoc is put before the first \keydoc.
+% \endkeydoc is put after the last description of a \keydoc.
+% \keydoc@beforekey is put before each \keydoc but only once
+% for \keydocs which belong together.
+% \keydoc@keysep is put between \keydocs which belong together.
+% \keydoc@descriptionsep is put between a \keydoc and it's description.
+% If a \keydoc is followed by a \par neither \keydoc@keysep
+% nor \keydoc@descriptionsep is inserted.
+
+
+\makeatletter
+
+% ---------- \keydoc settings ---------
+
+\newcommand{\begin@keydoc}{\begin{itemize}}
+\def \endkeydoc {\end{itemize}}
+
+\newcommand{\keydoc@beforekey}{\item}
+\newcommand{\keydoc@keysep}{~/ }
+\newcommand{\keydoc@descriptionsep}{\nopagebreak\par}
+
+\newcommand{\keydoc@mandatoryvalueformat}[1]{#1}
+\newcommand{\keydoc@optionalvalueformat}{\textcolor{gray}}
+
+\newcommand{\keydoc@keytype}[1]{\,\ensuremath{^{\pgfmanualcslinkpreskip=.33em\pgfmanualcslinkpostskip=\pgfmanualcslinkpreskip\LinkUnformattedKeyword{keytype}{#1}{\keytypesymbol{#1}}}}}
+\newcommand{\keytypedoc@keytype}[1]{\raisebox{.2ex}{\bfseries\keytypesymbol{#1}}}
+
+% ---------- key type symbols ---------
+
+\newcommand{\keytypesymbolformat}[1]{\hbox{\scriptsize(#1)}}
+\newcommand{\newkeytypesymbol}[2]{% #1: key type, #2: symbol
+ \expandafter\newcommand\csname keytypesymbol@#1\endcsname{#2}%
+}
+\newcommand{\keytypesymbol}[1]{% #1: key type
+ \@ifundefined{keytypesymbol@#1}%
+ {\PackageError{keydoc}{undefined keytype `#1'}{}}%
+ {\keytypesymbolformat{\csname keytypesymbol@#1\endcsname}}%
+}
+
+\newkeytypesymbol{storing key}{sto}
+\newkeytypesymbol{executed key}{exe}
+\newkeytypesymbol{boolean key}{bool}
+\newkeytypesymbol{forwarding key}{fwd}
+\newkeytypesymbol{handler}{hdl}
+\newkeytypesymbol{unknown key handler}{unk}
+
+
+% ---------- optional dependencies ---------
+
+\providecommand{\key}[2][]{% #1: key path/group, #2: key name
+ \texttt{#2}%
+}
+
+
+% ---------- auxiliary macros ---------
+
+% \ifendsonspace{<text>}{<then>}{<else>}
+% Checks if the last token of <text> is a space.
+% If it is it expands to <then>{<text-without-last-space>}.
+% If it is not it expands to <else>{<text>}.
+% <text> may not contain \relax.
+\newcommand\ifendsonspace{\ifendson{ }}
+\newcommand\ifendson[2]{%
+ \def\endson@check##1#1\relax.##2\relax\relax##3##4{%
+ \if \relax\detokenize{##2}\relax
+ \def\endson@do{##4}%
+ \endson@stripandappto##1%
+ \else
+ \def\endson@do{##3{##1}}%
+ \fi
+ \endson@do
+ }%
+ \def\endson@stripandappto##1\relax.{\appto\endson@do{{##1}}}%
+ \endson@check#2\relax.#1\relax.\relax\relax
+}
+
+% \newstripoptend{<cs>}{<suffix>}
+% Defines a new control sequence <cs> which checks if it's argument ends on <suffix>.
+% If the argument of <cs> ends on <suffix> it is stripped.
+% If the argument of <cs> does not end on <suffix> <cs> expands to the argument.
+% <cs> is expandable.
+% The number of required expansion steps depends on whether the argument ends on <suffix> or not.
+\newcommand\newstripoptend[2]{% #1: cs, #2: end
+ \expandafter\def\csname\string#1@do\endcsname##1#2\relax.##2\relax\relax{%
+ \if \relax\detokenize{##2}\relax
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \fi
+ {\csname\string#1@strip\endcsname##1}%
+ {##1}%
+ }%
+ \expandafter\def\csname\string#1@strip\endcsname##1\relax.{##1}%
+ \newcommand#1[1]{\csname\string#1@do\endcsname##1\relax.#2\relax.\relax\relax}%
+}
+\newstripoptend\stripoptplus{ (+)}
+
+
+% ---------- \FormatKey ---------
+
+\newcommand{\FormatKey}[1]{%
+ \def\FormatKeyText{}%
+ \FormatKey@lookahead#1\pgfeov
+ \let\FormatKey@original=\FormatKey
+ \let\FormatKey=\@firstofone
+ \KeyFormat@original@key{\FormatKeyText}%
+ \let\FormatKey=\FormatKey@original
+}
+\newcommand{\FormatKey@lookahead}{%
+ \futurelet \FormatKey@nexttoken \FormatKey@check
+}
+\newcommand{\FormatKey@check}{%
+ \ifx \FormatKey@nexttoken (%
+ \def\FormatKey@do{\FormatKey@optional}%
+ \else\ifx \FormatKey@nexttoken <%
+ \def\FormatKey@do{\FormatKey@var}%
+ \else\ifcat \noexpand\FormatKey@nexttoken \space
+ \def\FormatKey@do{\FormatKey@space}%
+ \else\ifx \FormatKey@nexttoken \pgfeov
+ \def\FormatKey@do{\FormatKey@endofloop}%
+ \else\ifx \FormatKey@nexttoken \bgroup
+ \def\FormatKey@do{\FormatKey@arg}%
+ \else
+ \def\FormatKey@do{\FormatKey@normaltoken}%
+ \fi \fi \fi \fi \fi
+ \FormatKey@do
+}
+\def\FormatKey@normaltoken#1{%
+ \appto\FormatKeyText{#1}%
+ \FormatKey@lookahead
+}
+\def\FormatKey@arg#1{%
+ \let\FormatKey@text@backup=\FormatKeyText
+ \def\FormatKeyText{}%
+ \FormatKey@lookahead#1\pgfeov
+ \eappto\FormatKey@text@backup{{\expandonce{\FormatKeyText}}}%
+ \let\FormatKeyText=\FormatKey@text@backup
+ \FormatKey@lookahead
+}
+\def\FormatKey@optional(#1){%
+ \appto\FormatKeyText{{\normalfont\color{gray}(}}%
+ \FormatKey@lookahead#1\pgfeov
+ \appto\FormatKeyText{{\normalfont\color{gray})}}%
+ \FormatKey@lookahead
+}
+\providecommand{\meta@nolink}{\meta}
+\def\FormatKey@var<#1>{%
+ \appto\FormatKeyText{{\normalfont\meta@nolink{#1}}}%
+ \FormatKey@lookahead
+}
+\@firstofone{\def\FormatKey@space} {%
+ \appto\FormatKeyText{ }%
+ \FormatKey@lookahead
+}
+\def\FormatKey@endofloop\pgfeov{%
+}
+
+\providecommand{\pgfeov}{\textcolor{red}{\textbf{eov, this should never be expanded}}}
+
+\let\KeyFormat@original@key=\key
+\renewcommand{\key}{\FormatKey}
+
+
+% ---------- format allowed values ---------
+
+\def\FormatVal@var#1{{\normalfont\meta{#1}}}
+\def\FormatVal@or{\unskip\,\ensuremath{|}\,\ignorespaces}
+
+\newcommand{\FormatValue}[1]{%
+ \def\FormatValue@val{}%
+ \expandafter\FormatValue@loop#1\pgfeov
+ \FormatValue@val
+}
+\newcommand{\FormatValue@loop}{%
+ \futurelet \FormatValue@nexttoken \FormatValue@check
+}
+\newcommand{\FormatValue@check}{%
+ \ifx \FormatValue@nexttoken \pgfeov
+ \def\FormatValue@do##1{}%
+ \else\ifcat \noexpand\FormatValue@nexttoken \space
+ \appto\FormatValue@val{ }%
+ \def\FormatValue@do##1{\FormatValue@loop##1}%
+ \else
+ \def\FormatValue@do{\FormatValue@check@ii}%
+ \fi \fi
+ \FormatValue@do
+}
+\newcommand{\FormatValue@check@ii}[1]{%
+ \if|\noexpand#1%
+ \appto\FormatValue@val{\FormatVal@or}%
+ \def\FormatValue@do{\FormatValue@loop}%
+ \else\if<\noexpand#1%
+ \def\FormatValue@do##1>{\appto\FormatValue@val{\FormatVal@var{##1}}\FormatValue@loop}%
+ \else
+ \appto\FormatValue@val{#1}%
+ \def\FormatValue@do{\FormatValue@loop}%
+ \fi \fi
+ \FormatValue@do
+}
+
+
+% ---------- keyword ---------
+% This is a generalized api to link certain keywords.
+% Use the following macro in a description:
+% \NewKeyword[\unexpanded]{<keywordtype>}{<keyword>}{<formatmacro-bg>}{<formatmacro-fg>}{<text>}
+% Use the following macro in references:
+% \LinkKeyword{<keywordtype>}{<keyword>}<formatmacro-bg><formatmacro-fg>{<text>}
+% <keywordtype> and <keyword> are used to generate/
+% link to a hyper link target. They are not visible
+% in the resulting document.
+% <formatmacro-bg/fg>: TeX code which takes one mandatory argument
+% and formats it as desired. Usually those passed to \NewKeyword are used
+% for both the description and the link.
+% Those passed to \LinkKeyword are used only if the link is undefined.
+% <formatmacro-bg> is applied before \FormatLink.
+% <formatmacro-fg> is applied inside of \FormatLink.
+% Setting a background color must happen in <formatmacro-bg>
+% otherwise it will cover the underline produced by \FormatLink.
+% Using \detokenize must happen in <formatmacro-fg>
+% otherwise \FormatLink will not be executed but printed to the pdf.
+% Changing the font can happen in either one.
+% <text>: TeX code to produce the displayed text.
+% The optional argument of \NewKeyword is a macro which
+% takes the <keyword> as argument and can protect it
+% from expansion when writing it to an auxiliary file.
+% If you try to link an undefined keyword you will
+% get a warning.
+%
+% You can define abbreviations so you do not always
+% need to type out the full name:
+% \AbbrevKeyword[\unexpanded]{<abbrevtype>}{<abbrevname>}{<fulltype>}{<fullname>}
+% If two abbreviations are ambiguous they will not
+% cause an error where they are defined but where
+% they are referenced so you can create abbreviations
+% automatically without trouble.
+%
+% In order to avoid warnings for undescribed keywords
+% \NoKeyword[\unexpanded]{<keywordtype>}{<keyword>}{<formatmacro-bg>}{<formatmacro-fg>}
+% can be used. It is used similar to \NewKeyword but
+% does not display any text and \LinkKeyword to this keyword
+% will not result in a link and will not give a warning.
+% The separation in <formatmacro-bg> and <formatmacro-fg>
+% is only for compatability with \NewKeyword.
+%
+% Links are defined in a temporary file which is loaded in the
+% preamble so that \LinkKeyword can be used before \NewKeyword.
+% I am not using the aux file for that because
+% (a) the aux file is loaded twice (once in \begin{document}
+% and once in \end{document}) and
+% (b) the aux file is loaded in a group so all definitions need
+% to be global but \newcommand can't do that and \gdef does not
+% check if a macro is already defined.
+
+
+% https://github.com/pgf-tikz/pgf/blob/master/tex/latex/pgf/doc/pgfmanual-en-macros.tex
+\colorlet{linkcolor}{black!8}
+\newdimen\pgfmanualcslinkpreskip
+\newdimen\pgfmanualcslinkpostskip
+\ifunderlinelinks
+\newcommand{\FormatLink}[1]{%
+ \begingroup
+ \setbox0=\hbox{#1}%
+ \rlap{{%
+ \keyword@original@color{linkcolor}%
+ \dimen0\wd0
+ \advance\dimen0by-\pgfmanualcslinkpreskip
+ \advance\dimen0by-\pgfmanualcslinkpostskip
+ \hskip\pgfmanualcslinkpreskip
+ \vrule width\dimen0 height-1pt depth1.6pt
+ }}%
+ \box0%
+ \endgroup
+}
+\else
+\newcommand{\FormatLink}[1]{#1}
+\fi
+
+
+% is used in the first run when the keyword is not yet defined
+% or if an abbreviation is ambiguous
+\newcommand{\keyword@placeholder}[1]{%
+ {\keyword@original@color{yellow}%
+ #1%
+ }%
+}
+\let\keyword@original@color=\color
+
+\newcommand{\keyword@targetname}[2]{% #1: keyword type, #2: name
+ keyword:#1:#2%
+}
+\newcommand{\keyword@csname}[2]{% #1: keyword type, #2: name
+ keyword@#1@#2%
+}
+\newcommand{\keyword@link}[3]{% #1: keyword type, #2: name, #3: text
+ \hyperlink{\keyword@targetname{#1}{#2}}{#3}%
+}
+\newcommand{\DisableLinks}{%
+ \let\keyword@link=\@thirdofthree
+ \let\FormatLink=\@firstofone
+}
+\let\keyword@formatenable=\@firstofone
+\newrobustcmd{\keyword@new}[4]{% #1: keyword type, #2: name, #3: format macro bg, #4: format macro fg
+ \expandafter\newcommand\csname\keyword@csname{#1}{#2}\endcsname[1]{\keyword@link{#1}{#2}{\keyword@formatenable{#3}{\FormatLink{\keyword@formatenable{#4}{##1}}}}}%
+}
+\newrobustcmd{\keyword@no}[4]{% #1: keyword type, #2: name, #3: format macro bg, #4: format macro fg
+ \expandafter\newcommand\csname\keyword@csname{#1}{#2}\endcsname[1]{\keyword@formatenable{#3}{\keyword@formatenable{#4}{##1}}}%
+}
+\newrobustcmd{\keyword@abbrev}[4]{% #1: abbrev keyword type, #2: abbrev name, #3: full keyword type, #4: full name
+ \IfKeywordUndefined{#3}{#4}{%
+ \PackageError{keyword}{#3 `#4' (for which you wanted to add the abbreviation `#1@#2') is undefined}{}%
+ }{\IfKeywordUndefined{#1}{#2}{%
+ \expandafter\let \csname\keyword@csname{#1}{#2}\expandafter\endcsname \csname\keyword@csname{#3}{#4}\endcsname
+ }{%
+ \expandafter\def \csname\keyword@csname{#1}{#2}\endcsname ##1{\PackageWarning{keyword}{The abbreviation #1 `#2' is ambiguous. Please specify the full name for ##1}{}\keyword@placeholder{##1}}%
+ }}%
+}
+\newcommand{\IfKeywordIsAbbrev}[4]{% key to be tested, reference key
+ \expandafter\ifx \csname\keyword@csname{#1}{#2}\expandafter\endcsname \csname\keyword@csname{#3}{#4}\endcsname
+ \expandafter \@firstoftwo
+ \else
+ \expandafter \@secondoftwo
+ \fi
+}
+
+\newcommand{\LinkKeyword}[5]{% #1: keyword type, #2: name, #3: formatmacro bg, #4: formatmacro fg, #5: displayed text
+ \IfKeywordUndefined{#1}{#2}{%
+ \edef\do{\noexpand\PackageWarning{keydoc}{Either #1 `#2' is undefined or you need to rerun LaTeX}}%
+ \do
+ \keyword@placeholder{#3{#4{#5}}}%
+ }{%
+ \csname \keyword@csname{#1}{#2}\endcsname{#5}%
+ }%
+}
+\newcommand{\LinkUnformattedKeyword}[3]{% #1: keyword type, #2: name, #3 displayed text
+ \begingroup
+ \let\keyword@formatenable=\@gobble
+ \LinkKeyword{#1}{#2}\@firstofone\@firstofone{#3}%
+ \endgroup
+}
+\newcommand{\IfKeywordUndefined}[2]{% #1: keyword type, #2: name, #3: then, #4: else
+ \expandafter \ifx \csname\keyword@csname{#1}{#2}\endcsname \relax
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \fi
+}
+
+
+\newcommand\keyword@filename{\jobname.kw}
+
+\AtBeginDocument{%
+ \IfFileExists{\keyword@filename}{%
+ \makeatletter
+ \input{\keyword@filename}%
+ \makeatother
+ }{}
+ \newwrite\keyword@file
+ \immediate\openout\keyword@file=\keyword@filename\relax
+}
+
+\newcommand{\NewKeyword}[6][\@firstofone]{% [#1: name protection], #2: type, #3: name, #4: format macro bg, #5: format macro fg, #6: text
+ %https://tex.stackexchange.com/a/17138
+ \Hy@raisedlink{\hypertarget{\keyword@targetname{#2}{#3}}{}}%
+ \if\relax\detokenize{#6}\relax
+ \else
+ #4{#5{#6}}%
+ \fi
+ \immediate\write\keyword@file{\keyword@new{#2}{#1{#3}}{\unexpanded{#4}}{\unexpanded{#5}}}%
+}
+\newcommand{\AbbrevKeyword}[5][\@firstofone]{% abbrev = full
+ \immediate\write\keyword@file{\keyword@abbrev{#2}{#1{#3}} {#1{#4}}{#1{#5}}}%
+}
+\newrobustcmd{\NoKeyword}[5][\@firstofone]{% #2: keyword type, #3: name, #4: format macro bg, #5: format macro fg
+ \immediate\write\keyword@file{\keyword@no{#2}{#1{#3}}{\unexpanded{#4}}{\unexpanded{#5}}}%
+}
+
+
+% ---------- \keydoc ---------
+
+\newif\if@inkeydoc
+\newif\ifkeydoc@isrelated
+
+\newcommand\keydoc@keypath{}
+\newcommand{\keydocpath}[1]{\def\keydoc@keypath{#1}}
+
+\pgfqkeys{/keydoc}{%
+ target/.initial,
+ target/.value required,
+ %
+ initial value/.initial,
+ initial value/.value required,
+ %
+ default value/.initial,
+ default value/.value required,
+}
+
+\newcommand{\keydoc@printvalues}{%
+ \pgfkeysgetvalue{/keydoc/initial value}{\keydoc@initialvalue}%
+ \pgfkeysgetvalue{/keydoc/default value}{\keydoc@defaultvalue}%
+ \let\keydoc@initdefault=\@empty
+ %
+ \unless\ifx \keydoc@defaultvalue \pgfkeysnovalue@text
+ \appto\keydoc@initdefault{\hyperref[initial-vs-default-values]{Default value}: \keydoc@defaultvalue.}%
+ \fi
+ \unless\ifx \keydoc@initialvalue \pgfkeysnovalue@text
+ \unless\ifx \keydoc@initdefault \@empty
+ \appto\keydoc@initdefault{ }%
+ \fi
+ \appto\keydoc@initdefault{\hyperref[initial-vs-default-values]{Initial value}: \keydoc@initialvalue.}%
+ \fi
+ \unless\ifx \keydoc@initdefault \@empty
+ \\%
+ {\MaxFontSize\footnotesize\keydoc@initdefault}%
+ \fi
+ \pgfkeyssetvalue{/keydoc/initial value}{\pgfkeysnovalue}%
+ \pgfkeyssetvalue{/keydoc/default value}{\pgfkeysnovalue}%
+}
+\newcommand{\MaxFontSize}[1]{%
+ #1%
+ \def\MaxFontSize@do##1#1##2\relax{%
+ \@tfor\MaxFontSize@fontsize:=##1\do{%
+ \expandafter\let\MaxFontSize@fontsize=\relax
+ }%
+ }%
+ \MaxFontSize@do\Huge\huge\LARGE\Large\large\normalsize\small\footnotesize\scriptsize\tiny\relax
+}
+
+\newcommand{\keydoc}[3][]{% [#1: options], #2: key name, #3: key type
+ \unless \if@inkeydoc
+ \begin@keydoc
+ \keydoc@registerend
+ \@inkeydoctrue
+ \fi
+ \pgfkeyssetvalue{/keydoc/target}{\pgfkeysnovalue}%
+ \pgfqkeys{/keydoc}{#1}%
+ \keydoc@parsekey#2=\relax%
+ \def\keydoc@abbrev{%
+ \AbbrevKeyword{key}{\keydoc@keypattern} {key}{\keydoc@keypath/\keydoc@keypattern}%
+ \AbbrevKeyword{}{\keydoc@keypattern} {key}{\keydoc@keypath/\keydoc@keypattern}%
+ }%
+ \pgfkeysgetvalue{/keydoc/target}{\keydoc@targetkey}%
+ \ifx \keydoc@targetkey \pgfkeysnovalue@text
+ \let\keydoc@link=\@firstofone
+ \else
+ \def\keydoc@link{\LinkKeyword{key}{\keydoc@targetkey}\keydoc@key@bg\keydoc@original@key}%
+ \IfKeywordUndefined{}{\keydoc@keypattern}{%
+ % keep \keydoc@abbrev
+ }{\IfKeywordIsAbbrev{}{\keydoc@keypattern} {key}{\keydoc@keypath/\keydoc@keypattern}{%
+ % keep \keydoc@abbrev
+ }{%
+ \let\keydoc@abbrev=\relax
+ }}%
+ \fi
+ \ifkeydoc@isrelated
+ \keydoc@keysep
+ \else
+ \keydoc@beforekey
+ \fi
+ \edef\keydoc@do{%
+ \noexpand\NewKeyword{key}{\keydoc@keypath/\keydoc@keypattern}{\noexpand\keydoc@key@bg}{\noexpand\keydoc@original@key}{\noexpand\keydoc@link{\keydoc@keypattern}%
+ \noexpand\keydoc@valueformat{\keydoc@keyvalsep\noexpand\FormatValue\noexpand\keydoc@keyval}}%
+ }%
+ \keydoc@do
+ \keydoc@abbrev
+ \keydoc@keytype{#3}%
+ \keydoc@isrelatedfalse
+ \keydoc@lookahead
+}
+\def\keydoc@parsekey#1=#2\relax{%
+ \if \relax\detokenize{#2}\relax
+ \def\keydoc@keypattern{#1}%
+ \def\keydoc@keyval{}%
+ \def\keydoc@keyvalsep{}%
+ \let\keydoc@valueformat=\@firstofone
+ \else
+ \expandafter\def\expandafter\keydoc@keyval\expandafter{\keydoc@stripeq#2\relax}%
+ \expandafter\keydoc@checkifvalueisoptional\keydoc@keyval\relax
+ \ifendsonspace{#1}{%
+ \def\keydoc@keyvalsep{\ =}%
+ \def\keydoc@keypattern%{#1 without space}
+ }{%
+ \def\keydoc@keyvalsep{=}%
+ \def\keydoc@keypattern%{#1}
+ }%
+ \fi
+}
+\def\keydoc@stripeq#1=\relax{#1}
+\def\keydoc@checkifvalueisoptional#1#2\relax{%
+ \pgfkeysgetvalue{/keydoc/default value}{\keydoc@defaultvalue}%
+ \ifx?#1%
+ \ifx \keydoc@defaultvalue \pgfkeysnovalue@text
+ \ifx \keydoc@link \@firstofone
+ \PackageWarning{keydoc}{keydoc with optional value but default value is not given}{}%
+ \fi
+ \fi
+ \def\keydoc@keyval{#2}%
+ \let\keydoc@valueformat=\keydoc@optionalvalueformat
+ \else
+ \unless\ifx \keydoc@defaultvalue \pgfkeysnovalue@text
+ \PackageWarning{keydoc}{keydoc with default value but value is not optional}{}%
+ \fi
+ \let\keydoc@valueformat=\keydoc@mandatoryvalueformat
+ \fi
+}
+
+
+
+\newcommand{\keydoc@lookahead}{%
+ \futurelet \keydoc@nexttoken \keydoc@lookahead@check
+}
+\newcommand{\keydoc@lookahead@check}{%
+ \ifcat \noexpand\keydoc@nexttoken \space
+ \let\keydoc@lookahead@do=\keydoc@lookahead
+ \let\keydoc@lookahead@gobble=\@firstofone
+ \else\ifx \keydoc@nexttoken \par
+ \let\keydoc@lookahead@do=\keydoc@afterlookahead
+ \let\keydoc@lookahead@gobble=\@empty
+ \else\ifx \keydoc@nexttoken /%
+ \keydoc@isrelatedtrue
+ \let\keydoc@lookahead@do=\keydoc@lookahead
+ \let\keydoc@lookahead@gobble=\@gobble
+ \else\ifx \keydoc@nexttoken \keydoc
+ \let\keydoc@lookahead@do=\keydoc@afterlookahead
+ \let\keydoc@lookahead@gobble=\@empty
+ \else\ifx \keydoc@nexttoken \forwardingkeydoc
+ \let\keydoc@lookahead@do=\keydoc@afterlookahead
+ \let\keydoc@lookahead@gobble=\@empty
+ \else\ifx \keydoc@nexttoken \correspondingkeydoc
+ \let\keydoc@lookahead@do=\keydoc@afterlookahead
+ \let\keydoc@lookahead@gobble=\@empty
+ \else\ifx \keydoc@nexttoken \endkeydoc
+ \let\keydoc@lookahead@do=\keydoc@afterlookahead
+ \let\keydoc@lookahead@gobble=\@empty
+ \else
+ \ifkeydoc@isrelated
+ \PackageError{keydoc}{expexcted another keydoc command after /}{}%
+ \fi
+ \keydoc@printvalues
+ \keydoc@descriptionsep
+ \let\keydoc@lookahead@do=\relax
+ \let\keydoc@lookahead@gobble=\@empty
+ \fi \fi \fi \fi \fi \fi \fi
+ \expandafter \keydoc@lookahead@do \keydoc@lookahead@gobble
+}
+\newcommand{\keydoc@afterlookahead}{%
+ \unless\ifkeydoc@isrelated
+ \keydoc@printvalues
+ \fi
+}
+\newcommand{\RegisterEnd}[1]{%
+ \@tfor \@sec@cmd :=\section\subsection\subsubsection \do{%
+ \expandafter\appto\csname My\expandafter\string\@sec@cmd Hook\endcsname{#1}%
+ }%
+}
+\newcommand{\keydoc@registerend}{\RegisterEnd\endkeydoc}
+
+\newcommand{\keylinktarget}[1]{%
+ \AbbrevKeyword{key}{\keydoc@keypath/#1} {key}{\keydoc@keypath/\keydoc@keypattern}%
+ \AbbrevKeyword{key}{#1} {key}{\keydoc@keypath/\keydoc@keypattern}%
+ \AbbrevKeyword{}{#1} {key}{\keydoc@keypath/\keydoc@keypattern}%
+ \ignorespaces
+}
+
+\let\keydoc@original@key=\key
+\newcommand{\keydoc@key@bg}{\formatcode}
+% I cannot say \renewcommand{\key}[1][] because that would break \keydoc@original@key
+\renewcommand{\key}{%
+ \@ifnextchar [
+ \key@withopt
+ \key@withoutopt
+}
+\newcommand{\key@withopt}{}
+\def\key@withopt[#1]#2{%
+ \ifx\relax#1\relax
+ \LinkKeyword{key}{#2}\keydoc@key@bg\keydoc@original@key{#2}%
+ \else
+ \LinkKeyword{key}{#1/#2}\keydoc@key@bg\keydoc@original@key{#2}%
+ \fi
+}
+\newcommand{\key@withoutopt}[1]{%
+ \LinkKeyword{key}{#1}\keydoc@key@bg\keydoc@original@key{#1}%
+}
+
+\def\key@withopt@unformatted[#1]#2{%
+ \ifx\relax#1\relax
+ \LinkUnformattedKeyword{key}{#2}{#2}%
+ \else
+ \LinkUnformattedKeyword{key}{#1/#2}{#2}%
+ \fi
+}
+
+
+% ---------- \forwardingkeydoc ---------
+
+\newcommand{\forwardingkeydoc}[2][]{% [#1: name, path or full key of target], #2: name
+ \correspondingkeydoc[#1]{#2}{forwarding key}%
+}
+\newcommand{\correspondingkeydoc}[3][]{% [#1: options], #2: name, #3: key type
+ \keydoc[#1, /utils/exec=\forwardingkeydoc@parsetarget{#2}]{#2}{#3}%
+}
+\newcommand{\forwardingkeydoc@parsetarget}[1]{% #1: this key name
+ % parse target which may be a name, path or full key of corresponding key
+ \pgfkeysgetvalue{/keydoc/target}{\forwardingkeydoc@targetkey}%
+ \ifx\forwardingkeydoc@targetkey\pgfkeysnovalue@text
+ \ifundef\TargetKey{%
+ \PackageError{keydoc}
+ {\string\TargetKey{<keypath>}{<keyname>} must be defined if the the optional argument of \forwardingkeydoc\space is not passed}
+ {\string\TargetKey\space shall expand to path/name of the linked key given the path (without trailing slash) and name of the forwarding key.}%
+ }{%
+ \def\forwardingkeydoc@targetkey{\TargetKey{\keydoc@keypath}}%
+ \edef\forwardingkeydoc@targetkey{\expandafter\forwardingkeydoc@targetkey\expandafter{\forwardingkeydoc@stripval#1=\relax}}%
+ \expandafter\ifendsonspace\expandafter{\forwardingkeydoc@targetkey}%
+ {\def\forwardingkeydoc@targetkey}%
+ {\def\forwardingkeydoc@targetkey}%
+ \pgfkeyslet{/keydoc/target}{\forwardingkeydoc@targetkey}%
+ }%
+ \else
+ \forwardingkeydoc@parse{\forwardingkeydoc@targetkey}{\keydoc@keypath}{#1}%
+ \pgfkeyslet{/keydoc/target}{\forwardingkeydoc@targetkey}%
+ \fi
+}
+\newcommand\forwardingkeydoc@parse[3]{% #1: key name, key path or full key of target, #2: path of source, #3: name of source
+ \IfStartsWithSlash{#1}{%
+ \edef\forwardingkeydoc@targetkey@original{#1}%
+ \edef\forwardingkeydoc@targetkey{#1/\forwardingkeydoc@stripval#3=\relax}%
+ \expandafter\ifendsonspace\expandafter{\forwardingkeydoc@targetkey}%
+ {\def\forwardingkeydoc@targetkey}%
+ {\def\forwardingkeydoc@targetkey}%
+ \IfKeywordUndefined{key}{\forwardingkeydoc@targetkey}{%
+ \let\forwardingkeydoc@targetkey=\forwardingkeydoc@targetkey@original
+ }{}%
+ }{%
+ \def\forwardingkeydoc@targetkey{#2/#1}%
+ }%
+}
+\def\forwardingkeydoc@stripval#1=#2\relax{#1}
+
+\newcommand{\IfStartsWithSlash}[1]{%
+ \expandafter\IfStartsWithSlash@do#1\relax
+}
+\def\IfStartsWithSlash@do#1#2\relax{%
+ \ifx/#1%
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \fi
+}
+
+
+% ---------- \keytypedoc ---------
+
+\newcommand{\begin@keytypedoc}{\begin{itemize}}
+\def \endkeytypedoc {\end{itemize}}
+
+\newcommand{\keytypedoc@beforekeytype}{\item}
+\newcommand{\keytypedoc@format}[1]{\emph{#1}}
+\newcommand{\keytypedoc@descriptionsep}{:}
+
+\newif\if@inkeytypedoc
+
+\newcommand{\keytypeRAW}[1]{#1}
+\newcommand{\keytype@bg}[1]{#1}
+\newcommand{\keytype}{% [#1: type name], #2: displayed text (usually the type name, but can be another grammatic form)
+ \@ifnextchar [
+ {\@keytype@do}
+ {\@dblarg\@keytype@do}%
+}
+\def\@keytype@do[#1]#2{%
+ \LinkKeyword{keytype}{#1}\keytype@bg\keytypeRAW{#2}%
+}
+
+\newcommand{\keytypedoc}[1]{% #1 key type name
+ \unless \if@inkeytypedoc
+ \begin@keytypedoc
+ \keytypedoc@registerend
+ \@inkeytypedoctrue
+ \fi
+ \keytypedoc@beforekeytype[\keytypedoc@keytype{#1}]
+ \NewKeyword{keytype}{#1}{\keytype@bg}{\keytypeRAW}{\keytypedoc@format{#1}}%
+ \keytypedoc@descriptionsep
+}
+
+\newcommand{\keytypedoc@registerend}{\RegisterEnd\endkeytypedoc}
+
+\makeatother
diff --git a/macros/latex/contrib/easyfloats/doc/preamble/link.tex b/macros/latex/contrib/easyfloats/doc/preamble/link.tex
new file mode 100644
index 0000000000..bd6daf7d42
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/doc/preamble/link.tex
@@ -0,0 +1,53 @@
+% !TeX root = ../easyfloats.tex
+
+% Copyright © 2020 E. Zöllner
+% Alternatively to the terms of the LPPL, at your choice,
+% you can redistribute and/or modify this file under the
+% terms of the Do What The Fuck You Want To Public License, Version 2,
+% as published by Sam Hocevar. See http://www.wtfpl.net/about/.
+
+% Adds an abstraction layer above hyperref's \href and \hyperref commands.
+% Links are defined with:
+% \newurllink{<name>}{<url>}
+% \newlabellink{<name>}{<label>}
+% A text is turned into a link with
+% \link[<name>]{<text>}
+% Like in markdown the name of the link is optional.
+% If it is omitted <text> is used instead.
+% This has the advantage that all links can be declared in one place
+% and URLs don't need to be repeated.
+% Changing an external link to an internal link is easy.
+
+\makeatletter
+\newcommand{\link@csname}[1]{link@cs@#1}
+
+\newcommand\newurllink{%
+ \begingroup
+ \let\do=\@makeother
+ \dospecials
+ \catcode`{=1
+ \catcode`}=2
+ \newurllink@do
+}
+\newcommand\newurllink@do[2]{% #1: name, #2: url
+ \endgroup
+ \expandafter \newcommand \csname\link@csname{#1}\endcsname{\href{#2}}%
+}
+
+\newcommand\newlabellink[2]{% #1: name, #2: label
+ \expandafter \newcommand \csname\link@csname{#1}\endcsname{\hyperref[#2]}%
+}
+
+\newcommand\link{% [#1: name], #2: displayed text
+ \@ifnextchar [
+ {\link@do}
+ {\@dblarg\link@do}%
+}
+\def\link@do[#1]#2{%
+ \ifcsname\link@csname{#1}\endcsname
+ \csname\link@csname{#1}\endcsname{#2}%
+ \else
+ \PackageError{link}{link name `#1' undefined}{}%
+ \fi
+}
+\makeatother
diff --git a/macros/latex/contrib/easyfloats/doc/preamble/macros.tex b/macros/latex/contrib/easyfloats/doc/preamble/macros.tex
new file mode 100644
index 0000000000..2be2bc74cb
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/doc/preamble/macros.tex
@@ -0,0 +1,218 @@
+% !TeX root = ../easyfloats.tex
+
+% Copyright © 2020 E. Zöllner
+% Alternatively to the terms of the LPPL, at your choice,
+% you can redistribute and/or modify this file under the
+% terms of the Do What The Fuck You Want To Public License, Version 2,
+% as published by Sam Hocevar. See http://www.wtfpl.net/about/.
+
+% Defines additional macros which are not provided
+% by the document class or other packages.
+%
+% \TikZ
+% Typesets the name of the TikZ package.
+% dtxdescribe defines the \tikz macro for that
+% but it's wrong, the Z is not capitalized.
+%
+% \eTeX
+% Typesets the name of eTeX.
+% In standard LaTeX there are \TeX, \LaTeX and \LaTeXe.
+% metalogo and dtxdescribe define more logos.
+% But I have failed to find a package which provides
+% the eTeX logo.
+% In contrast to the other logo macros \eTeX includes a
+% link to the eTeX manual on CTAN.
+%
+% \radioon
+% draws an activated radio button
+% \radiooff
+% draws a deactivated radio button
+%
+% \DescribeHandler[<class>]{<name>}
+% Typesets the handler name as a \marginpar.
+% The same like all other \Describe* macros defined by dtxdescribe
+% just for handlers.
+%
+% \handler{<name>}
+% To reference a handler described with \DescribeHandler.
+%
+% \filename{<filename>}
+% Typesets a file name in the pdf.
+%
+% \pkgoptn{<option>}
+% Typesets a package option in the pdf.
+% \key{<option>}
+% Typesets a macro/environment option in the pdf.
+% Usually \optn is used for both macro options and package options.
+% However, I am using pgfkeys for macro options and standard LaTeX
+% for package options making the two types of options quite different.
+% Unlike some other packages the easyfloats package does not allow to
+% pass macro options as package options.
+% Therefore I like to have a better distinction between them even
+% if they are formatted in the same way.
+% Also, dtxdescribe defines two different macros for the description:
+% \DescribeOption for package/class options and
+% \DescribeKey for macro/environment options.
+% So it is only consistent to have two different macros for typesetting
+% macro/environment and package/class options.
+% I have redefined \optn to print an error in order to avoid ambiguity.
+% \val{<value>}
+% typesets the value of a key. Package options don't have values.
+%
+% \errormessage{<message>}
+% Typesets an error message in the pdf. Changes category codes so that
+% control sequences and active characters do *not* need to be prefixed
+% by \string.
+%
+% \sectionname{<title>}
+% Format the name of a section of a different document which I am referring to.
+% For sections of this document use \cref or \Cref instead.
+%
+% \newlicense{<name>}{<display text>}{<url>}
+% \license{<name>}
+% Define a license in the preamble with displayed name and URL with \newlicense
+% and use it in the document with \license.
+% Changes catcodes for the <url> only so that special characters
+% can be used there without worrying (except for curly braces).
+%
+% \formatcode{<texcode>}
+% Formats inline code.
+% It does not change catcodes or performs any other kind of magic.
+% <texcode> is executed as TeX code.
+
+\usepackage{relsize}
+
+
+\makeatletter
+\newcommand{\version}{\newcommand\theversion}
+\newcommand{\package}{\newcommand\thepackage}
+\newcommand{\thedate}{\@date}
+\AtBeginDocument{%
+ \let\thedate=\@date
+ \ifundef{\theversion}{}{\appto\@date{\strut\\\strut\thepackage~\theversion}}%
+}
+\makeatother
+
+\makeatletter
+\newcommand\parskipintoc[1]{%
+ \def\@starttoc##1{%
+ \begingroup
+ \makeatletter
+ \parskip=#1\relax
+ \@input{\jobname.##1}%
+ \if@filesw
+ \expandafter\newwrite\csname tf@##1\endcsname
+ \immediate\openout\csname tf@##1\endcsname \jobname.##1\relax
+ \fi
+ \@nobreakfalse
+ \endgroup
+ }
+}
+\makeatother
+\parskipintoc{0pt plus .6em minus 1pt}
+
+\newcommand{\bigpar}{\par{\centering*~*~*\pagebreak[3]\par}}
+\newcommand{\bigparinlist}{\par\medskip\pagebreak[3]\par}
+\let\OriginalItemize=\itemize
+\def\itemize{\OriginalItemize\let\bigpar\bigparinlist}
+
+\newcommand{\eTeX}{\texorpdfstring{\href{https://ctan.org/pkg/etex}{\ensuremath{\varepsilon}-\TeX}}{eTeX}}
+\newcommand{\TikZ}{Ti\emph{k}Z}
+
+\newcommand{\radioon}{\radio{\fill circle (.45);}}
+\newcommand{\radiooff}{\radio\relax}
+\newcommand{\radio}[1]{\tikz[x=1ex,y=1ex,baseline=-.6ex,very thin]{\draw circle (.75);#1}}
+
+
+\newcommand{\filename}{\emph}
+
+\newcommand{\pkgoptn}{\optn}
+\newcommand{\key}{\optn}
+\let\pkgoptn=\optn
+\let\key=\optn
+\let\handler=\optn
+% Do *not* add the optional argument, otherwise \renewcommand would not only redefine \optn
+% but also two internal macros which \pkgoptn and \key depend on.
+\renewcommand{\optn}[1]{\PackageError{macros}{\string\optn\space is ambiguous}{Please use \string\key\space for macro/environment options and \string\pkgoptn\space for package/class options.}}
+
+\newcommand{\val}[1]{#1}
+
+\makeatletter
+\newcommand*{\DescribeHandler}[2][]{\DTXD@margintagindex{#1}{#2}{Handler}{handler}{usage}}
+
+\newcommand{\errormessage}{%
+ \begingroup
+ \let\do=\@makeother
+ \dospecials
+ \@makeother`
+ \catcode`{=1
+ \catcode`}=2
+ \catcode` =10
+ \do@errormessage
+}
+\newcommand{\do@errormessage}[1]{%
+ \endgroup
+ \enquote{\texttt{#1}}%
+}
+\makeatother
+
+
+\newrobustcmd{\sectionname}[1]{{\let\formatcode\formatcodeinsection\emph{#1}}}
+
+
+\makeatletter
+\newcommand{\license@csname}[1]{license@cs@#1}
+\newcommand{\FormatLicense}{\emph}
+
+\newcommand{\newlicense}[2]{%
+ \begingroup
+ \let\do=\@makeother
+ \dospecials
+ \catcode`{=1
+ \catcode`}=2
+ \newlicense@do{#1}{#2}%
+}
+\newcommand{\newlicense@do}[3]{% #1: name, #2: display text, #3: url
+ \endgroup
+ \expandafter \newcommand \csname\license@csname{#1}\endcsname{\href{#3}{\FormatLicense{#2}}}%
+}
+
+\newcommand{\license}[1]{% #1: name
+ \ifcsname\license@csname{#1}\endcsname
+ \csname\license@csname{#1}\endcsname
+ \else
+ \PackageError{macros}{license name `#1' undefined}{}%
+ \fi
+}
+
+
+% ---------- \formatcode ---------
+
+\newcommand{\formatcode}[1]{{\ttfamily\smaller[.5]\fboxsep=.5pt\colorbox{codebackground!50}{\vphantom\}\colorlet{linkcolor}{codelinkcolor}#1}}}
+\newcommand{\formatcodeinsection}[1]{{\ttfamily#1}}
+\newcommand{\formatcodeinmarginpar}[1]{\formatcodeinsection{\small#1}}
+
+% patch section commands and toc to use \formatcodeinsection instead of \formatcode
+\newcommand{\patchsection}[3]{% #1: command to be patched, #2: code to be inserted before, #3 code to be appended
+ \expandafter\let\csname @@originalsec@\string#1\endcsname #1%
+ \expandafter\def\csname @@sec@\string#1\endcsname##1##2{#2\csname @@originalsec@\string#1\endcsname##1{##2}#3}%
+ \def#1##1##{\csname @@sec@\string#1\endcsname{##1}}%
+}
+\@tfor \@sec@cmd :=\section\subsection\subsubsection \do{%
+ \expandafter\expandafter\expandafter\patchsection\expandafter\@sec@cmd\expandafter{%
+ \csname My\expandafter\string\@sec@cmd Hook\endcsname
+ \let\@original@formatcode=\formatcode
+ \let\formatcode=\formatcodeinsection
+ }{%
+ \let\formatcode=\@original@formatcode
+ }%
+}
+\let\@@original@toc=\tableofcontents
+\def\tableofcontents{{\let\formatcode\formatcodeinsection\DisableLinks\@@original@toc}}
+
+% patch \marginpar to use \formatcodeinmarginpar instead of \formatcode
+\let\@@original@marginpar=\marginpar
+\renewcommand\marginpar[1]{\@@original@marginpar{\let\formatcode=\formatcodeinmarginpar#1}}
+
+
+\makeatother
diff --git a/macros/latex/contrib/easyfloats/doc/preamble/markdown.tex b/macros/latex/contrib/easyfloats/doc/preamble/markdown.tex
new file mode 100644
index 0000000000..44662c79aa
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/doc/preamble/markdown.tex
@@ -0,0 +1,153 @@
+% !TeX root = ../easyfloats.tex
+
+% Copyright © 2020 E. Zöllner
+% Alternatively to the terms of the LPPL, at your choice,
+% you can redistribute and/or modify this file under the
+% terms of the Do What The Fuck You Want To Public License, Version 2,
+% as published by Sam Hocevar. See http://www.wtfpl.net/about/.
+
+% Allows markdown like syntax:
+% *emph*
+% `code`
+%
+% If `<code>` is used in an argument <code> cannot contain:
+% - comment characters (percent sign)
+% - unbalanced curly braces
+%
+% If `<code>` is used in a context where fragile commands break
+% (e.g. an entry of the table of contents or list of figures):
+% - control sequences and active characters *after* the first token
+% must be preceded by \string or \protect
+%
+% If `<code>` is used in a pdf string (e.g. in \section):
+% - control sequences *after* the first token must be preceded by \cmd
+% - active characters *after* the first token must be preceded by \string
+% - curly braces *after* the first token must be escaped or preceded by \string
+%
+% If you add prefixes like `\string` or `\cmd` in a normal execution context
+% they will (of course) be treated as code to be displayed.
+% Therefore it may be necessary to pass different code for these three cases:
+% \section[\texorpdfstring
+% {`\emph{page\string~42}`}
+% {`\emph\{page\string~42\}`}]
+% {`\emph{page~42}`}
+%
+% Warning: \section uses \write without \immediate.
+% If the definition of ` is different where it is written
+% e.g. if the next page break is inside of a minted environment
+% you will get into trouble.
+%
+% Warning: With * being an active character you cannot just
+% use starred versions of environments.
+% \starred expands to a * with catcode other:
+% \begin{examplecode\starred}
+% <code>
+% \end{examplecode\starred}
+% I am redefining \@ifstar to recognize active * as well.
+% So starred commands can be used usual.
+%
+% Warning: This should be loaded last so that the
+% category changing code is appended to the hook last.
+% Otherwise there is trouble with minted.
+%
+% depends on
+% \LinkKeyword{<keywordtype>}{<keyword>}<formatmacro>{<text>}
+% from preamble/keydoc.tex
+
+\usepackage{etoolbox}
+
+\newcommand{\starred}{*}
+
+\providecommand{\mintinline}[1]{\verb}%}
+
+\makeatletter
+% An alternative version of \@ifstar which also recognizes an active star.
+% I am not changing \@ifstar here because the active * is defined in \AtBeginDocument.
+% So in the preamble \newcommand would check if the next token is an undefined control sequence token.
+% If it was it would be discarded and it would try to define the next token.
+\let\@markdown@original@ifstar=\@ifstar
+\catcode`*=\active
+\def\@markdown@ifstar#1#2{%
+ \@markdown@original@ifstar
+ {#1}%
+ {%
+ \@ifnextchar*%
+ {\@firstoftwo{#1}}%
+ {#2}%
+ }%
+}
+\@makeother*
+
+\protected\def\IfProtectedContextGobble#1{\ifx\@thirdofthree#1\relax\else#1\fi}
+\newcommand\IfUnprotectedContext{%
+ \IfProtectedContextGobble\@thirdofthree
+ \@firstoftwo
+}
+
+\catcode``=\active
+\newcommand\MarkdownVerb{%
+ \begingroup
+ \@examplecode@setcatcodes
+ \catcode\string``=\active
+ \futurelet \@MarkdownVerb@nexttoken \@MarkdownVerb@do
+}
+\long\def\@MarkdownVerb@do#1`{%
+ \IfKeywordUndefined{}{\detokenize{#1}}{%
+ \ifcat \noexpand\@MarkdownVerb@nexttoken a%
+ \xckey`#1`%
+ \else
+ \xc`#1`%
+ \fi
+ }{%
+ \catcode\string` =10
+ \catcode\string`\^^M=9
+ \def\do{\LinkKeyword{}{\detokenize{#1}}\@firstofone\@firstofone}%
+ \scantokens{\appto\do{{#1}}}%
+ \do
+ }%
+ \endgroup
+}
+\def\StringifyMarkdownVerb#1`{\string#1\noexpand`}
+\def\PdfStringifyMarkdownVerb#1#2`{%
+ \ifcat\relax\noexpand#1\relax
+ \cmd#1%
+ \else
+ \string#1%
+ \fi
+ \detokenize{#2}%
+}
+\@makeother`
+
+\write\@auxout{\string\catcode\string\string``=\active}
+
+% \AfterEndPreamble is important when used with minted
+\AfterEndPreamble{%
+ \catcode`*=\active
+ \appto\dospecials{\do\*}%
+ \scantokens{\def\ActiveAsterisc{*}}%
+ \edef\do{\def\expandonce\ActiveAsterisc##1\expandonce\ActiveAsterisc{\noexpand\emph{##1}}}%
+ \do
+ \let\@ifstar=\@markdown@ifstar
+ %
+ \catcode``=\active
+ %% If I add ` to \dospecials \mintinline will change it to catcode other
+ %% therefore not finding the active ` which marks the end resulting in
+ %% ! Paragraph ended before \minted@inline@ii was complete.
+ %% I could change the definition of \mintinline to expect an other `
+ %% but that would fail when using `...` inside of an argument.
+ %% Whether ` is contained in \dospecials or not does not seem to bother \verb.
+ %\appto\dospecials{\do\`}%
+ \scantokens{%
+ \def`{%
+ \texorpdfstring{%
+ \IfUnprotectedContext%
+ {\MarkdownVerb}
+ {\noexpand`\StringifyMarkdownVerb}%
+ }{%
+ \PdfStringifyMarkdownVerb
+ }%
+ }%
+ }%
+}
+
+\makeatother
diff --git a/macros/latex/contrib/easyfloats/doc/preamble/pdfstring.tex b/macros/latex/contrib/easyfloats/doc/preamble/pdfstring.tex
new file mode 100644
index 0000000000..0a94b3d720
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/doc/preamble/pdfstring.tex
@@ -0,0 +1,35 @@
+% !TeX root = ../easyfloats.tex
+
+% Copyright © 2020 E. Zöllner
+% Alternatively to the terms of the LPPL, at your choice,
+% you can redistribute and/or modify this file under the
+% terms of the Do What The Fuck You Want To Public License, Version 2,
+% as published by Sam Hocevar. See http://www.wtfpl.net/about/.
+
+% Redefines \cmd so that it can be used in a pdf string,
+% e.g. in \section{...}.
+% Please note that additionally to the restrictions
+% named in the ltxdoc documentation you cannot use \cmd{\ }.
+% That is a bug in ltxdoc and unrelated to pdf strings.
+%
+% This must be loaded last, after all other modifications
+% to the \cmd macro.
+
+\let\PdfstringOriginalCmd=\cmd
+\renewcommand{\cmd}[1]{%
+ \texorpdfstring
+ {\PdfstringOriginalCmd{#1}}
+ {\expandafter\PdfstringCmd\string#1\relax}%
+}
+
+\def\PdfstringCmd#1#2#3\relax{%
+ \textbackslash
+ \ifnum\noexpand`\\=\noexpand`#2
+ \textbackslash
+ \else\ifnum\noexpand`\%=\noexpand`#2
+ \%%
+ \else
+ #2%
+ \fi\fi
+ #3%
+}
diff --git a/macros/latex/contrib/easyfloats/doc/undescribed-keywords.tex b/macros/latex/contrib/easyfloats/doc/undescribed-keywords.tex
new file mode 100644
index 0000000000..166f92423e
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/doc/undescribed-keywords.tex
@@ -0,0 +1,247 @@
+% !TeX root = easyfloats.tex
+\makeatletter
+\edef\@thecatcode@asterisc{\the\catcode\string`*}
+\@makeother*
+
+% undescribed packages
+\NoDescribePkg{graphics}
+\NoDescribePkg{subfigure}
+\NoDescribePkg{subfig}
+\NoDescribePkg{trivfloat}
+\NoDescribePkg{capt-of}
+\NoDescribePkg{geometry}
+\NoDescribePkg{fontenc}
+\NoDescribePkg{lmodern}
+
+% standard preamble
+\NoDescribeMacro\documentclass
+\NoDescribeMacro\usepackage
+\NoDescribeMacro\newcommand
+\NoDescribeMacro\AtBeginDocument
+\NoDescribeMacro\floatplacement
+\NoDescribeMacro\makeatletter
+\NoDescribeMacro\makeatother
+\NoDescribeMacro\title
+\NoDescribeMacro\author
+\NoDescribeMacro\typeout
+\NoDescribeMacro\@empty
+\NoDescribeMacro\@tfor
+
+% standard document
+\NoDescribeEnv{document}
+\NoDescribeMacro\section
+\NoDescribeMacro\begin
+\NoDescribeMacro\end
+\NoDescribeEnv{center}
+\NoDescribeMacro\centering
+\NoDescribeMacro\caption
+\NoDescribeMacro\label
+\NoDescribeMacro\texttt
+\NoDescribeMacro\small
+\NoDescribeMacro\href
+\NoDescribeMacro\vdots
+\NoDescribeMacro\quad
+\NoDescribeMacro\qquad
+\NoDescribeMacro\ref
+\NoDescribeMacro\pageref
+\NoDescribeMacro\raggedleft
+\NoDescribeMacro\bigskip
+\NoDescribeMacro\verb
+\NoDescribeMacro\hspace
+\NoDescribeMacro\phantom
+
+% escape sequences
+\NoDescribeMacro\textbackslash
+\NoDescribeMacro\{
+\NoDescribeMacro\}
+\NoDescribeMacro\$
+\NoDescribeMacro\&
+\NoDescribeMacro\#
+\NoDescribeMacro\^
+\NoDescribeMacro\_
+\NoDescribeMacro\textunderscore
+\NoDescribeMacro~
+\NoDescribeMacro\%
+
+% ambiguous values
+% e.g. placement, subpage outer pos, subcaptionbox inner pos
+\NoDescribeVal{htbp}
+\NoDescribeVal{h}
+\NoDescribeVal{t}
+\NoDescribeVal{b}
+\NoDescribeVal{p}
+\NoDescribeVal{H}
+\NoDescribeVal{h!}
+\NoDescribeVal{c}
+\NoDescribeVal{T}
+\NoDescribeVal{B}
+\NoDescribeVal{auto}
+\NoDescribeVal{Auto}
+\NoDescribeVal{l}
+\NoDescribeVal{r}
+\NoDescribeVal{s}
+\NoDescribeVal{tbp}
+\NoDescribeVal{lof}
+\NoDescribeVal{lot}
+\NoDescribeVal{cl}
+
+% float style values
+\NoDescribeVal{plain}
+\NoDescribeVal{plaintop}
+\NoDescribeVal{ruled}
+\NoDescribeVal{boxed}
+
+% plain TeX
+\NoDescribeMacro\csname
+\NoDescribeMacro\number
+
+% units
+\NoDescribeVal{cm}
+\NoDescribeVal{pt}
+\NoDescribeVal{em}
+\NoDescribeVal{ex}
+
+% this package
+\NoDescribePkg{easyfloats}
+\NoDescribeVal{all}
+\NoDescribeKey{graphic}% "prefix `graphic`"
+\NoDescribeKey{<options>}
+\NoDescribeKey{/object/<options>}
+\NoDescribeMacro\object@tableBreakText
+
+% tables
+\NoDescribeEnv{table}
+\NoDescribeEnv{tabular}
+\NoDescribeEnv{tabular*}
+\NoDescribeEnv{tabularx}
+\NoDescribeMacro\\
+\NoDescribeMacro\multicolumn
+\NoDescribeMacro\hline
+
+% booktabs
+\NoDescribeMacro\toprule
+\NoDescribeMacro\midrule
+\NoDescribeMacro\bottomrule
+
+% array
+\NoDescribeMacro\newcolumntype
+\NoDescribeMacro\arraybackslash
+
+% longtable
+\NoDescribeEnv{longtable}
+\NoDescribeMacro\LT@cols
+
+% graphics
+\NoDescribeEnv{figure}
+\NoDescribeMacro\includegraphics
+\NoDescribeMacro\linewidth
+\NoDescribeMacro\listoffigures
+\NoDescribeMacro\resizebox
+
+% float
+\NoDescribeMacro\restylefloat
+\NoDescribeMacro\floatstyle
+\NoDescribeMacro\floatname
+\NoDescribeKey{width}
+
+% (sub)caption
+\NoDescribeMacro\captionsetup
+\NoDescribeMacro\DeclareCaptionJustification
+\NoDescribeMacro\DeclareCaptionSubType
+\NoDescribeMacro\phantomcaption
+\NoDescribeEnv{subfigure}
+\NoDescribeEnv{subtable}
+\NoDescribeMacro\subcaptionbox
+\NoDescribeMacro\captionof
+
+% placeins
+\NoDescribePkgoptn{section}
+\NoDescribeMacro\FloatBarrier
+
+% xcolor
+\NoDescribeMacro\colorlet
+\NoDescribeMacro\rowcolor
+\NoDescribeMacro\rowcolors
+\NoDescribePkgoptn{table}
+
+% siunitx
+\NoDescribeMacro\si
+\NoDescribeMacro\degree
+\NoDescribeVal{S}
+
+% plain
+\NoDescribeMacro\def
+\NoDescribeMacro\catcode
+\NoDescribeMacro\active
+\NoDescribeMacro\the
+\NoDescribeMacro\string
+\NoDescribeMacro\par
+\NoDescribeMacro\ifx
+\NoDescribeMacro\else
+\NoDescribeMacro\fi
+\NoDescribeMacro\relax
+\NoDescribeMacro\begingroup
+\NoDescribeMacro\endgroup
+\NoDescribeMacro\scantokens
+
+% math
+\NoDescribeMacro\sin
+\NoDescribeMacro\cos
+\NoDescribeMacro\tan
+\NoDescribeMacro\pm
+\NoDescribeMacro\infty
+\NoDescribeMacro\langle
+\NoDescribeMacro\rangle
+
+% tikz
+\NoDescribeEnv{tikzpicture}
+\NoDescribeMacro\tikzset
+\NoDescribeMacro\draw
+\NoDescribeMacro\node
+\NoDescribeMacro\foreach
+
+% cleveref
+\NoDescribeMacro\cref
+\NoDescribeMacro\cpageref
+\NoDescribePkgoptn{nameinlink}
+\NoDescribePkgoptn{noabbrev}
+
+% hyperref
+\NoDescribeMacro\url
+\NoDescribePkgoptn{pdfusetitle}
+
+% pgfkeys
+\NoDescribeMacro\pgfkeys
+\NoDescribeVal{true}
+\NoDescribeVal{false}
+\NoDescribeHandler{.expand once}
+
+% keyval
+\NoDescribeMacro\setkeys
+
+% custom
+\NoDescribeMacro\pminfty
+\NoDescribeMacro\charsym
+\NoDescribeMacro\charname
+\NoDescribeMacro\colspec
+\NoDescribeMacro\n
+\NoDescribeMacro\i
+\NoDescribeMacro\w
+\NoDescribeEnv{tikzobject}
+\NoDescribeEnv{tikz3dobject}
+
+% not used directly
+\NoDescribeMacro\center
+\NoDescribeMacro\endcenter
+\NoDescribeMacro\refstepcounter
+\NoDescribeMacro\ignorespacesafterend
+\NoDescribeMacro\@endparenv
+\NoDescribeMacro\caption@iftop
+
+% not existing
+\NoDescribeMacro\endcentering
+\NoDescribeMacro\|
+\NoDescribeMacro|
+
+\catcode\string`*=\@thecatcode@asterisc
+\makeatother
diff --git a/macros/latex/contrib/easyfloats/easyfloats-file-list.txt b/macros/latex/contrib/easyfloats/easyfloats-file-list.txt
new file mode 100644
index 0000000000..44c333bcb5
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/easyfloats-file-list.txt
@@ -0,0 +1,40 @@
+This work is distributed under the LaTeX Project Public License, version 1.3 or later. The license is contained in the file license.txt.
+The preamble of the documentation may alternatively, at your choice, be reused under the terms of the WTFPL as published by Sam Hocevar (http://www.wtfpl.net/about/).
+This work consists of the following files:
+
+easyfloats-file-list.txt
+
+easyfloats.ins
+easyfloats.dtx
+easyfloats.sty
+README.md
+DEPENDS.txt
+
+doc/easyfloats.tex
+doc/easyfloats.pdf
+doc/easyfloats.bib
+doc/links.tex
+doc/undescribed-keywords.tex
+doc/content/bug-reports-and-contributions.tex
+doc/content/documentation.tex
+doc/content/examples.tex
+doc/content/installation.tex
+doc/content/license.tex
+doc/content/motivation.tex
+doc/content/other-packages.tex
+doc/content/names.tex
+doc/content/titlepage.tex
+doc/content/used-packages.tex
+doc/preamble/bibliography.tex
+doc/preamble/description-links.tex
+doc/preamble/examplecode.tex
+doc/preamble/keydoc.tex
+doc/preamble/link.tex
+doc/preamble/macros.tex
+doc/preamble/markdown.tex
+doc/preamble/pdfstring.tex
+doc/lexer/latex_atletter.py
+
+There are automated tests to test this work at
+https://gitlab.com/erzo/latex-easyfloats/-/tree/master/test
+These tests are licensed under the WTFPL http://www.wtfpl.net/about/.
diff --git a/macros/latex/contrib/easyfloats/easyfloats.dtx b/macros/latex/contrib/easyfloats/easyfloats.dtx
new file mode 100644
index 0000000000..eea9932e40
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/easyfloats.dtx
@@ -0,0 +1,1897 @@
+% easyfloats.dtx
+% Copyright 2020 E. Zöllner
+%
+% This work may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License, either version 1.3
+% 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.3 or later is part of all distributions of LaTeX
+% version 2005/12/01 or later.
+%
+% This work has the LPPL maintenance status `maintained'.
+%
+% The Current Maintainer of this work is E. Zöllner.
+%
+% This work consists of the files listed in easyfloats-file-list.txt.
+% The official git repository is https://gitlab.com/erzo/latex-easyfloats
+
+
+% dtx files (documented tex files) allow "to put the user documentation,
+% code documentation and code itself in one place."
+% https://www.texdev.net/2009/10/05/the-dtx-format/
+% see also
+% https://www.texdev.net/2009/10/06/a-model-dtx-file/
+% https://ctan.org/pkg/dtxtut
+%
+% This file is a lot simpler, it contains nothing but the package code with comments.
+% Technically it could be used instead of the sty file.
+% easyfloats.ins reads this file, strips comments and indentation using docstrip
+% and writes the result to the sty file in order to make it faster.
+
+
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{easyfloats}[2020/12/20 v1.0.0]
+
+
+% ========== options ==========
+
+% load either graphicx or graphbox
+\newif\ifesf@loadgraphics
+% load graphbox
+\newif\ifesf@loadgraphbox
+% load longtable
+\newif\ifesf@loadlongtable
+% load array
+\newif\ifesf@loadarray
+% load booktabs
+\newif\ifesf@loadbooktabs
+% print a warning if figure or table is used directly
+\newif\ifesf@warnstandardfloats
+\esf@warnstandardfloatstrue
+
+\DeclareOption{graphicx}{%
+ \esf@loadgraphicstrue
+ \esf@loadgraphboxfalse
+}
+\DeclareOption{graphbox}{%
+ \esf@loadgraphicstrue
+ \esf@loadgraphboxtrue
+}
+\DeclareOption{nographic}{%
+ \esf@loadgraphicsfalse
+ \esf@loadgraphboxfalse
+}
+
+\DeclareOption{longtable}{%
+ \esf@loadlongtabletrue
+}
+\DeclareOption{nolongtable}{%
+ \esf@loadlongtablefalse
+}
+
+\DeclareOption{booktabs}{%
+ \esf@loadbooktabstrue
+}
+\DeclareOption{nobooktabs}{%
+ \esf@loadbooktabsfalse
+}
+
+\DeclareOption{array}{%
+ \esf@loadarraytrue
+}
+\DeclareOption{noarray}{%
+ \esf@loadarrayfalse
+}
+
+% If I spell this with spaces LaTeX complains:
+% > Unknown option `allowstandardfloats'
+% It seems spaces are ignored by \usepackage
+% but not by \DeclareOption.
+% clsguide says:
+% > Note that the name of an option should contain
+% > only those characters allowed in a ‘LaTeX name’
+% So maybe it's better to not rely on that behaviour.
+\DeclareOption{allowstandardfloats}{%
+ \esf@warnstandardfloatsfalse
+}
+
+%\DeclareOption*{\objectset{\CurrentOption}}
+
+
+\ExecuteOptions{graphicx, array, booktabs}
+
+% \relax is in definition order, starred is in specification order
+\ProcessOptions\relax
+
+
+% ========== required packages ==========
+
+\RequirePackage{etoolbox}
+\RequirePackage{pgfkeys}
+
+% The float package defines the placement option H so that I don't need to
+% provide a separate inline/floating option and deal with spacing and captions
+% of inline objects. I can just use the usual environments like always.
+% It also defines float styles which move the caption to the top or bottom of
+% the object. It makes things easier for me because I can just insert the
+% caption somewhere independent of the object type.
+% I am *not* making use of it's capability to define new float types.
+% Please note that \floatplacement is overridden if the placement option is non-empty.
+\RequirePackage{float}
+
+% By default there is no space between a table and it's caption (at least with
+% the standard document classes). The caption package fixes this.
+% The caption package defines the \phantomcaption command (see object environment).
+% The caption package is required by the subcaption package.
+% It also gives the possibility to customize the layout of captions. But I am
+% leaving it to the user to do this if desired.
+\RequirePackage{caption}
+
+% subobjects
+\RequirePackage{environ}
+
+% "Die Pakete subfigure.sty und subfig.sty werden nicht mehr weiterentwickelt
+% und sind inkompatibel zu einigen aktuelleren Paketen wie hyperref.sty.
+% Als Ersatz bei Kompatibilitätsproblemen empfiehlt sich subcaption.sty."
+% (l2tabu, Version 2.4 vom 3. Februar 2016, Seite 16)
+\RequirePackage{subcaption}
+
+% \includegraphics
+\ifesf@loadgraphics
+ \ifesf@loadgraphbox
+ % extension for graphicx
+ \RequirePackage{graphbox}
+ \else
+ \RequirePackage{graphicx}
+ \fi
+\fi
+
+% Set long tables which are not floating
+% but can span across page breaks.
+% Requires several runs.
+\ifesf@loadlongtable
+ \RequirePackage{longtable}
+\fi
+
+% Additional features in column specification like <, >, !.
+% Changes also the behaviour of rules but that is irrelevant if you use booktabs.
+\ifesf@loadarray
+ \RequirePackage{array}
+\fi
+
+% Macros for formating tables.
+\ifesf@loadbooktabs
+ \RequirePackage{booktabs}
+\fi
+
+
+% ========== init ==========
+
+\newif\ifobject@directkeys
+\object@directkeystrue
+
+\newif\if@inobject
+\newif\if@firstsubobject
+\newif\if@containssubobjects
+
+\floatstyle{plaintop}
+\restylefloat{table}
+\floatstyle{plain}
+\restylefloat{figure}
+
+
+% ========== hooks ==========
+
+\newif\ifobject@isgraphic
+
+\newcommand{\object@hook}{}
+\newcommand{\subobject@hook}{}
+\newcommand{\object@graphic@hook}{}
+
+\newrobustcmd{\AtBeginObject}[1]{\appto\object@hook{#1}}
+\newrobustcmd{\AtBeginSubobject}[1]{\appto\subobject@hook{#1}}
+\newrobustcmd{\AtBeginGraphicObject}[1]{\appto\object@graphic@hook{#1}}
+
+
+% ========== key management ==========
+
+\newcommand{\esf@ifpgfkeyhasvalue}[1]{% #1: key, #2: executed if #1 is set, #3: executed if #1 has not been set
+ % WARNING: Trying to get the value defines the key to \relax if it
+ % was undefined (because of \csname). Setting the key to \relax is
+ % discouraged because it causes inconsistent behaviour [TikZ & PGF
+ % Manual v3.1.5b page 976 \pgfkeysifdefined].
+ % With eTeX: \pgfkeysifdefined will report the key as *defined*.
+ % Without eTeX: \pgfkeysifdefined will report the key as *un*defined.
+ % Therefore don't use this macro with undefined keys. If you do use
+ % it with an undefined key it will be treated as if it has been set [!].
+ \pgfkeysgetvalue{#1}{\esf@tmp@value}%
+ \ifx \pgfkeysnovalue@text \esf@tmp@value
+ \expandafter \@secondoftwo
+ \else
+ \expandafter \@firstoftwo
+ \fi
+}
+
+\newcommand{\esf@ifpgfkeyexists}[3]{%
+ % I cannot use \@firstoftwo and \@secondoftwo because \pgfkeysifdefined
+ % does not close the if statement before expanding the 2nd and 3rd argument
+ \pgfkeysifdefined{#1}
+ {#2}
+ {\pgfkeysifdefined{#1/.@cmd}{#2}{#3}}%
+}
+\newcommand{\esf@ifpgfkeyrequiresvalue}[3]{% #1: key, #2: then block, #3: else block
+ \pgfkeysifdefined{#1/.@def}{%
+ \pgfkeysgetvalue{#1/.@def}{\esf@tmp@value}%
+ \ifx \esf@tmp@value \pgfkeysvaluerequired
+ #2%
+ \else
+ #3%
+ \fi
+ }{%
+ #3%
+ }%
+}
+
+\newcommand{\esf@ifkeyvalkeyexists}[4]{% #1: family, #2: key, #3: then block, #4: else block
+ % \ifcsdef would treat \relax as defined, \ifcsundef does not
+ \ifcsundef{KV@#1@#2}{#4}{#3}%
+}
+\newcommand{\esf@ifkeyvalkeyrequiresvalue}[2]{% #1: family, #2: key, #3: then block, #4: else block
+ % \ifcsdef would treat \relax as defined, \ifcsundef does not
+ \ifcsundef{KV@#1@#2@default}%
+}
+
+\newcommand{\esf@pgfkeyscopyvalue}[2]{% #1: key to be set, #2 key to take the value from
+ % WARNING: the order of arguments is opposite of the shell command cp
+ % because all pgf macros take the key they operate on as first argument.
+ \pgfkeysgetvalue{#2}{\esf@tmp@value}%
+ \pgfkeyslet{#1}{\esf@tmp@value}%
+}
+\newcommand{\esf@pgfkeysvalueappend}[2]{% #1: key to be set, #2 value to be appended
+ \pgfkeysgetvalue{#1}{\esf@tmp@value}%
+ \appto\esf@tmp@value{#2}%
+ \pgfkeyslet{#1}{\esf@tmp@value}%
+}
+
+\pgfqkeys{/handlers}{%
+ % ------- recommended -------
+ .esf@recommended/.code={%
+ \esf@ifpgfkeyhasvalue{\pgfkeyscurrentpath}{%
+ % do nothing
+ }{%
+ \edef\esf@tmp@path{\pgfkeyscurrentpath}%
+ \PackageWarning{easyfloats}{Recommended key '\strippath\esf@tmp@path' not given. #1\ifx\pgfkeysnovalue#1\@empty\else. \fi This warning occured}%
+ }%
+ },
+ %
+ % ------- mandatory -------
+ .esf@mandatory/.code={%
+ \esf@ifpgfkeyhasvalue{\pgfkeyscurrentpath}{%
+ % do nothing
+ }{%
+ \edef\esf@tmp@path{\pgfkeyscurrentpath}%
+ \PackageError{easyfloats}{Mandatory key '\strippath\esf@tmp@path' not given\ifx\pgfkeysnovalue#1\@empty\else. \fi #1}{}%
+ }%
+ },
+ %
+ %
+ % ------- save unknown -------
+ % I can't use /pgf/keyfilters/defined with /pgf/key filter handlers/append filtered to
+ % because that appends full keys which are incompatible with keyval.
+ .esf@exec on unknown/.code={% #1: control sequence taking two args: key and value
+ \pgfkeysalso{\pgfkeyscurrentpath/.unknown/.code=% ##1: value
+ #1{\pgfkeyscurrentname}{##1}%
+ }%
+ },
+ %
+ % ------- also from -------
+ .esf@also from/.code={% #1: expandable control sequence containing options
+ \pgfkeysalsofrom{#1}%
+ },
+ %
+ % ------- debugging -------
+ .show boolean/.code={%
+ \begingroup
+ \renewcommand\pgfkeys@handle@boolean[2]{% ##1: if name, ##2: value
+ \expandafter \show \csname if##1\endcsname
+ }%
+ \edef\esf@tmp@path{\pgfkeyscurrentpath}%
+ \pgfkeysalso{\esf@tmp@path}%
+ \endgroup
+ },
+ .show boolean/.value forbidden,
+}
+
+\newcommand{\AppendToOptionsList}[3]{% #1: macro to append to, #2: key, #3: value
+ \ifdefvoid#1%
+ {}%
+ {\appto#1{, }}%
+ \eappto#1{#2}%
+ \ifx \pgfkeysnovalue #3\relax
+ % do nothing
+ \else
+ \appto#1{={#3}}%
+ \fi
+}
+
+\newcommand{\strippath}[1]{%
+ \expandafter\strippath@do#1/\pgfeov
+}
+\def\strippath@do#1/#2\pgfeov{%
+ \if\relax\detokenize{#2}\relax
+ #1%
+ \else
+ \strippath@do#2\pgfeov
+ \fi
+}
+
+
+% ========== other helper ==========
+
+\newcommand{\IfEnvironmentExistsOrIsEmpty}[1]{% #1: environment name, #2: then block, #3: else block
+ \ifstrempty{#1}{%
+ \let\IfEnvironmentExistsOrIsEmpty@do=\@firstoftwo
+ }{\IfEnvironmentExists{#1}{%
+ \let\IfEnvironmentExistsOrIsEmpty@do=\@firstoftwo
+ }{%
+ \let\IfEnvironmentExistsOrIsEmpty@do=\@secondoftwo
+ }}%
+ \IfEnvironmentExistsOrIsEmpty@do
+}
+
+\newcommand{\IfEnvironmentExists}[3]{% #1: environment name, #2: then block, #3: else block
+ \ifcsmacro{#1}{%
+ % I am not checking the existence of end#1 because for tabularx that is \relax.
+ #2%
+ }{%
+ #3%
+ }%
+}
+
+
+% \patchcmd replaces the first occurence only.
+% therefore I am recursing as long as patching was successful
+% to make sure that each occurrence was replaced.
+% it is important to replace with \textunderscore instead of \_
+% because otherwise it would replace \_ by \\_ and loop infinitely.
+\newcommand{\PatchUnderscore}[1]{% #1: macro
+ \patchcmd{#1}
+ {_}{\textunderscore}
+ {\PatchUnderscore#1}{}%
+}
+
+
+% ========== object ==========
+
+\newif\ifobject@warnotherenv
+\newif\ifobject@warnnolabel
+\newif\ifobject@warnnocaption
+\newif\ifobject@showenv
+
+% ---------- set object options ----------
+
+\newrobustcmd{\objectset}{% #1: options
+ \@ifnextchar [%]
+ \objectset@appendtostyles
+ \objectset@direct
+}
+
+\newcommand{\objectset@direct}{% #1: options
+ \pgfqkeys{/object}%
+}
+
+\newcommand{\GobbleLeadingSpaceIn}[1]{\edef#1{\expandafter\@firstofone#1}}
+
+\def\objectset@appendtostyles[#1]#2{% #1: style #2: options
+ \pgfkeyssetvalue{/object.check/env}{}%
+ \pgfqkeys{/object.check}{%
+ .esf@exec on unknown=\AppendOptionToObjectStyleGroups{#1},
+ #2%
+ }%
+}
+
+% ---------- check object options ----------
+
+\newcommand{\CheckObjectOption}[2]{% #1: key, #2: value, #3: executed if valid
+ % if #3 is *not* executed an error message is printed
+ %
+ % It is important to reset it at the beginning
+ % because the \Check* macros do not expand any
+ % of the two arguments if they throw an error.
+ \let\CheckObjectOption@handleArg=\@gobble
+ \esf@ifpgfkeyexists{/object/#1}{%
+ \esf@ifpgfkeyrequiresvalue{/object/#1}{%
+ \ifx \pgfkeysnovalue #2\relax
+ \PackageError{easyfloats}{The key '#1' requires a value. I am going to ignore this key}{}%
+ \else
+ \let\CheckObjectOption@handleArg=\@firstofone
+ \fi
+ }{%
+ \let\CheckObjectOption@handleArg=\@firstofone
+ }%
+ }{\CheckObjectGraphicOption{#1}{#2}{%
+ \let\CheckObjectOption@handleArg=\@firstofone
+ }{\CheckObjectEnvArgs{#1}{#2}{%
+ \let\CheckObjectOption@handleArg=\@firstofone
+ }{%
+ \PackageError{easyfloats}{I do not know the key '#1' and I am going to ignore it. Perhaps you misspelled it}{}%
+ }}}%
+ \CheckObjectOption@handleArg
+}
+
+
+% ---------- available object options ----------
+
+\pgfqkeys{/object}{%
+ %
+ % ------- mandatory -------
+ %
+ % The environment to use (figure|table)
+ % An empty value is allowed for longtable
+ % but that is intentionally left undocumented.
+ type/.initial,
+ type/.value required,
+ type/.code=\@ifundefined{fps@#1}
+ {\PackageError{easyfloats}{Invalid value for key 'type': '#1'. I am going to ignore this option}{}}
+ {\pgfkeyssetvalue{/object/type}{#1}},
+ %
+ % Where to place the caption, see float package (plain|plaintop|ruled|boxed)
+ % If empty do *not* perform a restyle.
+ % This is ignored if type is empty.
+ float style/.initial=,
+ float style/.value required,
+ %
+ %
+ % ------- recommended -------
+ %
+ % The caption displayed above or below the content (depending on the float style).
+ % There is *no* dot added automatically behind it.
+ caption/.initial,
+ caption/.value required,
+ caption/.prefix code={%
+ \esf@ifpgfkeyhasvalue{/object/caption}{%
+ \PackageWarning{easyfloats}{Overwriting existing value for caption with "#1"}%
+ }{%
+ % ok
+ }%
+ },
+ %
+ % A label which can be referenced by e.g. \ref{label} or \refpage{label}
+ label/.initial,
+ label/.value required,
+ label/.prefix code={%
+ \esf@ifpgfkeyhasvalue{/object/label}{%
+ \PackageWarning{easyfloats}{Overwriting existing value for label with "#1"}%
+ }{%
+ % ok
+ }%
+ },
+ %
+ %
+ % ------- optional -------
+ %
+ % Where to put the float on the page ([htbp]+ | H | <empty>)
+ % (empty means to *not* pass the optional placement argument to the foating environment)
+ % This is more powerful than \floatplacement because it allows H.
+ placement/.initial=,
+ placement/.value required,
+ %
+ % The caption used in the list of figures/list of tables
+ list caption/.initial,
+ list caption/.value required,
+ %
+ % An addition to the caption (at the object only, not in a list)
+ details/.initial=,
+ details/.value required,
+ %
+ details sep/.initial=.\space,
+ details sep/.value required,
+ %
+ % An additional label which can be used synonymously to label.
+ % If this key is given several times, only the last one will have an effect.
+ add label/.initial,
+ add label/.value required,
+ %
+ % TeX code which is inserted at the beginning of the type environment
+ align/.initial=\centering,
+ align/.value required,
+ %
+ % TeX code which is inserted at the beginning of the type environment (before align)
+ exec/.initial=,
+ exec/.value required,
+ exec +/.code=\esf@pgfkeysvalueappend{/object/exec}{#1},
+ exec +/.value required,
+ exec+/.forward to=/object/exec +,
+ exec+/.value required,
+ %
+ % An additional inner environment to wrap the content in like tabular, tabularx, tikzpicture
+ env/.code=\IfEnvironmentExistsOrIsEmpty{#1}
+ {\pgfkeyssetvalue{/object/env}{#1}}%
+ {\PackageError{easyfloats}{Environment #1 which you passed to the key 'env' does not exist}{}},
+ env/.value required,
+ env=,
+ %
+ % Specify that this object contains subobjects.
+ % This means that if env has a non-empty value
+ % this value is used for subobject env
+ % and env is set to an empty value.
+ sub/.forward to=/object/contains subobjects,
+ contains subobjects/.is if = @containssubobjects,
+ %
+ %
+ % ------- tables -------
+ % first head and last foot are optional but if they are given they have priority.
+ % head and foot always need to have a value even if it's just empty.
+ %
+ first head/.initial,
+ first head/.value required,
+ %
+ head/.initial=,
+ head/.value required,
+ %
+ foot/.initial=,
+ foot/.value required,
+ %
+ last foot/.initial,
+ last foot/.value required,
+ %
+ table head style/.code=\pgfkeysdef{/object/table head}{\pgfqkeys{/object}{#1}},
+ table head style/.value required,
+ table head style={%
+ first head =
+ \toprule
+ #1 \\
+ \midrule,
+ head =
+ #1 \\
+ \midrule,
+ foot =
+ \midrule
+ \ifx\object@tableBreakText\@empty
+ \else
+ \multicolumn{\the\LT@cols}{r@\relax}{\object@tableBreakText}%
+ \fi,
+ last foot =
+ \bottomrule,
+ },
+ %
+ % text displayed in the non-last foot of a table
+ table break text/.code=\def\object@tableBreakText{#1},
+ table break text/.value required,
+ table break text = (to be continued),
+ %
+ %
+ % ------- warnings -------
+ %
+ warn no caption/.is if=object@warnnocaption,
+ warn no caption=true,
+ %
+ warn no label/.is if=object@warnnolabel,
+ warn no label=true,
+ %
+ warn other env/.is if=object@warnotherenv,
+ warn other env=false,
+ %
+ %
+ % ------- debugging -------
+ %
+ show env args/.is if=object@showenv,
+ show env args=false,
+ %
+ %
+ % ------- subobject -------
+ % .value required is code duplication but
+ % it is necessary for \esf@ifpgfkeyrequiresvalue.
+ % It also changes the error message to report
+ % this key instead of the linked key.
+ %
+ subobject linewidth/.forward to=/subobject/linewidth,
+ subobject linewidth/.value required,
+ subobject env/.forward to=/subobject/env,
+ subobject env/.value required,
+ %
+ subcaptionbox/.forward to=/subobject/subcaptionbox,
+ subcaptionbox/.value forbidden,
+ subpage/.forward to=/subobject/subpage,
+ subpage/.value forbidden,
+ %
+ subcaptionbox inner pos/.forward to=/subobject/subcaptionbox inner pos,
+ subcaptionbox inner pos/.value required,
+ %
+ subpage inner pos/.forward to=/subobject/subpage inner pos,
+ subpage inner pos/.value required,
+ subpage height/.forward to=/subobject/subpage height,
+ subpage height/.value required,
+ subpage outer pos/.forward to=/subobject/subpage outer pos,
+ subpage outer pos/.value required,
+ subpage align/.forward to=/subobject/subpage align,
+ subpage align/.value required,
+ %
+ subobject sep/.forward to=/subobject/sep,
+ subobject sep/.value required,
+ %
+ subobject hor/.forward to=/subobject/hor,
+ %subobject hor/ value is allowed but not necessary
+ subobject hor sep/.forward to=/subobject/hor sep,
+ subobject hor sep/.value required,
+ subobject hor sep+/.forward to=/subobject/hor sep+,
+ subobject hor sep+/.value required,
+ subobject hor sep +/.forward to=/subobject/hor sep +,
+ subobject hor sep +/.value required,
+ %
+ subobject ver/.forward to=/subobject/ver,
+ %subobject ver/ value is allowed but not necessary
+ subobject ver sep/.forward to=/subobject/ver sep,
+ subobject ver sep/.value required,
+ subobject ver sep+/.forward to=/subobject/ver sep+,
+ subobject ver sep+/.value required,
+ subobject ver sep +/.forward to=/subobject/ver sep +,
+ subobject ver sep +/.value required,
+ %
+ subobject exec/.forward to=/subobject/exec,
+ subobject exec/.value required,
+ subobject exec+/.forward to=/subobject/exec+,
+ subobject exec+/.value required,
+ subobject exec +/.forward to=/subobject/exec +,
+ subobject exec +/.value required,
+ %
+ subobject warn no caption/.forward to=/subobject/warn no caption,
+ %value is allowed but not necessary
+ subobject warn no label/.forward to=/subobject/warn no label,
+ %value is allowed but not necessary
+ %
+ %
+ % ------- unknown handler / key patterns -------
+ %
+ % Two key patterns are defined to automatically pass arguments to the environments specified by the env option if the environment name matches.
+ % `<envname> arg` is for a single mandatory (undelimited) argument. It is wrapped in braces.
+ % `<envname> args` is not wrapped in braces and can be used for several arguments or an optional argument.
+ % It cannot be used for a single mandatory argument because \pgfkeys strips several levels of braces.
+ .unknown/.code={%
+ \ObjectProcessKeyPattern{\pgfkeyscurrentname}{#1}{%
+ \pgfkeysgetvalue{/object/.really unknown/.@cmd}{\esf@tmp@err}%
+ \esf@tmp@err#1\pgfeov
+ }%
+ },
+ % Setting an unknown key handler shall not override env args but set an additional unknown handler.
+ .unknown/.code/.code={%
+ \pgfkeysdef{/object/.really unknown}{#1}%
+ },
+ .really unknown/.code={%
+ \edef\do{\noexpand\pgfkeys{/errors/unknown key={\pgfkeyscurrentkey}{\unexpanded{#1}}}}%
+ \do
+ },
+}
+
+\pgfqkeys{/object.check}{%
+ env/.initial=,
+ env/.code={%
+ \ifx \pgfkeysnovalue #1\relax
+ \PackageError{easyfloats}{The key 'env' requires a value. I am going to ignore this key}{}%
+ \else
+ \IfEnvironmentExistsOrIsEmpty{#1}{%
+ % set env so that I can use the value to check args
+ \pgfkeyssetvalue{/object.check/env}{#1}%
+ % call the unknown handler which appends it to the style
+ % unlike '/errors/unknown key' '.unknown' does not take the key as argument
+ % but it may require \pgfkeyscurrentpath and \pgfkeyscurrentname to be set
+ \pgfkeys@split@path
+ \pgfkeysvalueof{\pgfkeyscurrentpath/.unknown/.@cmd}#1\pgfeov
+ }{%
+ \PackageError{easyfloats}{Environment #1 which you passed to the key 'env' does not exist}{}%
+ }%
+ \fi
+ },
+ type/.code={%
+ % set type so that I can use the value in \NewObjectStyleGroup
+ \pgfkeyssetvalue{/object.check/type}{#1}%
+ % call the unknown handler which appends it to the style
+ % unlike '/errors/unknown key' '.unknown' does not take the key as argument
+ % but it may require \pgfkeyscurrentpath and \pgfkeyscurrentname to be set
+ \pgfkeys@split@path
+ % Without the braces I got "Undefined control sequence. [...] \pgfeov"
+ % \pgfkeys strips several levels of braces around an argument.
+ % (I have already experienced that while experimenting with <env> args.
+ % That is the reason why I defined two separate keys arg and args.)
+ % I am assuming that because of that the \pgfeov ended the argument of some
+ % pgfkeys internal macro too early causing undefined behavior.
+ % I am preventing this from happening by hiding \pgfeov inside of braces
+ % which are inside of the argument so they won't get stripped.
+ % I put \@firstofone in front of them so that they do not function as a group.
+ \@firstofone{\pgfkeysvalueof{\pgfkeyscurrentpath/.unknown/.@cmd}#1\pgfeov}%
+ },
+}
+
+% ---------- process key patterns ----------
+
+\newcommand{\ObjectProcessKeyPattern}[2]{% #1: key, #2: value, #3: else
+ \expandafter\ObjectProcessKeyPattern@expandedkey\expandafter{#1}{#2}%
+}
+
+\newcommand{\ObjectProcessKeyPattern@expandedkey}[2]{% #1: key, #2: value, #3: else
+ \ObjectProcessGraphicOption@expandedkey{#1}{#2}{%
+ \@gobble
+ }{%
+ \ObjectProcessArgs@expandedkey{#1}{#2}\relax
+ }%
+}
+
+% ---------- process graphic options ----------
+
+\ifesf@loadgraphics
+
+% do not confuse this with \CheckGraphicobjectOption
+\newcommand{\CheckObjectGraphicOption}[2]{% #1: key, #2: value
+ % #3: executed if valid, #4: executed if *not* a graphic option
+ % Please note that if the option looks like a graphic option
+ % but is not valid neither #3 nor #4 is executed.
+ % Instead an appropriate error message is printed.
+ \begingroup
+ \let\ObjectCheckGraphicOption@aftergroup=\@gobbletwo
+ \renewcommand{\AppendToOptionsList}[3]{%
+ \let\ObjectCheckGraphicOption@aftergroup=\@firstoftwo
+ }%
+ \ObjectProcessGraphicOption{#1}{#2}{%
+ \let\ObjectCheckGraphicOption@aftergroup=\@secondoftwo
+ }%
+ \expandafter
+ \endgroup
+ \ObjectCheckGraphicOption@aftergroup
+}
+
+\newcommand{\ObjectProcessGraphicOption}[2]{% #1: key, #2: value
+ % #3: executed if *not* a graphic option
+ \expandafter\ObjectProcessGraphicOption@expandedkey\expandafter{#1}{#2}\relax
+}
+\newcommand{\ObjectProcessGraphicOption@expandedkey}[2]{% #1: key, #2: value
+ % #3: executed if graphic option, #4: executed if *not* a graphic option
+ \ObjectProcessGraphicOption@checkoption#1graphic \pgfeov{#2}%
+}
+\long\def\ObjectProcessGraphicOption@checkoption#1graphic #2\pgfeov#3{% #1: empty if graphic option, #2: key, #3: value
+ % #4: executed if graphic option, #5: executed if *not* a graphic option
+ \def\esf@tmp@arg{#1}%
+ \ifx \esf@tmp@arg \@empty
+ \edef\esf@opgoco@key{\StripGraphicSpace#2\pgfeov}%
+ \CheckGraphicobjectOption{\esf@opgoco@key}{#3}{%
+ \AppendGraphicobjectOption{\esf@opgoco@key}{#3}%
+ }%
+ \expandafter \@firstoftwo
+ \else
+ \expandafter \@secondoftwo
+ \fi
+}
+
+\def\StripGraphicSpace#1graphic \pgfeov{#1}
+
+\else %\ifesf@loadgraphics
+
+\newcommand{\CheckObjectGraphicOption}[2]{% #1: key, #2: value
+ % #3: executed if valid, #4: executed if *not* a graphic option
+ \@secondoftwo
+}
+
+\newcommand{\ObjectProcessGraphicOption@expandedkey}[2]{% #1: key, #2: value
+ % #3: executed if graphic option, #4: executed if *not* a graphic option
+ \@secondoftwo
+}
+
+\fi %\ifesf@loadgraphics
+
+% ---------- process env args ----------
+
+\newcommand{\@object@envkey}{/object/env}
+\newcommand{\CheckObjectEnvArgs}[2]{% #1: key, #2: value
+ % #3: executed if valid, #4: executed if *not* an <env> arg
+ % Please note that if the option looks like an <env> arg
+ % but is not valid neither #3 nor #4 is executed.
+ % Instead an appropriate error message is printed.
+ \begingroup
+ \edef\ObjectCheckArgs@key{#1}%
+ \let\ObjectCheckArgs@aftergroup=\@gobbletwo
+ \pgfkeysgetvalue{/object.check/env}{\esf@tmp@env}%
+ \pgfkeys{\@object@envkey/.expand once=\esf@tmp@env}%
+ \renewcommand{\ObjectDefineEnvargs}[2]{% ##1: env name, ##2: arguments
+ \let\ObjectCheckArgs@aftergroup=\@firstoftwo
+ }%
+ \ObjectProcessArgs{\ObjectCheckArgs@key}{#2}{%
+ \let\ObjectCheckArgs@aftergroup=\@secondoftwo
+ }%
+ \expandafter
+ \endgroup
+ \ObjectCheckArgs@aftergroup
+}
+
+
+\newcommand{\ObjectProcessArgs}[2]{% #1: key, #2: value, #3: else
+ \expandafter\ObjectProcessArgs@expandedkey\expandafter{#1}{#2}\relax
+}
+
+\newcommand{\ObjectProcessArgs@expandedkey}[2]{% #1: key, #2: value, #3: then, #4: else
+ \IfEndsOnSpacePlus{#1}{%
+ \let\ObjectProcessArgs@csdef=\csappto
+ \expandafter\ObjectProcessArgs@checkArgs\expandafter{\StripSpacePlus#1\pgfeov}{#2}%
+ }{\IfEndsOnPlus{#1}{%
+ \let\ObjectProcessArgs@csdef=\csappto
+ \expandafter\ObjectProcessArgs@checkArgs\expandafter{\StripPlus#1\pgfeov}{#2}%
+ }{%
+ \let\ObjectProcessArgs@csdef=\csdef
+ \ObjectProcessArgs@checkArgs{#1}{#2}%
+ }}%
+}
+
+\newrobustcmd{\IfEndsOn}[2]{% #1: end character, #2: text
+ \def\IfEndsOn@do##1#1##2\pgfeov{%
+ \ifstrequal{##2}{}{%
+ \let\do=\@secondoftwo
+ }{\ifstrequal{##2}{#1}{%
+ \let\do=\@firstoftwo
+ }{%
+ \def\do{\IfEndsOn@do##2\pgfeov}%
+ }}%
+ \do
+ }%
+ \IfEndsOn@do#2#1\pgfeov
+}
+\newcommand{\IfEndsOnPlus}{\IfEndsOn+}
+\newcommand{\IfEndsOnSpacePlus}{\IfEndsOn{ +}}
+
+\def\StripSpacePlus#1 +\pgfeov{#1}
+\def\StripPlus#1+\pgfeov{#1}
+
+
+\newcommand{\ObjectProcessArgs@checkArgs}[2]{% #1: key, #2: value, #3: then, #4: else
+ \ObjectProcessArgs@do#1 args\pgfeov{#2}%
+}
+\long\def\ObjectProcessArgs@do#1 arg#2\pgfeov#3{% #1: env name, #2: test value, #3: arguments, #4: then, #5: else
+ \let\ObjectProcessArgs@do@after=\@firstoftwo
+ \ifstrequal{#2}{ args}{%
+ \ObjectDefineEnvargsCheckName{#1}{{#3}}%
+ }{\ifstrequal{#2}{s args}{%
+ \ObjectDefineEnvargsCheckName{#1}{#3}%
+ }{\ifstrequal{#2}{s}{%
+ \ifstrequal{#1}{arg}{%
+ \ObjectDefineEnvargsAuto{{#3}}%
+ }{\ifstrequal{#1}{args}{%
+ \ObjectDefineEnvargsAuto{#3}%
+ }{%
+ \let\ObjectProcessArgs@do@after=\@secondoftwo
+ }}%
+ }{%
+ \let\ObjectProcessArgs@do@after=\@secondoftwo
+ }}}%
+ \ObjectProcessArgs@do@after
+}
+\newcommand{\ObjectDefineEnvargsCheckName}[2]{% #1: env name, #2: arguments
+ \ifobject@directkeys
+ \pgfkeysgetvalue{\@object@envkey}{\esf@tmp@env}%
+ \ifdefvoid{\esf@tmp@env}{%
+ }{\ifdefstring{\esf@tmp@env}{#1}{%
+ }{%
+ \ifobject@warnotherenv
+ \PackageWarning{easyfloats}{Defining 'arg(s)' for #1 but 'env=\esf@tmp@env'}%
+ \fi
+ }}%
+ \fi
+ \IfEnvironmentExists{#1}
+ {\ObjectDefineEnvargs{#1}{#2}}
+ {\PackageError{easyfloats}{Environment #1 for which you set 'arg(s)' does not exist}{}}%
+}
+\newcommand{\ObjectDefineEnvargsAuto}[1]{% #1: arguments
+ \pgfkeysgetvalue{\@object@envkey}{\esf@tmp@env}%
+ \ifx \esf@tmp@env \@empty
+ \PackageError{easyfloats}{'env' for 'arg(s)' is not defined}{}%
+ \else
+ \ObjectDefineEnvargs{\esf@tmp@env}{#1}%
+ \fi
+}
+\newcommand{\ObjectDefineEnvargs}[2]{% #1: env name, #2: arguments
+ \ObjectProcessArgs@csdef{object@#1 env@args}{#2}%
+}
+
+
+\newcommand{\ObjectAppendEnvargs}[1]{% #1: macro
+ \ifcsname object@\pgfkeysvalueof{\@object@envkey} env@args\endcsname
+ \eappto#1{\csexpandonce{object@\pgfkeysvalueof{\@object@envkey} env@args}}%
+ \fi
+}
+
+
+% ---------- object environment ----------
+
+\newcommand{\object@head}{}
+\newcommand{\object@foot}{}
+\newcommand{\object@restorestandardfloats}{}
+
+\newcommand{\object@label}[1]{%
+ \pgfkeys{/object/label={#1}}%
+}%
+\newcommand{\object@caption}[2][\pgfkeysnovalue]{%
+ \pgfkeys{/object/caption={#2}}%
+ \ifx \pgfkeysnovalue #1\relax
+ \pgfkeys{/object/list caption={#2}}%
+ \else
+ \pgfkeys{/object/list caption={#1}}%
+ \fi
+}
+\newcommand{\object@longtable@label}[1]{%
+ \ObjectDefineEnvargs{longtable}{\label{#1}}%
+}%
+\newcommand{\object@longtable@caption}[2][\pgfkeysnovalue]{%
+ \ifx \pgfkeysnovalue #1\relax
+ \ObjectDefineEnvargs{longtable}{\caption{#2}}%
+ \else
+ \ObjectDefineEnvargs{longtable}{\caption[#1]{#2}}%
+ \fi
+ \def\object@longtable@caption@sep{\ObjectDefineEnvargs{longtable}{\\}}%
+}
+
+\newenvironment{object}[1]{% #1: options
+ \if@inobject
+ \PackageError{easyfloats}{object environment may not be nested}{Did you mean to use the subobject environment instead?}%
+ \fi
+ \@inobjecttrue
+ %
+ \object@restorestandardfloats
+ %
+ \object@hook
+ \ifobject@isgraphic
+ \object@graphic@hook
+ \global\object@isgraphicfalse
+ \fi
+ %
+ % ---------- options ---------
+ %
+ \pgfqkeys{/object}{%
+ #1,
+ %
+ % ------- mandatory -------
+ type/.esf@mandatory=It should be the name of a floating environment like figure or table,
+ float style/.esf@mandatory={It should be one of plain, plaintop, ruled or boxed. See float package},
+ env/.esf@mandatory=It should be the name of an environment like tabular or empty,
+ }%
+ %
+ % ------- contains subobjects -------
+ \if@containssubobjects
+ \pgfkeysgetvalue{/object/env}{\esf@tmp@env}%
+ \ifx \esf@tmp@env \@empty
+ \else
+ \pgfkeys{/subobject/env/.expand once=\esf@tmp@env}%
+ \pgfkeyssetvalue{/object/env}{}%
+ \fi
+ \fi
+ %
+ % ---------- prepare ---------
+ %
+ \pgfkeysgetvalue{/object/env}{\esf@tmp@env}%
+ \ifdefstring\esf@tmp@env{longtable}{%
+ \object@longtable@prepare
+ }{%
+ \esf@ifpgfkeyhasvalue{/object/first head}{%
+ \pgfkeysgetvalue{/object/first head}{\object@head}%
+ }{%
+ \pgfkeysgetvalue{/object/head}{\object@head}%
+ }%
+ \esf@ifpgfkeyhasvalue{/object/last foot}{%
+ \pgfkeysgetvalue{/object/last foot}{\object@foot}%
+ }{%
+ \pgfkeysgetvalue{/object/foot}{\object@foot}%
+ }%
+ }%
+ %
+ \pgfkeysgetvalue{/object/type}{\esf@tmp@type}%
+ \ifx\esf@tmp@type\@empty
+ \let\object@floatenv@begin=\relax
+ \let\object@floatenv@end=\relax
+ \else
+ \pgfkeysgetvalue{/object/float style}{\esf@tmp@floatstyle}%
+ \ifx \esf@tmp@floatstyle \@empty
+ \else
+ \floatstyle{\esf@tmp@floatstyle}%
+ \restylefloat{\esf@tmp@type}%
+ \fi
+ \edef\object@floatenv@begin{\expandonce{\csname\esf@tmp@type\endcsname}}%
+ \edef\object@floatenv@end{\expandonce{\csname end\esf@tmp@type\endcsname}}%
+ \pgfkeysgetvalue{/object/placement}{\esf@tmp@placement}%
+ \ifx \esf@tmp@placement \@empty
+ % do nothing
+ \else
+ \eappto\object@floatenv@begin{[\esf@tmp@placement]}%
+ \fi
+ \fi
+ %
+ \pgfkeysgetvalue{/object/details}{\object@details}%
+ \ifx \object@details \@empty
+ % do nothing
+ \else
+ \preto\object@details{\pgfkeysvalueof{/object/details sep}}%
+ \fi
+ %
+ \pgfkeysgetvalue{/object/env}{\esf@tmp@env}%
+ \ifx \esf@tmp@env \@empty
+ % if you change this remember to update \object@lookahead@beforesubobject
+ \def\object@innerenv@begin{\object@head\ignorespaces}%
+ \def\object@innerenv@end{\unskip\object@foot}%
+ \else
+ \edef\object@innerenv@begin{\expandonce{\csname\esf@tmp@env\endcsname}}%
+ \edef\object@innerenv@end{\expandonce{\csname end\esf@tmp@env\endcsname}}%
+ \ObjectAppendEnvargs{\object@innerenv@begin}%
+ \eappto\object@innerenv@begin{\expandonce{\object@head}}%
+ \epreto\object@innerenv@end{\expandonce{\object@foot}}%
+ \let\object@lookahead@begin=\object@innerenv@begin
+ \ifobject@showenv
+ \show\object@innerenv@begin
+ \fi
+ \let\object@innerenv@begin=\object@lookahead
+ \fi
+ %
+ \global \@firstsubobjecttrue
+ %
+ % ---------- execute ---------
+ %
+ \object@floatenv@begin
+ \let\esf@original@label=\label
+ \let\esf@original@caption=\caption
+ \let\label=\object@label
+ \let\caption=\object@caption
+ \pgfkeysvalueof{/object/exec}%
+ \pgfkeysvalueof{/object/align}%
+ \object@innerenv@begin
+}{%
+ \object@innerenv@end
+ \if@containssubobjects
+ \if@firstsubobject
+ \PackageWarning{easyfloats}{'contains subobjects' is true but the object does not contain any subobjects.}%
+ \fi
+ \fi
+ \let\label=\esf@original@label
+ \let\caption=\esf@original@caption
+ \object@processCaptionAndLabel
+ \object@floatenv@end
+}
+
+\newcommand{\object@processCaptionAndLabel}{%
+ % position of caption (above/below) is handled by float package (see float style)
+ \esf@ifpgfkeyhasvalue{/object/caption}{%
+ \esf@ifpgfkeyhasvalue{/object/list caption}%
+ {\pgfkeysgetvalue{/object/list caption}{\esf@tmp@caption@short}}%
+ {\pgfkeysgetvalue{/object/caption}{\esf@tmp@caption@short}}%
+ \caption[\esf@tmp@caption@short]{\pgfkeysvalueof{/object/caption}\object@details}%
+ }{%
+ \ifobject@warnnocaption
+ \PackageWarning{easyfloats}{%
+ No caption given.
+ This object will not show up in the list of figures/tables/whatsoever.
+ If captions for subfigures are given they will be placed incorrectly in the list of figures.
+ If you are using hyperref links to this figure may turn out wrong.
+ This warning occured%
+ }%
+ \fi
+ % Generate an anchor for a \label.
+ % \phantomcaption is defined in the caption-package but
+ % documented in subcaption for the subfigure environment.
+ % It appears that here (without a subfigure but within a figure)
+ % references are output correctly but links created by hyperref
+ % which should be pointing to this object point to the previous caption.
+ \phantomcaption
+ }%
+ % ------- label -------
+ \esf@ifpgfkeyhasvalue{/object/label}{%
+ \label{\pgfkeysvalueof{/object/label}}%
+ }{%
+ \ifobject@warnnolabel
+ \PackageWarning{easyfloats}{%
+ No label given.
+ Without a label you cannot reference this object.
+ This warning occured%
+ }%
+ \fi
+ }%
+ \esf@ifpgfkeyhasvalue{/object/add label}%
+ {\label{\pgfkeysvalueof{/object/add label}}}%
+ {}%
+}
+
+\newcommand{\object@longtable@prepare}{%
+ \pgfkeyssetvalue{/object/type}{}%
+ \pgfkeyssetvalue{/object/align}{}%
+ \let\object@label=\label
+ \let\object@caption=\caption
+ \let\ObjectProcessArgs@csdef=\csappto
+ %
+ \let\esf@original@label=\label
+ \let\esf@original@caption=\caption
+ \let\label=\object@longtable@label
+ \let\caption=\object@longtable@caption
+ \let\object@longtable@caption@sep=\relax
+ % it seems possible to have a label without a caption in a longtable
+ % which actually makes sense because \caption may appear several times
+ % so it makes sense to increase the counter somewhere else.
+ \let\phantomcaption=\relax
+ \object@processCaptionAndLabel
+ \let\object@processCaptionAndLabel=\relax
+ \object@longtable@caption@sep
+ \let\label=\esf@original@label
+ \let\caption=\esf@original@caption
+ %
+ \esf@ifpgfkeyhasvalue{/object/first head}{%
+ \ObjectDefineEnvargs{longtable}{\pgfkeysvalueof{/object/first head}}%
+ }{%
+ \ObjectDefineEnvargs{longtable}{\pgfkeysvalueof{/object/head}}%
+ }%
+ \ObjectDefineEnvargs{longtable}{%
+ \endfirsthead
+ \pgfkeysvalueof{/object/head}%
+ \endhead
+ \pgfkeysvalueof{/object/foot}%
+ \endfoot
+ }%
+ \esf@ifpgfkeyhasvalue{/object/last foot}{%
+ \ObjectDefineEnvargs{longtable}{\pgfkeysvalueof{/object/last foot}}%
+ }{%
+ \ObjectDefineEnvargs{longtable}{\pgfkeysvalueof{/object/foot}}%
+ }%
+ \ObjectDefineEnvargs{longtable}{%
+ \endlastfoot
+ }%
+}
+
+
+% ---------- lookahead for subobjects ----------
+
+\newcommand{\object@lookahead@nosubobject}{%
+ \object@lookahead@begin
+}
+\newcommand{\object@lookahead@beforesubobject}{%
+ \PackageWarning{easyfloats}{It seems you have forgotten to specify 'contains subobjects'. I am using the value of 'env' for the subobjects instead of for \@currenvir.}%
+ \pgfkeysgetvalue{/object/env}{\esf@tmp@env}%
+ \pgfkeys{/subobject/env/.expand once=\esf@tmp@env}%
+ \pgfkeyssetvalue{/object/env}{}%
+ \let\object@innerenv@end=\unskip
+ %\ignorespaces unnecessary because I just checked
+ %that the next token is the start of a subobject
+}
+
+\newcommand{\object@lookahead}{%
+ \futurelet \next \object@lookahead@checknext
+}
+\newcommand{\object@lookahead@checknext}{%
+ \ifx \next \@implicitspace
+ \let\object@lookahead@gobble=\@gobblespace
+ \let\object@lookahead@do=\object@lookahead
+ \else\ifx \next \par
+ \let\object@lookahead@gobble=\@gobble
+ \let\object@lookahead@do=\object@lookahead
+ \else\ifx \next \begin
+ \let\object@lookahead@gobble=\@empty
+ \let\object@lookahead@do=\object@lookahead@checkbegin
+ \else\ifx \next \includegraphicsubobject
+ \let\object@lookahead@gobble=\@empty
+ \let\object@lookahead@do=\object@lookahead@beforesubobject
+ \else
+ \let\object@lookahead@gobble=\@empty
+ \let\object@lookahead@do=\object@lookahead@nosubobject
+ \fi \fi \fi \fi
+ \expandafter \object@lookahead@do \object@lookahead@gobble
+}
+\newcommand{\object@lookahead@checkbegin}[2]{% #1: \begin, #2: environment name
+ \ifstrequal{#2}{subobject}
+ \object@lookahead@beforesubobject
+ \object@lookahead@nosubobject
+ #1{#2}%
+}
+
+\@firstofone{\let\@implicitspace= }
+\@firstofone{\def\@gobblespace} {}
+
+
+% ========== object styles ==========
+
+\newcommand{\IfObjectStyleExists}[1]{% #1: style name or group name, #2: then block, #3: else block
+ \ifcsmacro{object@style@#1}%
+}
+\newcommand{\IfObjectStyleNotGroup}[1]{% #1: style name, #2: then block, #3: else block
+ \IfObjectStyleExists{#1}
+ {\edef\esf@tmp@do{\ifcsstring{object@stylegroup@#1}{{#1}}}\esf@tmp@do}%
+ \@secondoftwo
+}
+
+\newcommand{\objectstyle@init}[1]{% #1: style name or group name
+ \expandafter \newcommand \csname object@style@#1\endcsname{/utils/exec=\object@directkeysfalse}%
+ \expandafter \newcommand \csname object@stylegroup@#1\endcsname{}%
+}
+
+\newrobustcmd{\AddObjectStyleToGroup}[2]{% #1: group name, #2: style name
+ \IfObjectStyleExists{#1}{%
+ \IfObjectStyleNotGroup{#2}{%
+ \AddObjectStyleToGroup@do{#1}{#2}%
+ }{%
+ \PackageError{easyfloats}{Undefined object style: #2}{In this case you cannot use a style group instead of a group.}%
+ }}{%
+ \PackageError{easyfloats}{Undefined object style group: #1}{}%
+ }%
+}
+\newrobustcmd{\AddObjectStyleToGroup@do}[2]{% #1: group name, #2: style name
+ \expandafter\eappto\csname object@stylegroup@#1\endcsname{{#2}}%
+}
+\newrobustcmd{\ShowObjectStylesInGroup}[1]{%
+ \expandafter\show\csname object@stylegroup@#1\endcsname
+}
+
+\newcommand{\AppendOptionToObjectStyleGroups}[3]{% #1: list of style groups, #2: key, #3: value
+ \CheckObjectOption{#2}{#3}{%
+ \@for\esf@aotosg@group:=#1\do{%
+ \GobbleLeadingSpaceIn\esf@aotosg@group
+ \AppendOptionToObjectStyleGroup\esf@aotosg@group{#2}{#3}%
+ }%
+ }%
+}
+\newcommand{\AppendOptionToObjectStyleGroup}[3]{% #1: style group, #2: key, #3: value
+ \IfObjectStyleExists{#1}{%
+ \expandafter \let \expandafter \esf@tmp@listofstyles \csname object@stylegroup@#1\endcsname
+ \def\esf@tmp@loop{\@tfor\esf@aotosg@style:=}%
+ \expandafter\esf@tmp@loop\esf@tmp@listofstyles \do {%
+ \AppendOptionToObjectStyle\esf@aotosg@style{#2}{#3}%
+ }%
+ }{%
+ \PackageError{easyfloats}{Undefined object style: '#1'}{}%
+ }%
+}
+\newcommand{\AppendOptionToObjectStyle}[3]{% #1: style, #2: key, #3: value
+ \expandafter\AppendToOptionsList\csname object@style@#1\endcsname{#2}{#3}%
+}
+\newrobustcmd{\ShowObjectStyleOptions}[1]{%
+ \IfObjectStyleNotGroup{#1}
+ {\expandafter\show\csname object@style@#1\endcsname}%
+ {\PackageError{easyfloats}{Undefined object style: '#1'}{}}%
+}
+
+
+% ---------- style groups ----------
+
+\newrobustcmd{\NewObjectStyleGroup}[2]{% #1: group name, #2: list of style names
+ \IfObjectStyleExists{#1}{%
+ \PackageError{easyfloats}{Style or style group with the name '#1' exists already}{}%
+ }{%
+ \objectstyle@init{#1}%
+ \@for\esf@nosg@style:=#2\do{%
+ \GobbleLeadingSpaceIn\esf@nosg@style
+ \AddObjectStyleToGroup{#1}{\esf@nosg@style}%
+ }%
+ }%
+}
+
+% ---------- object styles ----------
+
+\newrobustcmd{\NewObjectStyle}[2]{% #1: name, #2: options
+ \IfObjectStyleExists{#1}{%
+ \PackageError{easyfloats}{Style or style group with the name '#1' exists already}{}%
+ }{%
+ \objectstyle@init{#1}%
+ \AddObjectStyleToGroup@do{#1}{#1}%
+ %hack into \objectset[#1] to retrieve the value of type
+ \pgfkeyssetvalue{/object.check/type}{\pgfkeysnovalue}%
+ \objectset[#1]{#2}%
+ \esf@ifpgfkeyhasvalue{/object.check/type}{%
+ \edef\@do{\noexpand\DeprecateStandardFloatObject{\pgfkeysvalueof{/object.check/type}}{#1object}}%
+ \@do
+ }{%
+ \PackageError{easyfloats}{Missing required key 'type'}%
+ }%
+ %
+ \AddObjectStyleToGroup{all}{#1}%
+ %
+ \newenvironment{#1object}[1]{% #1: options
+ \object{%
+ .esf@also from/.expand once=\csname object@style@#1\endcsname,
+ /utils/exec=\object@directkeystrue,
+ ##1,
+ }%
+ }{%
+ \endobject
+ }%
+ \pgfkeysgetvalue{/object.check/type}{\NewObjectStyle@type}%
+ \edef\@do{\noexpand\AfterPreamble{%
+ \noexpand\IfEnvironmentExists{sub\NewObjectStyle@type}{%
+ \noexpand\PackageInfo{easyfloats}{environment 'sub\NewObjectStyle@type' exists already}%
+ }{\NewObjectStyle@IfCaptionNewEnough{%
+ \noexpand\PackageInfo{easyfloats}{declaring new caption subtype 'sub\NewObjectStyle@type'}%
+ \noexpand\DeclareCaptionSubType{\NewObjectStyle@type}%
+ }{%
+ \noexpand\PackageWarning{easyfloats}{The caption package is too old for me to define the subtype automatically. Please insert `\string\AtBeginDocument{\string\DeclareCaptionSubType{\NewObjectStyle@type}}' before loading this package}%
+ }%
+ }%
+ }}\@do
+ }%
+}
+
+\@ifpackagelater{caption}{2020/08/30}
+ {\let\NewObjectStyle@IfCaptionNewEnough=\@firstoftwo}
+ {\let\NewObjectStyle@IfCaptionNewEnough=\@secondoftwo}
+
+
+\newcommand{\DeprecateStandardFloatObject}[2]{% #1: float environment, #2: alternative object environment
+ \ifesf@warnstandardfloats
+ \ifcsmacro{esf@#1@alternatives}{%
+ \expandafter \appto \csname esf@#1@alternatives\endcsname{ or #2}%
+ }{%
+ \AtBeginDocument{%
+ \csletcs{esf@original#1}{#1}%
+ \expandafter \preto\csname#1\endcsname{\PackageWarning{easyfloats}{In order to profit from the advantages of the easyfloats package please use \csname esf@#1@alternatives\endcsname\space instead}}%
+ }%
+ \expandafter \def \csname esf@#1@alternatives\endcsname{#2}%
+ \ifesf@loadgraphics
+ \ifstrequal{#1}{table}{%
+ % do nothing
+ }{%
+ \expandafter \appto \csname esf@#1@alternatives\endcsname{ or \string\includegraphicobject}%
+ }%
+ \fi
+ \eappto\object@restorestandardfloats{\let\expandonce{\csname #1\endcsname}=\expandonce{\csname esf@original#1\endcsname}}%
+ }%
+ \fi
+}
+
+
+% ---------- default styles ----------
+
+\NewObjectStyleGroup{all}{}
+
+\NewObjectStyle{table}{type=table}
+\NewObjectStyle{figure}{type=figure}
+
+
+% ========== include graphic object ==========
+
+\newif\ifgraphicobject@autocaption
+\newif\ifgraphicobject@autolabel
+\newif\ifgraphicobject@autocaption@strippath
+\newif\ifgraphicobject@autolabel@strippath
+\newif\ifgraphicobject@warnenv
+\newif\ifgraphicobject@noenv
+
+\ifesf@loadgraphics
+
+\newcommand\object@graphic@env{figureobject}
+\newcommand\object@graphic@path{/object}
+\newcommand\object@graphic@options{}
+
+\newrobustcmd{\graphicobjectstyle}[1]{%
+ \IfObjectStyleNotGroup{#1}{%
+ \def\object@graphic@env{#1object}%
+ }{%
+ \PackageError{easyfloats}{Undefined object style: '#1'}{}%
+ }%
+}
+
+% do not confuse this with \CheckObjectGraphicOption
+% this corresponds to \CheckObjectOption
+\newcommand{\CheckGraphicobjectOption}[2]{% #1: key, #2: value, #3: executed if valid
+ % if #3 is *not* executed an error message is printed
+ \let\CheckGraphicobjectOption@handleArg=\@gobble
+ \esf@ifpgfkeyexists{/graphicobject/#1}{%
+ \esf@ifpgfkeyrequiresvalue{/graphicobject/#1}{%
+ \ifx \pgfkeysnovalue #2\relax
+ \PackageError{easyfloats}{The key '#1' requires a value. I am going to ignore this key}{}%
+ \else
+ \let\CheckGraphicobjectOption@handleArg=\@firstofone
+ \fi
+ }{%
+ \let\CheckGraphicobjectOption@handleArg=\@firstofone
+ }%
+ }{\esf@ifkeyvalkeyexists{Gin}{#1}{%
+ \esf@ifkeyvalkeyrequiresvalue{Gin}{#1}{%
+ \ifx \pgfkeysnovalue #2\relax
+ \PackageError{easyfloats}{The key '#1' requires a value. I am going to ignore this key}{}%
+ \else
+ \let\CheckGraphicobjectOption@handleArg=\@firstofone
+ \fi
+ }{%
+ \let\CheckGraphicobjectOption@handleArg=\@firstofone
+ }%
+ }{%
+ \PackageError{easyfloats}{'#1' is not a valid graphic option key}
+ {If you intended to use a graphbox option please make sure that you loaded this package with the option 'graphbox'.}%
+ }}%
+ \CheckGraphicobjectOption@handleArg
+}
+
+\newcommand{\AppendGraphicobjectOption}[2]{% #1: key, #2: value
+ \AppendToOptionsList{\object@graphic@options}{#1}{#2}%
+}
+\newcommand{\includegraphicobject@SetGraphicobjectOption}[2]{% #1: key, #2: value
+ \pgfkeysalso{#1={#2}}%
+}
+
+% available options
+\pgfqkeys{/graphicobject}{%
+ auto caption/.is if=graphicobject@autocaption,
+ auto caption=true,
+ %
+ auto label/.is if=graphicobject@autolabel,
+ auto label=true,
+ %
+ auto caption strip path/.is if=graphicobject@autocaption@strippath,
+ auto caption strip path=false,
+ %
+ auto label strip path/.is if=graphicobject@autolabel@strippath,
+ auto label strip path=false,
+ %
+ warn env/.is if=graphicobject@warnenv,
+ warn env=true,
+ %
+ no env/.is if=graphicobject@noenv,
+ no env=true,
+}
+
+\newrobustcmd{\includegraphicobject}{% [#1: graphicstyle], [#2: options], #3: graphic filename without extension
+ \let\includegraphicobject@after=\@empty
+ \@ifnextchar [%
+ \includegraphicobject@firstarg
+ \includegraphicobject@parseoptions
+}
+\def\includegraphicobject@firstarg[#1]{%
+ \begingroup
+ \@ifnextchar [%
+ {%
+ \begingroup
+ \let\includegraphicobject@after=\endgroup
+ \graphicobjectstyle{#1}%
+ \includegraphicobject@parseoptions
+ }%
+ {%
+ \includegraphicobject@parseoptions[#1]%
+ }%
+}
+
+\newcommand{\includegraphicobject@parseoptions}{% [#1: options], #2: graphic filename without extension
+ % expanding \object@graphic@env before is important for subcaptionbox
+ % otherwise I get the error \begin{subobject} ended by \end{subobject}
+ \@ifnextchar [
+ {\expandafter\includegraphicobject@do\expandafter{\object@graphic@env}}
+ {\expandafter\includegraphicobject@do\expandafter{\object@graphic@env}[]}%
+}
+\def\includegraphicobject@do#1[#2]#3{% #1: environment name, #2: options, #3: graphic filename without extension
+ \global\object@isgraphictrue
+ \begin{#1}{%
+ /utils/exec=\def\object@graphic@options@tmp{}%
+ \let\AppendGraphicobjectOption\includegraphicobject@SetGraphicobjectOption,
+ .unknown/.code={%
+ \esf@ifkeyvalkeyexists{Gin}{\pgfkeyscurrentname}{%
+ \AppendToOptionsList{\object@graphic@options@tmp}{\pgfkeyscurrentname}{##1}%
+ }{%
+ \let\pgfkeys@searchalso@name=\pgfkeyscurrentname
+ \pgfkeysalso{%
+ /graphicobject/\pgfkeys@searchalso@name={##1},
+ }%
+ }%
+ },
+ .esf@also from=\object@graphic@options,
+ #2,
+ /utils/exec=
+ \ifgraphicobject@autocaption
+ \esf@ifpgfkeyhasvalue{\object@graphic@path/caption}{%
+ % do nothing
+ }{%
+ \def\graphicobject@caption{#3}%
+ \PatchUnderscore\graphicobject@caption
+ \ifgraphicobject@autocaption@strippath
+ \protected@edef\graphicobject@caption{\strippath\graphicobject@caption}%
+ \fi
+ \pgfkeyslet{\object@graphic@path/caption}{\graphicobject@caption}%
+ }%
+ \fi
+ \ifgraphicobject@autolabel
+ \esf@ifpgfkeyhasvalue{\object@graphic@path/label}{%
+ % do nothing
+ }{%
+ \def\graphicobject@label{#3}%
+ \ifgraphicobject@autolabel@strippath
+ \protected@edef\graphicobject@label{\strippath\graphicobject@label}%
+ \fi
+ \pgfkeyslet{\object@graphic@path/label}{\graphicobject@label}%
+ }%
+ \fi
+ \ifgraphicobject@warnenv
+ \pgfkeysalso{env/.get=\esf@tmp@env}%
+ \ifx \esf@tmp@env \@empty
+ \else
+ \ifdefstring{\object@graphic@env}{subobject}
+ {\edef\esf@tmp@name{\string\includegraphicsubobject}}
+ {\edef\esf@tmp@name{\string\includegraphicobject}}%
+ \ifgraphicobject@noenv
+ \PackageWarning{easyfloats}{I am ignoring 'env=\esf@tmp@env' in \esf@tmp@name}%
+ \else
+ \PackageWarning{easyfloats}{'env=\esf@tmp@env' in \esf@tmp@name. Is that intended?}%
+ \fi
+ \fi
+ \fi
+ \ifgraphicobject@noenv
+ \pgfkeysalso{env=}%
+ \fi
+ ,
+ }
+ \expandafter\includegraphics\expandafter[\object@graphic@options@tmp]{#3}%
+ \end{#1}%
+ % if this is \@empty it should not interfere with \ignorespacesafterend (\ignorespaces) or \@endparenv (\@doendpe)
+ \includegraphicobject@after
+}
+
+\newrobustcmd{\includegraphicsubobject}{%
+ \begingroup
+ \def\object@graphic@env{subobject}%
+ \def\object@graphic@path{/subobject}%
+ \def\includegraphicobject@after{\endgroup\ignorespaces}%
+ \includegraphicobject@parseoptions
+}
+
+
+\fi %\ifesf@loadgraphics
+
+
+% ========== sub object ==========
+
+\newif\ifsubobject@warnnolabel
+\newif\ifsubobject@warnnocaption
+
+% available options
+\pgfqkeys{/subobject}{%
+ % A label for the left/right part of the content
+ label/.initial,
+ label/.value required,
+ %
+ % A caption displayed above or below the sub content
+ % (depending on the float style).
+ % There is *no* dot added automatically behind it.
+ caption/.initial,
+ caption/.value required,
+ %
+ % A caption used in the list of figures/tables/...
+ % for the left/right part of the content.
+ list caption/.initial,
+ list caption/.value required,
+ %
+ % An addition to the caption (at the object only, not in a list)
+ details/.initial=,
+ details/.value required,
+ %
+ details sep/.initial=.\space,
+ details sep/.value required,
+ %
+ % TeX code which is inserted before env
+ exec/.initial=,
+ exec/.value required,
+ exec +/.code=\esf@pgfkeysvalueappend{/subobject/exec}{#1},
+ exec +/.value required,
+ exec+/.forward to=/subobject/exec +,
+ exec+/.value required,
+ %
+ % The width argument of \subcaptionbox or subfigure.
+ % For \subcaptionbox an empty value is allowed
+ % meaning that the argument is not passed so that
+ % \subcaptionbox takes the width of the content.
+ linewidth/.initial=.5\linewidth,
+ linewidth/.value required,
+ %
+ % Use the \subcaptionbox command.
+ % Aligns the captions.
+ % Does not allow verbatim content.
+ % Is *not* compatible with env=tabularx.
+ subcaptionbox/.code=
+ \let\subobject@begin\subobject@subcaptionbox
+ \let\subobject@end\endsubobject@subcaptionbox,
+ subcaptionbox/.value forbidden,
+ % Use the subfigure/subtable environment.
+ % Requires linewidth.
+ subpage/.code=
+ \let\subobject@begin\subobject@subpage
+ \let\subobject@end\endsubobject@subpage,
+ subpage/.value forbidden,
+ %
+ % ------- subcaptionbox options -------
+ % Horizontal position of the content in the box.
+ % Allowed values: c, l, r, s, <empty> or any
+ % justification defined with \DeclareCaptionJustification
+ % (see the caption package documentation).
+ % An empty value means that this optional argument is
+ % *not* passed to the \subcaptionbox command.
+ % This option has no effect if linewidth is empty.
+ % I discourage using this option because it destroys
+ % the alignment of (sub)object and (sub)caption.
+ subcaptionbox inner pos/.initial=,
+ subcaptionbox inner pos/.value required,
+ %
+ % ------- subfigure/subtable options -------
+ % The subfigure/subtable environments are minipages
+ % and take the same arguments.
+ % http://tug.org/texinfohtml/latex2e.html#minipage
+ %
+ % The vertical position of the minipage on the baseline.
+ % Allowed values: c, t, b, auto, <empty>.
+ % auto means t if the caption is displayed at the top
+ % or b if the caption is displayed at the bottom
+ % so that the captions are aligned if the minipages
+ % have the same height.
+ % <empty> is equivalent to c.
+ subpage outer pos/.initial=auto,
+ subpage outer pos/.value required,
+ %
+ % The height of the minipage.
+ % An empty value means that this optional argument is
+ % *not* passed to the subfigure/subtable environment.
+ subpage height/.initial=,
+ subpage height/.value required=,
+ %
+ % The vertical position of the content on the minipage.
+ % Allowed values: t, c, b, s, <empty>.
+ % <empty> means that this optional argument is
+ % *not* passed to the subfigure/subtable environment.
+ % This option has no effect if subpage height is <empty>.
+ subpage inner pos/.initial=,
+ subpage inner pos/.value required,
+ %
+ % TeX code which is inserted at the beginning of the subfigure/subtable environment
+ subpage align/.initial=\centering,
+ subpage align/.value required,
+ %
+ % ------- separator options -------
+ % Insert a separator in front of each subobject
+ % except for the first subobject.
+ sep/.initial=,
+ sep/.value required,
+ %
+ % Place the subobjects side by side.
+ hor/.code=
+ \esf@pgfkeyscopyvalue{/subobject/sep}{/subobject/hor sep}%
+ \esf@pgfkeysvalueappend{/subobject/sep}{#1},
+ hor/.default=,
+ %
+ % The separator to be used when the subobjects
+ % shall be placed side by side.
+ hor sep/.initial=,
+ hor sep/.value required,
+ hor sep+/.forward to=/subobject/hor sep +,
+ hor sep+/.value required,
+ hor sep +/.code=\esf@pgfkeysvalueappend{/subobject/hor sep}{#1},
+ hor sep +/.value required,
+ %
+ % Place the subobjects below each other.
+ ver/.code=
+ \esf@pgfkeyscopyvalue{/subobject/sep}{/subobject/ver sep}%
+ \esf@pgfkeysvalueappend{/subobject/sep}{#1},
+ ver/.default=,
+ %
+ % The separator to be used when the subobjects
+ % shall be placed below eachother.
+ ver sep/.initial=\par\bigskip,
+ ver sep/.value required,
+ ver sep+/.forward to=/subobject/ver sep +,
+ ver sep+/.value required,
+ ver sep +/.code=\esf@pgfkeysvalueappend{/subobject/ver sep}{#1},
+ ver sep +/.value required,
+ %
+ %
+ % ------- warnings -------
+ %
+ warn no caption/.is if=subobject@warnnocaption,
+ warn no caption=true,
+ %
+ warn no label/.is if=subobject@warnnolabel,
+ warn no label=false,
+ %
+ warn other env/.forward to=/object/warn other env,
+ %value is allowed but not necessary
+ %
+ %
+ % ------- debugging -------
+ %
+ show env args/.forward to=/object/show env args,
+ %
+ %
+ % ------- inner environment -------
+ %
+ % An additional inner environment to wrap the content in like tabular, tabularx, tikzpicture
+ env/.code=\IfEnvironmentExistsOrIsEmpty{#1}{%
+ \ifstrequal{#1}{longtable}{%
+ \PackageError{easyfloats}{You cannot use 'env=longtable' in a subobject}
+ {Either use 'env=tabular' instead or combine the subobjects into one longtable.}%
+ \pgfkeyssetvalue{/subobject/env}{tabular}%
+ }{%
+ \pgfkeyssetvalue{/subobject/env}{#1}%
+ }%
+ }{%
+ \PackageError{easyfloats}{Environment #1 which you passed to the key 'env' does not exist}{}%
+ },
+ env/.value required,
+ env=,
+ %
+ % ------- unknown handler / env args -------
+ %
+ % see /object
+ %
+ .unknown/.code={%
+ % Using \ObjectProcessKeyPattern instead of \ObjectProcessArgs
+ % means that keys like `graphic width` can be used in subobjects as well.
+ % For a directly used subobject this should not be allowed.
+ % But I am leaving it in for \includegraphicsubobject so that the same key
+ % which works in \objectset and \includegraphicobject also works there.
+ \ObjectProcessKeyPattern{\pgfkeyscurrentname}{#1}{%
+ \pgfkeysgetvalue{/subobject/.really unknown/.@cmd}{\esf@tmp@err}%
+ \esf@tmp@err#1\pgfeov
+ }%
+ },
+ % Setting an unknown key handler shall not override env args but set an additional unknown handler.
+ .unknown/.code/.code={%
+ \pgfkeysdef{/subobject/.really unknown}{#1}%
+ },
+ .really unknown/.code={%
+ \edef\do{\noexpand\pgfkeys{/errors/unknown key={\pgfkeyscurrentkey}{\unexpanded{#1}}}}%
+ \do
+ },
+}%
+
+\newenvironment{subobject}[1]{% #1: options
+ \if@inobject
+ \else
+ \PackageError{easyfloats}{subobject environment may not be used outside of an object}{Did you mean to use the object environment instead?}%
+ \fi
+ %
+ \subobject@hook
+ \ifobject@isgraphic
+ \object@graphic@hook
+ \global\object@isgraphicfalse
+ \fi
+ %
+ \let\label=\esf@original@label
+ \let\caption=\esf@original@caption
+ %
+ % ------- options -------
+ %
+ \renewcommand\@object@envkey{/subobject/env}%
+ \pgfqkeys{/subobject}{#1}%
+ \ifsubobject@warnnocaption
+ \pgfkeys{/subobject/caption/.esf@recommended}%
+ \fi
+ \ifsubobject@warnnolabel
+ \pgfkeys{/subobject/label/.esf@recommended}%
+ \fi
+ %
+ \esf@ifpgfkeyhasvalue{/subobject/list caption}%
+ {\pgfkeys{/subobject/list caption/.get=\subobject@caption@short}}%
+ {\pgfkeys{/subobject/caption/.get=\subobject@caption@short}}%
+ \pgfkeysgetvalue{/subobject/linewidth}{\subobject@linewidth}%
+ %
+ \pgfkeysgetvalue{/subobject/details}{\subobject@details}%
+ \ifx \subobject@details \@empty
+ % do nothing
+ \else
+ \preto\subobject@details{\pgfkeysvalueof{/subobject/details sep}}%
+ \fi
+ %
+ \pgfkeysgetvalue{/subobject/env}{\esf@tmp@env}%
+ \ifx \esf@tmp@env \@empty
+ \def\subobject@innerenv@begin{\ignorespaces}%
+ \def\subobject@innerenv@end{\unskip}%
+ \else
+ \edef\subobject@innerenv@begin{\expandonce{\csname\esf@tmp@env\endcsname}}%
+ \edef\subobject@innerenv@end{\expandonce{\csname end\esf@tmp@env\endcsname}}%
+ \ObjectAppendEnvargs{\subobject@innerenv@begin}%
+ \ifobject@showenv
+ \show\subobject@innerenv@begin
+ \fi
+ \fi
+ %
+ % ------- execute -------
+ %
+ \if@firstsubobject
+ \else
+ % No need to worry about \parskip.
+ % Inside of a floating environment it appears to be always zero.
+ \pgfkeysvalueof{/subobject/sep}%
+ \fi
+ \subobject@begin
+}{%
+ \subobject@end
+ \global \@firstsubobjectfalse
+}
+
+\NewEnviron{subobject@subcaptionbox}{%
+ \def\subobject@box{%
+ \subcaptionbox[% list caption
+ \subobject@caption@short
+ ]{% caption
+ \pgfkeysvalueof{/subobject/caption}%
+ \subobject@details
+ \esf@ifpgfkeyhasvalue{/subobject/label}
+ {\label{\pgfkeysvalueof{/subobject/label}}}
+ {}%
+ }%
+ }%
+ \ifdefvoid\subobject@linewidth{%
+ % do nothing
+ }{%
+ \appto\subobject@box{[\subobject@linewidth]}%
+ \pgfkeysgetvalue{/subobject/subcaptionbox inner pos}{\subobject@innerpos}%
+ \ifx \subobject@innerpos \@empty
+ % do nothing
+ \else
+ \eappto\subobject@box{[\subobject@innerpos]}%
+ \fi
+ }%
+ \subobject@box{% content
+ \begingroup
+ \renewcommand{\label}[1]{\PackageError{easyfloats}{\string\label\space is not allowed in subobject. Please use the 'label' option instead}{}}%
+ \renewcommand{\caption}[2][]{\PackageError{easyfloats}{\string\caption\space is not allowed in subobject. Please use the 'caption' option instead}{}}%
+ \pgfkeysvalueof{/subobject/exec}%
+ \subobject@innerenv@begin
+ \BODY
+ \subobject@innerenv@end
+ \endgroup
+ }%
+}
+
+\newenvironment{subobject@subpage}{%
+ \ifx \subobject@linewidth \@empty
+ \PackageError{easyfloats}{'linewidth' may not be empty when using the 'subpage' backend}{}%
+ \fi
+ \edef\subobject@subpage@envname{sub\pgfkeysvalueof{/object/type}}%
+ \def\subobject@subpage@begin{\csname\subobject@subpage@envname\endcsname}%
+ \def\subobject@subpage@end{\csname end\subobject@subpage@envname\endcsname}%
+ %
+ \pgfkeysgetvalue{/subobject/subpage outer pos}{\subobject@outerpos}%
+ \ifx \subobject@outerpos \@empty
+ \appto\subobject@subpage@begin{[c]}%
+ \else \ifdefstring \subobject@outerpos {auto}{%
+ \caption@iftop
+ {\eappto\subobject@subpage@begin{[t]}}%
+ {\eappto\subobject@subpage@begin{[b]}}%
+ }{\ifdefstring \subobject@outerpos {Auto}{%
+ \caption@iftop
+ {\eappto\subobject@subpage@begin{[T]}}%
+ {\eappto\subobject@subpage@begin{[B]}}%
+ }{%
+ \eappto\subobject@subpage@begin{[\subobject@outerpos]}%
+ }}\fi
+ \pgfkeysgetvalue{/subobject/subpage height}{\subobject@height}%
+ \ifx \subobject@height \@empty
+ \else
+ \appto\subobject@subpage@begin{[\subobject@height]}%
+ \pgfkeysgetvalue{/subobject/subpage inner pos}{\subobject@innerpos}%
+ \ifx \subobject@innerpos \@empty
+ \else
+ \eappto\subobject@subpage@begin{[\subobject@innerpos]}%
+ \fi
+ \fi
+ %
+ \subobject@subpage@begin{\subobject@linewidth}%
+ \pgfkeysvalueof{/subobject/subpage align}%
+ % \caption@iftop is defined by caption package
+ \caption@iftop{\subobject@subpage@captionAndLabel}{}%
+ \begingroup
+ \renewcommand{\label}[1]{\PackageError{easyfloats}{\string\label\space is not allowed in subobject. Please use the 'label' option instead}{}}%
+ \renewcommand{\caption}[2][]{\PackageError{easyfloats}{\string\caption\space is not allowed in subobject. Please use the 'caption' option instead}{}}%
+ \pgfkeysvalueof{/subobject/exec}%
+ \subobject@innerenv@begin
+}{%
+ \subobject@innerenv@end
+ \endgroup
+ \caption@iftop{}{\subobject@subpage@captionAndLabel}%
+ \subobject@subpage@end
+ \ignorespacesafterend
+}
+\newcommand{\subobject@subpage@captionAndLabel}{%
+ % ------- caption -------
+ % position of caption (above/below) is handled by float package (see float style)
+ \esf@ifpgfkeyhasvalue{/subobject/caption}{%
+ \caption[\subobject@caption@short]{\pgfkeysvalueof{/subobject/caption}\subobject@details}%
+ }{%
+ % Generate an anchor for a \label.
+ \phantomcaption
+ }%
+ % ------- label -------
+ \esf@ifpgfkeyhasvalue{/subobject/label}%
+ {\label{\pgfkeysvalueof{/subobject/label}}}%
+ {}%
+}
+
+\pgfqkeys{/subobject}{subpage}
diff --git a/macros/latex/contrib/easyfloats/easyfloats.ins b/macros/latex/contrib/easyfloats/easyfloats.ins
new file mode 100644
index 0000000000..c3f1020483
--- /dev/null
+++ b/macros/latex/contrib/easyfloats/easyfloats.ins
@@ -0,0 +1,82 @@
+% !TeX program = tex
+
+%% easyfloats.ins
+%% Copyright 2020 E. Zöllner
+%
+% This work may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License, either version 1.3
+% 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.3 or later is part of all distributions of LaTeX
+% version 2005/12/01 or later.
+%
+% This work has the LPPL maintenance status `maintained'.
+%
+% The Current Maintainer of this work is E. Zöllner.
+%
+% This work consists of the files listed in easyfloats-file-list.txt.
+% The official git repository is https://gitlab.com/erzo/latex-easyfloats
+
+
+% Make easyfloats.dtx faster by stripping comments and indentation
+% and write the result to easyfloats.sty.
+
+\input docstrip.tex
+
+\preamble
+
+Copyright 2020 E. Z\string\"ollner
+
+This work may be distributed and/or modified under the
+conditions of the LaTeX Project Public License, either version 1.3
+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.3 or later is part of all distributions of LaTeX
+version 2005/12/01 or later.
+Additionally to the rights granted by the LaTeX Project Public License
+you have permission to freely distribute unmodified copies
+of the files \jobname.sty and doc/easyfloats.pdf without other files of this work.
+The other files of this work can be found at:
+https://gitlab.com/erzo/latex-easyfloats
+
+This work has the LPPL maintenance status `maintained'.
+
+The Current Maintainer of this work is E. Z\string\"ollner.
+
+This work consists of the files listed in easyfloats-file-list.txt.
+\endpreamble
+
+\askforoverwritefalse
+\generate{
+ \file{\jobname.sty}{\from{\jobname.dtx}{package}}
+}
+
+\def\lnout{}
+\count0=0
+\def\append#1{\advance\count0 by 1 \expandafter\def\expandafter\lnout\expandafter{\lnout#1}}
+\def\appendmany#1{\ifx\relax#1\else\append{#1}\expandafter\appendmany\fi}
+\obeyspaces
+\appendmany \relax
+\expandafter\appendmany\jobname.sty\relax
+\loop\append{ }\ifnum\count0<48\repeat
+\Msg{****************************************************}
+\Msg{* *}
+\Msg{* To finish the installation you have to move the *}
+\Msg{* following file into a directory searched by TeX: *}
+\Msg{* *}
+\Msg{* \lnout *}
+\Msg{* *}
+\Msg{* To produce the documentation run: *}
+\Msg{* $ cd doc *}
+\Msg{* $ pdflatex easyfloats.tex *}
+\Msg{* $ biber easyfloats *}
+\Msg{* $ pdflatex easyfloats.tex *}
+\Msg{* $ pdflatex easyfloats.tex *}
+\Msg{* *}
+\Msg{* Happy TeXing! *}
+\Msg{* *}
+\Msg{****************************************************}
+
+\endbatchfile