summaryrefslogtreecommitdiff
path: root/macros/latex/contrib
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2023-11-21 03:02:55 +0000
committerNorbert Preining <norbert@preining.info>2023-11-21 03:02:55 +0000
commitff01be90452ac7aec530af4623f334ca21869cc5 (patch)
treec6cce3ca77cbf7d86029297394b55c965199c062 /macros/latex/contrib
parent682900f29e7ea9d31046e9541be14fd749b2eb17 (diff)
CTAN sync 202311210302
Diffstat (limited to 'macros/latex/contrib')
-rw-r--r--macros/latex/contrib/hvextern/Changes23
-rw-r--r--macros/latex/contrib/hvextern/README4
-rw-r--r--macros/latex/contrib/hvextern/doc/hvextern.pdfbin1484026 -> 1498330 bytes
-rw-r--r--macros/latex/contrib/hvextern/doc/hvextern.tex4
-rw-r--r--macros/latex/contrib/hvextern/latex/hvextern.sty18
-rw-r--r--[-rwxr-xr-x]macros/latex/contrib/hvextern/script/hvextern-checkfile.lua0
-rw-r--r--macros/latex/contrib/latex2pydata/README29
-rw-r--r--macros/latex/contrib/latex2pydata/latex2pydata.dtx1280
-rw-r--r--macros/latex/contrib/latex2pydata/latex2pydata.ins58
-rw-r--r--macros/latex/contrib/latex2pydata/latex2pydata.pdfbin0 -> 292477 bytes
-rw-r--r--macros/latex/contrib/logoetalab/doc/logoetalab-doc.pdfbin674245 -> 721510 bytes
-rw-r--r--macros/latex/contrib/logoetalab/doc/logoetalab-doc.tex207
-rw-r--r--macros/latex/contrib/logoetalab/tex/logoetalab.sty136
-rw-r--r--macros/latex/contrib/uni-titlepage/README.md2
-rw-r--r--macros/latex/contrib/uni-titlepage/titlepage-DHBW.pdfbin43998 -> 44028 bytes
-rw-r--r--macros/latex/contrib/uni-titlepage/titlepage-JT-Aufsaetze.pdfbin41265 -> 41296 bytes
-rw-r--r--macros/latex/contrib/uni-titlepage/titlepage-JT-Geschichte.pdfbin38250 -> 38279 bytes
-rw-r--r--macros/latex/contrib/uni-titlepage/titlepage-JT-Typography.pdfbin26902 -> 26919 bytes
-rw-r--r--macros/latex/contrib/uni-titlepage/titlepage-KIT.pdfbin42151 -> 42235 bytes
-rw-r--r--macros/latex/contrib/uni-titlepage/titlepage-KOMAScript.pdfbin166493 -> 166600 bytes
-rw-r--r--macros/latex/contrib/uni-titlepage/titlepage-Markus-1.pdfbin119778 -> 119869 bytes
-rw-r--r--macros/latex/contrib/uni-titlepage/titlepage-Markus-2.pdfbin128796 -> 128889 bytes
-rw-r--r--macros/latex/contrib/uni-titlepage/titlepage-Spacer.pdfbin127997 -> 128092 bytes
-rw-r--r--macros/latex/contrib/uni-titlepage/titlepage-TU-DD.pdfbin40396 -> 40484 bytes
-rw-r--r--macros/latex/contrib/uni-titlepage/titlepage-TU-HH.pdfbin54041 -> 54160 bytes
-rw-r--r--macros/latex/contrib/uni-titlepage/titlepage-UKoLa.pdfbin103389 -> 103448 bytes
-rw-r--r--macros/latex/contrib/uni-titlepage/titlepage-WWUM.pdfbin58802 -> 59125 bytes
-rw-r--r--macros/latex/contrib/uni-titlepage/uni-titlepage.dtx83
-rw-r--r--macros/latex/contrib/uni-titlepage/uni-titlepage.pdfbin1161923 -> 1182020 bytes
29 files changed, 1794 insertions, 50 deletions
diff --git a/macros/latex/contrib/hvextern/Changes b/macros/latex/contrib/hvextern/Changes
index 14afbfe9ed..ac24c74145 100644
--- a/macros/latex/contrib/hvextern/Changes
+++ b/macros/latex/contrib/hvextern/Changes
@@ -1,23 +1,24 @@
hvextern.sty ----------------
-v 0.37 2023-08-29 - do not write files without --shell-escape
-v 0.36 2023-08-24 - added option "vshift" for inline objects
-v 0.35 2023-08-22 - fix shellesc option, don`t set it globally to true
-v 0.34 2023-07-05 - fix for missing --shell-escape option
-v 0.33 2023-01-29 - fixed bug with vertical space before and end of
+v 0.37a 2023-11-20 - fix bug in documentation
+v 0.37 2023-08-29 - do not write files without --shell-escape
+v 0.36 2023-08-24 - added option "vshift" for inline objects
+v 0.35 2023-08-22 - fix shellesc option, don`t set it globally to true
+v 0.34 2023-07-05 - fix for missing --shell-escape option
+v 0.33 2023-01-29 - fixed bug with vertical space before and end of
the example code
-v 0.32 2022-06-23 - fixed introduced bug
+v 0.32 2022-06-23 - fixed introduced bug
- added checkCode also for pdflatex and xelatex
-v 0.31 2022-06-20 - added package option checkCode to run the external
+v 0.31 2022-06-20 - added package option checkCode to run the external
file only if the code changes.
-v 0.30 2022-06-09 - added \hfuzz=\maxdimen for filename to prevent
+v 0.30 2022-06-09 - added \hfuzz=\maxdimen for filename to prevent
overfull box messages
-v 0.29 2022-06-06 - use skin "enhanced jigsaw" for tcolorbox
+v 0.29 2022-06-06 - use skin "enhanced jigsaw" for tcolorbox
- output -> showoutput
-v 0.28 2022-06-01 - added option output
+v 0.28 2022-06-01 - added option output
- added macro \defMarkerType for own marker setting
(is only a link to the internal macro \hv@extern@ExampleType)
-v 0.27 2022-05-27 - suppress overfull warnings for filename output
+v 0.27 2022-05-27 - suppress overfull warnings for filename output
- fix for tcolorbox with minipage and breakable
- write filename in tt
- added verbose message for force=false
diff --git a/macros/latex/contrib/hvextern/README b/macros/latex/contrib/hvextern/README
index adbd87ba71..c79f2266ee 100644
--- a/macros/latex/contrib/hvextern/README
+++ b/macros/latex/contrib/hvextern/README
@@ -6,11 +6,11 @@ The main LaTeX document must be run with the option --shell-escape
%% It may be distributed and/or modified under the
-%% conditions of the LaTeX Project Public License, either version 1.3c
+%% 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.3c or later is part of all distributions of LaTeX
+%% and version 1.3 or later is part of all distributions of LaTeX
%% version 2005/12/01 or later.
diff --git a/macros/latex/contrib/hvextern/doc/hvextern.pdf b/macros/latex/contrib/hvextern/doc/hvextern.pdf
index 21dd33cfdc..a6755a2935 100644
--- a/macros/latex/contrib/hvextern/doc/hvextern.pdf
+++ b/macros/latex/contrib/hvextern/doc/hvextern.pdf
Binary files differ
diff --git a/macros/latex/contrib/hvextern/doc/hvextern.tex b/macros/latex/contrib/hvextern/doc/hvextern.tex
index ae1528783d..619ca1254a 100644
--- a/macros/latex/contrib/hvextern/doc/hvextern.tex
+++ b/macros/latex/contrib/hvextern/doc/hvextern.tex
@@ -1,4 +1,4 @@
-%% $Id: hvextern.tex 753 2023-08-29 07:22:20Z herbert $
+%% $Id: hvextern.tex 819 2023-11-20 20:37:38Z herbert $
%\RequirePackage{pdfmanagement-testphase}
\DocumentMetadata{}
\documentclass[english,a4paper,twoside]{article}
@@ -1893,7 +1893,7 @@ if the package option \Loption{checkCode} exists.
option \Lkeyword{ExampleDir}.
\item[\Lkeyword{ExampleDir}] name of a directory for the examples, must
first be created by the user himself.
-\item[\Lkeyset{tclbox=false}] Can be used if there are some negative interactions between package \Lpack{listings}
+\item[\Lkeyset{tcbox=false}] Can be used if there are some negative interactions between package \Lpack{listings}
and package \Lpack{tcolorbox}.
\item[\Lkeyword{framesep}] Value for \Lcs{fbox} if keyword \texttt{frame} is used.
\item[\Lkeyword{mpsep}] Distance between code and output (default 1\,em).
diff --git a/macros/latex/contrib/hvextern/latex/hvextern.sty b/macros/latex/contrib/hvextern/latex/hvextern.sty
index 5db1916c16..b7e422958e 100644
--- a/macros/latex/contrib/hvextern/latex/hvextern.sty
+++ b/macros/latex/contrib/hvextern/latex/hvextern.sty
@@ -1,19 +1,19 @@
-%% $Id: hvextern.sty 753 2023-08-29 07:22:20Z herbert $
+%% $Id: hvextern.sty 819 2023-11-20 20:37:38Z herbert $
%% This is file `hvextern.sty',
%%
%% Copyright (C) 2016-23
%% Herbert Voss
%%
%% It may be distributed and/or modified under the
-%% conditions of the LaTeX Project Public License, either version 1.3c
+%% 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.3c or later is part of all distributions of LaTeX
+%% and version 1.3 or later is part of all distributions of LaTeX
%% version 2005/12/01 or later.
-\def\hvexternFileversion{0.37}
-\ProvidesFile{hvextern}[2023/08/29 v\hvexternFileversion: package for running external documents (HV)]
+\def\hvexternFileversion{0.37a}
+\ProvidesFile{hvextern}[2023/11/20 v\hvexternFileversion: package for running external documents (HV)]
\newif\ifhv@extern@checkCode
\hv@extern@checkCodefalse
@@ -143,7 +143,8 @@
}
\define@boolkey{hv}[hv@extern@]{shellesc}[true]{}
\define@key{hv}{aboveskip}[\medskipamount]{\setlength\hv@extern@aboveskip{#1}}
-\define@key{hv}{belowpreambleskip}[\smallskipamount]{\setlength\hv@extern@belowpreambleskip{#1}}
+\define@key{hv}{belowpreambleskip}[2pt%\smallskipamount
+]{\setlength\hv@extern@belowpreambleskip{#1}}
\define@key{hv}{belowbodyskip}[\smallskipamount]{\setlength\hv@extern@belowbodyskip{#1}}
\define@key{hv}{belowskip}[\medskipamount]{\setlength\hv@extern@belowskip{#1}}
@@ -200,8 +201,8 @@
cropmargin=2,% 2pb margin
eps=false,% create an eps output?
aboveskip=\medskipamount,% space above everything
- belowpreambleskip=\smallskipamount,% space below preamble
- belowbodyskip=\smallskipamount,% space below body
+ belowpreambleskip=2pt,%\smallskipamount,% space below preamble
+ belowbodyskip=2pt,%\smallskipamount,% space below body
belowskip=\medskipamount,% space below everything
}%
}
@@ -445,6 +446,7 @@
%%
\newenvironment{externalDocument}[2][]
{%
+ \the\hv@extern@belowbodyskip\par
\ifhv@extern@shellesc\gdef\hv@run@options{ --shell-escape }\else\gdef\hv@run@options{}\fi%
\xdef\hvExternFilename{#2-\arabic{hv@example@counter}}%
\gdef\hv@extern@savePara{#1}%
diff --git a/macros/latex/contrib/hvextern/script/hvextern-checkfile.lua b/macros/latex/contrib/hvextern/script/hvextern-checkfile.lua
index ea163c6a72..ea163c6a72 100755..100644
--- a/macros/latex/contrib/hvextern/script/hvextern-checkfile.lua
+++ b/macros/latex/contrib/hvextern/script/hvextern-checkfile.lua
diff --git a/macros/latex/contrib/latex2pydata/README b/macros/latex/contrib/latex2pydata/README
new file mode 100644
index 0000000000..678217ebc7
--- /dev/null
+++ b/macros/latex/contrib/latex2pydata/README
@@ -0,0 +1,29 @@
+latex2pydata - write data to file in Python literal format
+
+Author: Geoffrey M. Poore
+License: LPPL v1.3c or later
+Development: https://github.com/gpoore/latex2pydata_tex
+
+
+latex2pydata is a LaTeX package for writing data to file using Python literal
+syntax (https://docs.python.org/3/reference/lexical_analysis.html#literals).
+The data may be loaded safely in Python using the ast.literal_eval() function
+(https://docs.python.org/3/library/ast.html#ast.literal_eval) or the
+latex2pydata Python package https://github.com/gpoore/latex2pydata_py).
+
+The top-level data structure can be configured as either a Python dict or a
+list of dicts. Within dicts, all keys and values are written to file as
+Python string literals. However, this does not limit the data types that can
+be passed from LaTeX to Python. When data is loaded, the included schema
+functionality makes it possible to convert string values into other Python
+data types such as dicts, lists, sets, bools, and numbers.
+
+The data is suitable for direct loading in Python with ast.literal_eval().
+It is also possible to load data using the latex2pydata Python package
+(https://github.com/gpoore/latex2pydata_py). This functions as a wrapper for
+ast.literal_eval(). The package requires all keys to match the regex
+"[A-Za-z_][0-9A-Za-z_]*". Periods in keys are interpreted as key paths and
+indicate sub-dicts. For example, the key path "main.sub" represents a key
+"main" in the main dict that maps to a sub-dict containing a key "sub". The
+Python package supports the schema features provided by the LaTeX package, so
+that data types other than dicts of strings are possible.
diff --git a/macros/latex/contrib/latex2pydata/latex2pydata.dtx b/macros/latex/contrib/latex2pydata/latex2pydata.dtx
new file mode 100644
index 0000000000..c49c732037
--- /dev/null
+++ b/macros/latex/contrib/latex2pydata/latex2pydata.dtx
@@ -0,0 +1,1280 @@
+% \iffalse meta-comment
+%
+% Copyright (C) 2023 by Geoffrey M. Poore <gpoore@gmail.com>
+% ---------------------------------------------------------------------------
+% This work may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License, either version 1.3c
+% of this license or (at your option) any later version.
+% The latest version of this license is in
+% http://www.latex-project.org/lppl.txt
+% and version 1.3c or later is part of all distributions of LaTeX
+% version 2008/05/04 or later.
+%
+% This work has the LPPL maintenance status `maintained'.
+%
+% The Current Maintainer of this work is Geoffrey M. Poore.
+%
+% This work consists of the files latex2pydata.dtx and latex2pydata.ins
+% and the derived filebase latex2pydata.sty.
+%
+% \fi
+%
+% \iffalse
+%<*driver>
+\ProvidesFile{latex2pydata.dtx}
+%</driver>
+%<package>\NeedsTeXFormat{LaTeX2e}[1999/12/01]
+%<package>\ProvidesPackage{latex2pydata}
+%<*package>
+ [2023/11/19 v0.1 latex2pydata - write data to file in Python literal format]
+%</package>
+%
+%<*driver>
+\documentclass{ltxdoc}
+
+\makeatletter
+
+\usepackage[T1]{fontenc}
+\usepackage[utf8]{inputenc}
+\usepackage{lmodern}
+\usepackage{fourier}
+\usepackage{microtype}
+
+\usepackage[svgnames]{xcolor}
+\usepackage{upquote}
+% The typesetting for macrocode doesn't use \@noligs, which upquote modifies.
+% So apply the upquote fix to \verbatim@nolig@list as well, which is in macrocode.
+\begingroup
+\catcode`'=\active
+\catcode``=\active
+\g@addto@macro\verbatim@nolig@list{%
+ \let'\textquotesingle
+ \let`\textasciigrave
+ \ifx\encodingdefault\upquote@OTone
+ \ifx\ttdefault\upquote@cmtt
+ \def'{\char13 }%
+ \def`{\char18 }%
+ \fi\fi}
+\endgroup
+\usepackage{fvextra}
+\usepackage{latex2pydata}
+
+\usepackage{graphicx}
+
+\usepackage{amsmath, amssymb}
+
+\usepackage{environ}
+
+\usepackage{tcolorbox}
+\tcbuselibrary{listings}
+% strip leading percent symbols
+\def\tcbverbatimwrite#1{%
+ \@bsphack
+ \tcb@set@verbatim@finish%
+ \tcb@allocate@tcb@out%
+ \immediate\openout\tcb@out #1
+ \tcb@verbatim@begin@hook%
+ \let\do\@makeother\dospecials
+ \tcb@verbatim@change@percent\catcode`\^^M\active \catcode`\^^I=12
+ \def\verbatim@processline{%
+ \immediate\write\tcb@out
+ {\expandafter\@gobble\the\verbatim@line}}%
+ \verbatim@start}%
+
+% fix redefinition by tcolorbox
+\def\verbatim@processline{%
+ \expandafter\check@percent\the\verbatim@line\par}
+
+\usepackage{hyperref}
+\hypersetup{
+ pdftitle=The latex2pydata package: write key-value data to file in Python literal format,
+ pdfauthor=Geoffrey M. Poore,
+ pdfsubject={latex2pydata LaTeX package manual},
+ colorlinks=true,
+ allcolors=ForestGreen,
+}
+\usepackage{cleveref}
+
+\let\code\Verb
+\def\meta#1{\mbox{\ensuremath{\langle}\textit{\ttfamily#1}\ensuremath{\rangle}}}
+
+% A more robust \cmd
+\let\cmd\Verb
+
+% Create a short verbatim pipe that handles quotation marks properly
+\begingroup
+\catcode`\|=\active
+\gdef\pipe@active@verbatim{%
+ \begingroup
+ \let\do\@makeother\dospecials
+ \catcode`\|=\active
+ \catcode`\`=\active
+ \catcode`\'=\active
+ \catcode`\<=\active
+ \catcode`\>=\active
+ \catcode`\-=\active
+ \catcode`\,=\active
+ \catcode`\ =\active
+ \pipe@active@verbatim@i}
+\gdef\pipe@active@verbatim@i#1|{%
+ \endgroup
+ \begingroup
+ \def\FV@SV@pipe@active@verbatim{%
+ \FV@Gobble
+ \expandafter\FV@ProcessLine\expandafter{#1}}%
+ %\let\FV@BeginVBox\relax
+ %\let\FV@EndVBox\relax
+ %\def\FV@BProcessLine##1{\FancyVerbFormatLine{##1}}%
+ \BUseVerbatim{pipe@active@verbatim}%
+ \endgroup}
+\AtBeginDocument{\let|\pipe@active@verbatim}
+\endgroup
+
+\newcommand\pkg[1]{\textsf{\mbox{#1}}}
+
+\def\MacroFont{%
+ \fontencoding\encodingdefault%
+ \fontfamily\ttdefault%
+ \fontseries\mddefault%
+ \fontshape\updefault%
+ \small}
+
+\def\PrintMacroName#1{{\strut\MacroFont\color{DarkGreen}\footnotesize\string #1\ }}
+
+\def\PrintDescribeMacro#1{\strut\MacroFont\textcolor{DarkGreen}{\string #1\ }}
+\let\PrintDescribeEnv\PrintDescribeMacro
+%\let\PrintMacroName\PrintDescribeMacro
+\let\PrintEnvName\PrintDescribeEnv
+
+\def\theCodelineNo{\textcolor{DarkGreen}{\sffamily\scriptsize{\arabic{CodelineNo}}}}
+
+
+\def\DescMacro{%
+ \begingroup\makeatletter\DescMacro@i}
+\def\DescMacro@i#1{%
+ \endgroup
+ \DescMacro@ii#1\FV@Sentinel
+}
+\def\DescMacro@ii#1#2\FV@Sentinel{%
+ \@nameuse{SpecialMacroIndex}{#1}%
+ \vspace{1em}%
+ \begingroup
+ \ttfamily
+ \large
+ \setlength{\parindent}{0pt}%
+ \hspace{-3em}{\bfseries\color{DarkGreen}\detokenize{#1}}{\normalsize#2}%
+ \endgroup
+ \par\vspace{0.5em}\noindent\ignorespaces
+}
+\def\DescEnv#1{%
+ \@nameuse{SpecialEnvIndex}{#1}%
+ \vspace{1em}%
+ \begingroup
+ \ttfamily
+ \large
+ \setlength{\parindent}{0pt}%
+ \hspace{-3em}{\bfseries\color{DarkGreen}\detokenize{#1}}\space%
+ \endgroup
+ (\textit{env.})
+ \par\vspace{0.5em}\noindent\ignorespaces
+}
+
+\let\orig@footnote\footnote
+\renewcommand{\footnote}{%
+ \begingroup
+ \let\do\@makeother
+ \dospecials
+ \catcode`\{=1
+ \catcode`\}=2
+ \new@footnote}
+\newcommand{\new@footnote}[1]{%
+ \endgroup
+ \orig@footnote{\scantokens{#1}}}
+
+\def\printopt#1(#2) (#3){%
+ \vspace{0.1in}%
+ \leavevmode%
+ \marginpar{\raggedleft\texttt{\small\textcolor{DarkGreen}{#1}}\ }%
+ \kern-\parindent\textsf{(#2)}\hfill(default: \texttt{#3})\\}
+
+\newenvironment{optionlist}%
+ {%
+ ~\par\vspace{-14pt}%
+ \def\pipechar{|}
+ \let\|\pipechar
+ \newcommand*\optionlistnext{}%
+ \renewcommand*\item[1][]{%
+ \optionlistnext%
+ \renewcommand*\optionlistnext{\par}%
+ \printopt##1%
+ \ignorespaces}}
+ {%
+ \par}
+
+\newenvironment{example}
+ {\VerbatimEnvironment
+ \begin{VerbatimOut}[gobble=4]{example.out}}
+ {\end{VerbatimOut}%
+ \vspace{1ex}%
+ \setlength{\parindent}{0pt}%
+ \setlength{\fboxsep}{1em}%
+ \fcolorbox{DarkGreen}{white}{\begin{minipage}{0.5\linewidth}%
+ \VerbatimInput{example.out}%
+ \end{minipage}%
+ \hspace{0.025\linewidth}%
+ {\color{DarkGreen}\vrule}%
+ \hspace{0.025\linewidth}%
+ \begin{minipage}{0.4\linewidth}%
+ \input{example.out}%
+ \end{minipage}%
+ }\vspace{1ex}}
+
+\newenvironment{longexample}
+ {\VerbatimEnvironment
+ \begin{VerbatimOut}[gobble=4]{example.out}}
+ {\end{VerbatimOut}%
+ \vspace{1ex}%
+ \setlength{\parindent}{0pt}%
+ \setlength{\fboxsep}{1em}%
+ \fcolorbox{DarkGreen}{white}{\begin{minipage}{0.94\linewidth}%
+ \VerbatimInput{example.out}%
+ {\color{DarkGreen}\hrulefill}
+ \setlength{\fboxsep}{3pt}%
+ \input{example.out}%
+ \end{minipage}%
+ }\vspace{1ex}}
+
+\CustomVerbatimEnvironment{VerbatimVerbatim}{Verbatim}{}
+
+\edef\hashchar{\string#}
+
+\newcommand{\changestext}{}
+\NewEnviron{changelog}[2]{%
+ \g@addto@macro\changestext{\item[#1] (#2) \begin{itemize}}%
+ \expandafter\g@addto@macro\expandafter\changestext\expandafter{\BODY}%
+ \g@addto@macro\changestext{\end{itemize}}%
+}
+\newcommand{\PrintChangelog}{%
+ %\addcontentsline{toc}{section}{Changelog}
+ %\section*{Changelog}%
+ \section{Changelog}
+ \label{sec:changelog}
+ \begin{description}%
+ \changestext
+ \end{description}%
+}
+
+\begingroup
+\catcode`\#=12\relax
+\gdef\astliteval{\href{https://docs.python.org/3/library/ast.html#ast.literal_eval}{\code{ast.literal_eval()}}}
+\endgroup
+\def\pydatapy{\href{https://github.com/gpoore/latex2pydata_py}{\pkg{latex2pydata} Python package}}
+\def\fvextra{\href{https://github.com/gpoore/fvextra/}{\pkg{fvextra}}}
+\def\fancyvrb{\href{https://ctan.org/pkg/fancyvrb}{\pkg{fancyvrb}}}
+
+%\EnableCrossrefs
+%\CodelineIndex
+%\RecordChanges
+
+\makeatother
+\begin{document}
+ \DocInput{latex2pydata.dtx}
+ %\PrintChanges
+ %\PrintIndex
+\end{document}
+%</driver>
+% \fi
+%
+%
+% \begin{changelog}{v0.1}{2023-11-19}
+% \item Initial release.
+% \end{changelog}
+%
+%
+% \DoNotIndex{\newcommand,\newenvironment}
+% \DoNotIndex{\#,\$,\%,\&,\@,\\,\{,\},\^,\_,\~,\ }
+% \DoNotIndex{\@ne}
+% \DoNotIndex{\advance,\begingroup,\catcode,\closein}
+% \DoNotIndex{\closeout,\day,\def,\edef,\else,\empty,\endgroup}
+% \DoNotIndex{\begin,\end,\bgroup,\egroup}
+%
+% \providecommand*{\url}{\texttt}
+% \newcommand{\pydata}{\pkg{latex2pydata}}
+% \GetFileInfo{latex2pydata.dtx}
+%
+% \title{\vspace{-0.5in}The \pydata\ package}
+% \author{Geoffrey M.\ Poore \\ \href{mailto://gpoore@gmail.com}{\texttt{gpoore@gmail.com}} \\ \href{https://github.com/gpoore/latex2pydata_tex}{\Verb{github.com/gpoore/latex2pydata_tex}}}
+% \date{\fileversion~from \filedate}
+%
+% \maketitle
+%
+% \begin{abstract}
+% \noindent\pydata\ is a \LaTeX\ package for writing data to file using \href{https://docs.python.org/3/reference/lexical_analysis.html#literals}{Python literal syntax}. The data may then be loaded safely in Python using the \astliteval\ function or the \pydatapy.
+%
+% \vspace{1.25in}
+% \noindent The original development of this package was funded by a \href{https://tug.org/tc/devfund/grants.html}{\TeX\ Development Fund grant} from the \href{https://tug.org/}{\TeX\ Users Group}. \pydata\ is part of the 2023 grant for improvements to the \href{https://github.com/gpoore/minted/}{\pkg{minted}} package.
+% \end{abstract}
+%
+%
+% \pagebreak
+% \begingroup
+% \makeatletter
+% ^^A https://tex.stackexchange.com/a/45165/10742
+% \patchcmd{\@dottedtocline}
+% {\rightskip\@tocrmarg}
+% {\rightskip\@tocrmarg plus 4em \hyphenpenalty\@M}
+% {}{}
+% \makeatother
+% \tableofcontents
+% \endgroup
+% \pagebreak
+%
+%
+% \section{Introduction}
+%
+% The \pydata\ package is designed for passing data from \LaTeX\ into Python. It writes data to file using \href{https://docs.python.org/3/reference/lexical_analysis.html#literals}{Python literal syntax}. The data may then be loaded safely in Python using the \astliteval\ function or the \pydatapy.
+%
+% The data that \pydata\ writes to file can take two forms. The top-level data structure can be configured as a Python dict. This is appropriate for representing a single \LaTeX\ command or environment. The top-level data structure can also be configured as a list of dicts. This is useful for representing a sequence of \LaTeX\ commands or environments. In both cases, all keys and values within dicts are written to file as Python string literals. Thus, the overall data is |dict[str, str]| or |list[dict[str, str]]|. This does not limit the data types that can be passed from LaTeX to Python, however. When data is loaded, the included schema functionality makes it possible to convert string values into other Python data types such as dicts, lists, sets, bools, and numbers.
+%
+% The data is suitable for direct loading in Python with \astliteval. It is also possible to load data with the \pydatapy, which serves as a wrapper for \code{ast.literal_eval()}. The Python package requires all keys to match the regex \code{[A-Za-z_][0-9A-Za-z_]*}. Periods in keys are interpreted as key paths and indicate sub-dicts. For example, the key path |main.sub| represents a key |main| in the main dict that maps to a sub-dict containing a key |sub|. This makes it convenient to represent nested dicts.
+%
+% \pkg{latex2pydata} optionally supports writing metadata to file, including basic schema definitions for values. When the \pydatapy\ loads data with a schema definition for a given value, the value is initially loaded as a string, which is the verbatim text sent from \LaTeX. Then this string is evaluated with \code{ast.literal_eval()}. An error is raised if this process does not result in an object with the data type specified in the schema.
+%
+%
+%
+% \section{Example}
+%
+%\begin{tcblisting}{}
+%\pydatasetfilename{\jobname.pydata}
+%\pydatawritedictopen
+%\pydatawritekeyvalue{key}{value with "quote" and \backslash\ ...}
+%\pydatawritedictclose
+%\pydataclosefilename{\jobname.pydata}
+%\VerbatimInput{\jobname.pydata}
+%\end{tcblisting}
+%
+%
+%
+% \section{Design considerations}
+%
+% \pydata\ is intended for use with Python. Python literal syntax was chosen instead of \href{https://www.json.org/json-en.html}{JSON} or another data format because it provides simpler compatibility with \LaTeX.
+% \begin{itemize}
+% \item It must be possible to serialize the contents of a \LaTeX\ environment verbatim. Python literal syntax supports multi-line string literals, so this is straightforward: write an opening multi-line string delimiter to file, write the environment contents a line at a time (backslash-escaping any delimiter characters), and finally write a closing multi-line string delimiter. Meanwhile, JSON requires that all literal newlines in strings be replaced with ``\code{\n}''. The naive \LaTeX\ implementation of this would be to accumulate the entire environment contents verbatim within a single macro and then perform newline substitutions. For long environment contents, this can lead to buffer memory errors (\LaTeX's |buf_size|). It should be possible to avoid this, but only with more creative algorithms that bring additional complexity.
+% \item Python literal syntax only requires that the backslash plus the string delimiter be escaped within strings. JSON has the additional requirement that command characters be escaped.
+% \end{itemize}
+%
+% \pkg{latex2pydata} is designed for use with Python and there are no plans to add additional data formats for use with other languages. Choosing Python literal syntax does make \pkg{latex2pydata} less compatible with other programming languages than JSON or some other formats would be. However, the only data structures used are |dict[str, str]| and |list[dict[str, str]]|. It should be straightforward to implement a parser for this subset of Python literal syntax in other languages.
+%
+% Data structures are limited to |dict[str, str]| and |list[dict[str, str]]| because the objective is to minimize the potential for errors during serialization and deserialization. These are simple enough data structures that basic checking for incomplete or malformed data is possible on the \LaTeX\ side during writing or buffering. More complex data types, such as floating point numbers or deeply nested dicts, would be difficult to validate on the \LaTeX\ side, so invalid values would tend to result in parse errors during deserialization in Python. The current approach still allows for a broad variety of data types via a schema, with the advantage that it can be easier to give useful error messages during schema validation than during deserialization parsing.
+%
+%
+%
+% \section{Usage}
+%
+% Load the package as usual: |\usepackage{latex2pydata}|. There are no package options.
+%
+%
+% \subsection[Errors]{\textcolor{red}{Errors}}
+%
+% Most \LaTeX\ packages handle errors based on the |-interaction| and |-halt-on-error| command-line options, plus |\interactionmode| and associated macros. With the common |-interaction=nonstopmode|, \LaTeX\ will continue after most errors except some related to missing external files.
+%
+% \pydata\ is designed to force \LaTeX\ to exit immediately after any \pydata\ errors. \pydata\ is designed for serializing data to file, typically so that an external program (restricted or unrestricted shell escape, or otherwise) can process the data and potentially generate output intended for \LaTeX. Data that is known to be incomplete or malformed should not be passed to external programs, particularly via shell escape.
+%
+% When \pydata\ forces \LaTeX\ to exit immediately, there will typically be a message similar to ``\Verb[breaklines]{! Emergency stop [...] cannot \read from terminal in nonstop modes}.'' This is due to the mechanism that \pydata\ uses to force \LaTeX\ to exit. To debug, go back further up the log to find the \pydata\ error message that caused exiting.
+%
+%
+% \subsection{File handling}
+%
+% \DescMacro{\pydatasetfilehandle\marg{filehandle}}
+% Configure writing to file using an existing file handle created with |\newwrite|. This allows manual management of the file handle. For example:
+% \begin{Verbatim}[gobble=2]
+% \newwrite\testdata
+% \immediate\openout\testdata=\jobname.pydata\relax
+% \pydatasetfilehandle{\testdata}
+% ...
+% \pydatareleasefilehandle{\testdata}
+% \immediate\closeout\testdata
+% \end{Verbatim}
+%
+% To switch from one file handle to another, simply use |\pydatasetfilehandle| with the new file handle. When the file handle is no longer in use, |\pydatareleasefilehandle| is recommended (but not required) to remove references to the file handle and perform basic checking for incomplete or malformed data written to file.
+%
+% \DescMacro{\pydatareleasefilehandle\marg{filehandle}}
+% When a file handle is no longer needed, remove references to it. Also perform basic checking for incomplete or malformed data written to file.
+%
+% This should only be used once per file handle, after all data has been written. It is not needed when switching from one file handle to another when both files remain open; in that case, only |\pydatasetfilehandle| is needed.
+%
+% \DescMacro{\pydatasetfilename\marg{filename}}
+% Configure a file for writing based on filename, opening the file if necessary. For example:
+% \begin{Verbatim}[gobble=2]
+% \pydatasetfilename{\jobname.pydata}
+% \end{Verbatim}
+% This is not designed for manual management of the file handle. The file does not have to be closed manually since this will happen automatically at the end of the document. However, using |\pydataclosefilename|\marg{filename} is recommended since it closes the file immediately and also performs basic checking for incomplete or malformed data written to file.
+%
+% To switch from one file to another, simply use |\pydatasetfilename| with the new filename. When the file is no longer in use, |\pydataclosefilename| is recommended.
+%
+% \DescMacro{\pydataclosefilename\marg{filename}}
+% Close a file previously opened with |\pydatasetfilename|. Also perform basic checking for incomplete or malformed data written to file.
+%
+%
+% \subsection{Metadata}
+%
+% \pkg{latex2pydata} optionally supports writing metadata to file, including basic schema definitions for values. When data is loaded with the \pydatapy, the schema is used to perform type conversion and type checking. When a schema definition exists for a given value, the value is initially loaded as a string, and then (for non-string data types) it is evaluated with \astliteval. An error is raised if this process does not result in an object with the data type specified in the schema.
+%
+% \DescMacro{\pydatasetschemamissing\marg{missing behavior}}
+% This determines how the schema is processed when the schema is missing definitions for one or more key-value pairs. Options for \meta{missing behavior}:
+% \begin{itemize}
+% \item |error| (default): If a schema is defined then a complete schema is required. That is, a schema definition must exist for all key-value pairs or an error is raised.
+% \item |rawstr|: The schema is enforced for all key-value pairs for which it is defined, and any other key-value pairs are kept with string values. These string values are the raw verbatim text passed from \LaTeX.
+% \item |evalany|: The schema is enforced for all key-value pairs for which it is defined, and any other key-value pairs have the value evaluated with \astliteval, with all value data types being permitted. Because all values without a schema definition are evaluated, any string values without a schema definition must be quoted and escaped as strings on the \LaTeX\ side.
+% \end{itemize}
+%
+% \DescMacro{\pydatasetschemakeytype\marg{key}\marg{value type}}
+% Define a key's schema. For example, |\pydatasetschemakeytype{key}{int}|.
+%
+% \meta{value type} should be a standard Python type annotation, such as |list[int]| or |dict[str, float]|. See the \pydatapy\ documentation for information about value data types that are currently supported.
+%
+% \DescMacro{\pydataclearschema}
+% Delete the existing schema. If the schema is not deleted, it can be reused across multiple output files.
+%
+% \DescMacro{\pydatawritemeta}
+% Write metadata, including schema, to a file previously configured with |\pydatasetfilename| or |\pydatasetfilehandle|. Metadata must always be the first thing written to file, before any data.
+%
+% \DescMacro{\pydataclearmeta}
+% Clear all metadata. This includes deleting the schema and resetting schema missing behavior to the default.
+%
+%
+%
+% \subsection{Writing list and dict delimiters}
+% The overall data structure, before any schema is applied by the \pydatapy, can be either |list[dict[str, str]]| or |dict[str, str]|. This determines which data collection delimiters are needed.
+%
+% Delimiters are written to the file previously configured via |\pydatasetfilehandle| or |\pydatasetfilename|.
+%
+% \DescMacro{\pydatawritedictopen}
+% Write an opening dict delimiter |{| to file.
+%
+% \DescMacro{\pydatawritedictclose}
+% Write a closing dict delimiter |}| to file.
+%
+% \DescMacro{\pydatawritelistopen}
+% Write an opening list delimiter |[| to file.
+%
+% \DescMacro{\pydatawritelistclose}
+% Write a closing list delimiter |]| to file.
+%
+%
+% \subsection{Writing keys and values}
+% All keys must be single-line strings of text without a newline. Both single-line and multi-line values are supported. Keys and values are written to the file previously configured via |\pydatasetfilehandle| or |\pydatasetfilename|.
+%
+% The \pydata\ commands read keys and values verbatim. When these commands are used inside other commands, they use macros from \fvextra\ to attempt to interpret their arguments as verbatim. However, there are limitations in this case because the arguments are already tokenized:
+% \begin{itemize}
+% \item |#| and |%| cannot be used.
+% \item Curly braces are only allowed in pairs.
+% \item Multiple adjacent spaces will be collapsed into a single space.
+% \item Be careful with backslashes. A backslash that is followed by one or more ASCII letters will cause a following space to be lost, if the space is not immediately followed by an ASCII letter.
+% \item A single |^| is fine, but |^^| will serve as an escape sequence for an ASCII command character.
+% \end{itemize}
+% When the \pydata\ commands are used inside other commands that pass their arguments to the \pydata\ commands, it will usually be best to avoid these limitations by defining the other commands to read their arguments verbatim. Consider using the \href{https://ctan.org/pkg/xparse}{\pkg{xparse}} package. It is also possible to use |\FVExtraReadVArg| from \fvextra; for an example, see the implementation of |\pydatawritekey|.
+%
+% Because the \pydata\ commands treat keys and values as verbatim, any desired macro expansion must be performed before passing the keys and values to the \pydata\ commands.
+%
+% \DescMacro{\pydatawritekey\marg{key}}
+% Write a key to file.
+%
+% \DescMacro{\pydatawritevalue\marg{value}}
+% Write a single-line value to file.
+%
+% \DescMacro{\pydatawritekeyvalue\marg{key}\marg{value}}
+% Write a key and a single-line value to file simultaneously.
+%
+% \DescEnv{pydatawritemlvalue}
+% Write a multi-line value to file.
+%
+% This environment uses \fvextra\ and \fancyvrb\ internally to capture the environment contents verbatim. If a new environment is defined as a wrapper for |pydatawritemlvalue|, then |\VerbatimEnvironment| must be used at the beginning of the new environment definition. This configures \fancyvrb\ to find the end of the new environment correctly.
+%
+%
+% \subsection{Buffer}
+%
+% Key-value data can be written to file once a dict is opened with |\pydatawritedictopen|. It is also possible to accumulate key-value data in a ``buffer.'' This is convenient when the data serves as input to an external program that generates cached content. Buffered data can be hashed in memory without being written to file, so the existence of cached content can be checked efficiently.
+%
+% A buffer consists of a sequence of macros of the form |\|\meta{buffername}|line|\meta{n}, where each line of data corresponds to a macro and \meta{n} is an integer greater than or equal to one (one-based indexing). The length of the buffer is stored in the counter \meta{buffername}|length|. Buffers are limited to containing comma-separated key-value data, without any opening or closing dict delimiters |{}|.
+%
+%
+% \subsubsection{Creating and deleting buffers}
+%
+% \DescMacro{\pydatasetbuffername\marg{buffername}}
+% Initialize a new buffer if \meta{buffername} has not been used previously, and configure all buffer operations to use \meta{buffername}.
+%
+% \meta{buffername} is used as a base name for creating the buffer line macros of the form |\|\meta{buffername}|line|\meta{n} and the buffer length counter \meta{buffername}|length|.
+%
+% \DescMacro{\pydataclearbuffername\marg{buffername}}
+% Delete the specified buffer. |\let| all line macros |\|\meta{buffername}|line|\meta{n} to an undefined macro, and set the length counter \meta{buffername}|length| to zero.
+%
+%
+% \subsubsection{Special buffer operations}
+%
+% \DescMacro{\pydatabuffermdfivesum}
+% Calculate the MD5 hash of the current buffer, using |\pdf@mdfivesum| from \href{https://ctan.org/pkg/pdftexcmds}{\pkg{pdftexcmds}}. This is fully expandable. For example:
+% \begin{Verbatim}[gobble=2]
+% \edef\hash{\pydatabuffermdfivesum}
+% \end{Verbatim}
+%
+% \DescMacro{\pydatawritebuffer}
+% Write the current buffer to the file previously configured via |\pydatasetfilename| or |\pydatasetfilehandle|.
+%
+% Writing the buffer does not modify the buffer in any way or delete it. To delete the buffer after writing, use |\pydataclearbuffername|.
+%
+%
+% \subsubsection{Buffering keys and values}
+% All keys must be single-line strings of text without a newline. Both single-line and multi-line values are supported. Keys and values are appended to the buffer previously configured via |\pydatasetbuffername|.
+%
+% The \pydata\ commands read keys and values verbatim. Like the commands for writing keys and values, the commands for buffering keys and values have limitations when used inside other commands.
+%
+% \DescMacro{\pydatabufferkey\marg{key}}
+% Append a key to the buffer.
+%
+% \DescMacro{\pydatabuffervalue\marg{value}}
+% Append a single-line value to the buffer.
+%
+% \DescMacro{\pydatabufferkeyvalue\marg{key}\marg{value}}
+% Append a key and a single-line value to the buffer simultaneously.
+%
+% \DescEnv{pydatabuffermlvalue}
+% Append a multi-line value to the buffer.
+%
+% This environment uses \fvextra\ and \fancyvrb\ internally to capture the environment contents verbatim. If a new environment is defined as a wrapper for |pydatabuffermlvalue|, then |\VerbatimEnvironment| must be used at the beginning of the new environment definition. This configures \fancyvrb\ to find the end of the new environment correctly.
+%
+%
+%
+%
+% \PrintChangelog
+%
+% \StopEventually{\PrintIndex}
+%
+% \section{Implementation}
+%
+% \iffalse
+%<*package>
+% \fi
+%
+%
+%
+% \subsection{Exception handling}
+% \begin{macro}{\pydata@error}
+% Shortcut for error message. The |\batchmode\read -1 to \pydata@exitnow| forces an immediate exit with ``\Verb[breaklines]{! Emergency stop [...] cannot \read from terminal in nonstop modes}.'' Due to the potentially critical nature of written or buffered data, any errors in assembling the data should be treated as fatal.
+% \begin{macrocode}
+\def\pydata@error#1{%
+ \PackageError{latex2pydata}{#1}{}%
+ \batchmode\read -1 to \pydata@exitnow}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\pydata@warning}
+% Shortcut for warning message.
+% \begin{macrocode}
+\def\pydata@warning#1{%
+ \PackageWarning{latex2pydata}{#1}}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Required packages}
+% \begin{macrocode}
+\RequirePackage{etoolbox}
+\RequirePackage{fvextra}
+\IfPackageAtLeastTF{fvextra}{2023/11/19}%
+ {}{\pydata@error{package fvextra is outdated; upgrade to the latest version}}
+\RequirePackage{pdftexcmds}
+% \end{macrocode}
+%
+%
+%
+% \subsection{Util}
+%
+% \begin{macro}{\pydata@empty}
+% Empty macro.
+% \begin{macrocode}
+\def\pydata@empty{}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{State}
+%
+% Track state of writing data and of buffering data.
+%
+% \begin{macro}{pydata@canwrite}
+% Whether data can be written. False if a file handle has not been set or if the top-level data structure has been closed.
+% \begin{macrocode}
+\newbool{pydata@canwrite}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{pydata@hasmeta}
+% Whether metadata was written. Metadata is a \code{dict[str, str | dict[str, str]]}.
+% \begin{macrocode}
+\newbool{pydata@hasmeta}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{pydata@topexists}
+% Whether the top-level data structure has been configured. The top-level data structure can be a list or a dict. The overall data structure must be either |dict[str, str]| or |list[dict[str, str]]|.
+% \begin{macrocode}
+\newbool{pydata@topexists}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{pydata@topislist}
+% Whether the top-level data structure is a list.
+% \begin{macrocode}
+\newbool{pydata@topislist}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{pydata@indict}
+% Whether a dict has been opened.
+% \begin{macrocode}
+\newbool{pydata@indict}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{pydata@haskey}
+% Whether a key has been written (waiting for a value).
+% \begin{macrocode}
+\newbool{pydata@haskey}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\pydata@fhstartstate, \pydata@fhstopstate}
+% Start and stop state tracking for a file handle (|\newwrite|). Each file handle has its own set of state bools of the form |pydata@|\meta{boolname}|@|\meta{fh}. When a file handle is in use, the values of these bools are copied into the |pydata@|\meta{boolname} bools; when the file handle is no longer in use, |pydata@|\meta{boolname} values are copied back into |pydata@|\meta{boolname}|@|\meta{fh}.
+% \begin{macrocode}
+\def\pydata@fhstartstate#1{%
+ \expandafter\pydata@fhstartstate@i\expandafter{\number#1}}
+\newbool{pydata@fhnewstate}
+\def\pydata@fhstartstate@i#1{%
+ \ifcsname ifpydata@canwrite@#1\endcsname
+ \boolfalse{pydata@fhnewstate}%
+ \else
+ \booltrue{pydata@fhnewstate}%
+ \fi
+ \def\do##1{%
+ \providebool{pydata@##1@#1}%
+ \ifbool{pydata@##1@#1}{\booltrue{pydata@##1}}{\boolfalse{pydata@##1}}}%
+ \docsvlist{canwrite, hasmeta, topexists, topislist, indict, haskey}%
+ \ifbool{pydata@fhnewstate}{\booltrue{pydata@canwrite}{}}{}}
+\def\pydata@fhstopstate#1{%
+ \expandafter\pydata@fhstopstate@i\expandafter{\number#1}}
+\def\pydata@fhstopstate@i#1{%
+ \ifcsname ifpydata@canwrite@#1\endcsname
+ \def\do##1{%
+ \ifbool{pydata@##1}{\booltrue{pydata@##1@#1}}{\boolfalse{pydata@##1@#1}}%
+ \boolfalse{pydata@##1}}%
+ \docsvlist{canwrite, hasmeta, topexists, topislist, indict, haskey}%
+ \fi}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{pydata@bufferhaskey}
+% Whether a key has been added to the buffer (waiting for a value).
+%
+% If multiple buffers are in use, all buffers use the same |pydata@bufferhaskey|. Inconsistent state is avoided by requiring that |\pydatasetbuffername| can only be invoked when |pydata@bufferhaskey| is false.
+% \begin{macrocode}
+\newbool{pydata@bufferhaskey}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{File handle}
+%
+% \begin{macro}{\pydata@filehandle}
+% File handle for writing data.
+% \begin{macrocode}
+\let\pydata@filehandle\relax
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\pydata@checkfilehandle}
+% Check whether file handle has been set.
+% \begin{macrocode}
+\def\pydata@checkfilehandle{%
+ \ifx\pydata@filehandle\relax
+ \pydata@error{Undefined file handle; use \string\pydatasetfilehandle}%
+ \fi}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\pydatasetfilehandle, \pydatareleasefilehandle}
+% Set and release file handle. Release isn't strictly required, but it is necessary for basic data checking on the \LaTeX\ side.
+% \begin{macrocode}
+\def\pydatasetfilehandle#1{%
+ \ifx\pydata@filehandle\relax
+ \else
+ \pydata@fhstopstate{\pydata@filehandle}%
+ \fi
+ \let\pydata@filehandle#1\relax
+ \pydata@fhstartstate{#1}}
+\def\pydatareleasefilehandle#1{%
+ \ifx\pydata@filehandle\relax
+ \else
+ \ifx\pydata@filehandle#1\relax
+ \pydata@fhstopstate{#1}%
+ \let\pydata@filehandle\relax
+ \fi
+ \fi
+ \ifcsname ifpydata@canwrite@\number#1\endcsname
+ \ifbool{pydata@canwrite@\number#1}%
+ {\ifbool{pydata@haskey@\number#1}%
+ {\pydata@error{Incomplete data: key is waiting for value}}{}%
+ \ifbool{pydata@indict@\number#1}%
+ {\pydata@error{Incomplete data: dict is not closed}}{}%
+ \ifbool{pydata@topislist@\number#1}%
+ {\pydata@error{Incomplete data: list is not closed}}{}}%
+ {}%
+ \fi}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\pydatasetfilename, \pydataclosefilename}
+% Shortcut for creating a |\newwrite| and then passing the file handle to |\pydatasetfilehandle|. Automatically attempt to close the file handle (if it still exists) at the end of the document. This isn't strictly required since \TeX\ will \href{https://tex.stackexchange.com/a/337291}{automatically close open writes}. Invoking the close macro is necessary for basic data checking on the \LaTeX\ side.
+% \begin{macrocode}
+\def\pydatasetfilename#1{%
+ \ifcsname pydata@fh@#1\endcsname
+ \else
+ \expandafter\newwrite\csname pydata@fh@#1\endcsname
+ \expandafter\immediate\expandafter\openout\csname pydata@fh@#1\endcsname=#1\relax
+ \AtEndDocument{\pydataclosefilename{#1}}%
+ \fi
+ \expandafter\pydatasetfilehandle\expandafter{\csname pydata@fh@#1\endcsname}}
+\def\pydataclosefilename#1{%
+ \ifcsname pydata@fh@#1\endcsname
+ \expandafter\pydatareleasefilehandle\expandafter{\csname pydata@fh@#1\endcsname}%
+ \expandafter\immediate\expandafter\closeout\csname pydata@fh@#1\endcsname
+ \expandafter\let\csname pydata@fh@#1\endcsname\pydata@undefined
+ \fi}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Buffer}
+%
+% Key-value data can be written directly to file once a dict is opened. It is also possible to accumulate key-value data in a ``buffer.'' This is convenient when the data serves as input to an external program that generates cached content. Buffered data can be hashed in memory without being written to file, so the existence of cached content can be checked efficiently.
+%
+% The buffer consists of a sequence of macros of the form |\<buffer_name>line<n>|, where each line of data corresponds to a macro and |<n>| is an integer greater than or equal to one. The length of the buffer is stored in the counter |<buffer_name>length|. The buffer includes comma-separated key-value data, without any opening or closing dict delimiters |{}|.
+%
+% \begin{macro}{pydata@bufferindex}
+% Counter for looping through buffers.
+% \begin{macrocode}
+\newcounter{pydata@bufferindex}
+\setcounter{pydata@bufferindex}{0}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\pydatasetbuffername, \pydata@buffername, \pydata@bufferlinename, \pydata@bufferlengthname}
+% Set the buffer base name and create a corresponding length counter if it does not exist.
+% \begin{macrocode}
+\def\pydatasetbuffername#1{%
+ \ifbool{pydata@bufferhaskey}%
+ {\pydata@error{Cannot change buffers when a buffered key is waiting for a value}}%
+ {}%
+ \def\pydata@buffername{#1}%
+ \def\pydata@bufferlinename{#1line}%
+ \def\pydata@bufferlengthname{#1length}%
+ \ifcsname c@\pydata@bufferlengthname\endcsname
+ \else
+ \expandafter\newcounter\expandafter{\pydata@bufferlengthname}%
+ \fi
+ \expandafter\setcounter\expandafter{\pydata@bufferlengthname}{0}}
+\pydatasetbuffername{pydata@defaultbuffer}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\pydatawritebuffer}
+% Write existing buffer macros to file handle.
+% \begin{macrocode}
+\def\pydatawritebuffer{%
+ \ifnum\expandafter\value\expandafter{\pydata@bufferlengthname}<1\relax
+ \pydata@error{Cannot write empty buffer}%
+ \fi
+ \ifbool{pydata@indict}{}{\pydata@error{Cannot write a buffer unless in a dict}}%
+ \ifbool{pydata@bufferhaskey}%
+ {\pydata@error{Cannot write buffer when a buffered key is waiting for a value}}{}%
+ \setcounter{pydata@bufferindex}{1}%
+ \loop\unless\ifnum\value{pydata@bufferindex}>%
+ \expandafter\value\expandafter{\pydata@bufferlengthname}\relax
+ \immediate\write\pydata@filehandle{%
+ \csname\pydata@bufferlinename\arabic{pydata@bufferindex}\endcsname}%
+ \stepcounter{pydata@bufferindex}%
+ \repeat
+ \setcounter{pydata@bufferindex}{0}}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\pydataclearbuffername}
+% Delete the buffer: |\let| all line macros to an undefined macro, and set length to zero.
+% \begin{macrocode}
+\def\pydataclearbuffername#1{%
+ \def\pydata@clearbuffername{#1}%
+ \ifcsname c@#1length\endcsname
+ \else
+ \pydata@error{Buffer #1 does not exist}%
+ \fi
+ \setcounter{pydata@bufferindex}{1}%
+ \loop\unless\ifnum\value{pydata@bufferindex}>\value{#1length}\relax
+ \expandafter\let
+ \csname#1line\arabic{pydata@bufferindex}\endcsname\pydata@undefined
+ \stepcounter{pydata@bufferindex}%
+ \repeat
+ \setcounter{#1length}{0}%
+ \setcounter{pydata@bufferindex}{0}%
+ \ifx\pydata@clearbuffername\pydata@buffername
+ \boolfalse{pydata@bufferhaskey}%
+ \fi}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\pydatabuffermdfivesum}
+% Calculate buffer MD5.
+% \begin{macrocode}
+\def\pydatabuffermdfivesum{%
+ \pdf@mdfivesum{%
+ \ifnum\expandafter\value\expandafter{\pydata@bufferlengthname}<1
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \fi
+ {}{\pydatabuffermdfivesum@i{1}}}}
+\def\pydatabuffermdfivesum@i#1{%
+ \csname\pydata@bufferlinename#1\endcsname^^J%
+ \ifnum\expandafter\value\expandafter{\pydata@bufferlengthname}=#1
+ \expandafter\@gobble
+ \else
+ \expandafter\@firstofone
+ \fi
+ {\expandafter\pydatabuffermdfivesum@i\expandafter{\the\numexpr#1+1 }}}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{String processing}
+%
+% Ensure correct catcode for double quotation mark, which will be used for delimiting all Python string literals.
+% \begin{macrocode}
+\begingroup
+\catcode`\"=12\relax
+% \end{macrocode}
+%
+%
+% \begin{macro}{\pydata@escstrtext}
+% Escape string text by replacing |\| with |\\| and |"| with |\"|. Any text that requires expansion must be expanded prior to escaping. The string text is processed with |\detokenize| to ensure catcodes and prepare it for writing. This is redundant in cases where text has already been processed with |\FVExtraDetokenizeVArg|.
+% \begin{macrocode}
+\begingroup
+\catcode`\!=0
+!catcode`!\=12
+!gdef!pydata@escstrtext#1{%
+ !expandafter!pydata@escstrtext@i!detokenize{#1}\!FV@Sentinel}
+!gdef!pydata@escstrtext@i#1\#2!FV@Sentinel{%
+ !if!relax!detokenize{#2}!relax
+ !expandafter!@firstoftwo
+ !else
+ !expandafter!@secondoftwo
+ !fi
+ {!pydata@escstrtext@ii#1"!FV@Sentinel}%
+ {!pydata@escstrtext@ii#1\\"!FV@Sentinel!pydata@escstrtext@i#2!FV@Sentinel}}
+!gdef!pydata@escstrtext@ii#1"#2!FV@Sentinel{%
+ !if!relax!detokenize{#2}!relax
+ !expandafter!@firstoftwo
+ !else
+ !expandafter!@secondoftwo
+ !fi
+ {#1}%
+ {#1\"!pydata@escstrtext@ii#2!FV@Sentinel}}
+!endgroup
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\pydata@quotestr}
+% Escape a string then quote it with |"|.
+% \begin{macrocode}
+\gdef\pydata@quotestr#1{%
+ "\pydata@escstrtext{#1}"}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\pydata@mlstropen, \pydata@mlstrclose}
+% Multi-line string delimiters. The opening delimiter has a trailing backslash to prevent the string from starting with a newline.
+% \begin{macrocode}
+\begingroup
+\catcode`\!=0
+!catcode`!\=12
+!gdef!pydata@mlstropen{"""\}
+!gdef!pydata@mlstrclose{"""}
+!endgroup
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \noindent End |"| catcode.
+% \begin{macrocode}
+\endgroup
+% \end{macrocode}
+%
+%
+%
+% \subsection{Metadata}
+%
+% \begin{macro}{\pydata@schema}
+% Macro storing key-value schema data.
+% \begin{macrocode}
+\def\pydata@schema{}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\pydatasetschemamissing, \pydata@schemamissing}
+% Define behavior for missing key-value pairs in a schema.
+% \begin{macrocode}
+\let\pydata@schemamissing@error\relax
+\let\pydata@schemamissing@rawstr\relax
+\let\pydata@schemamissing@evalany\relax
+\def\pydatasetschemamissing#1{%
+ \ifcsname pydata@schemamissing@\detokenize{#1}\endcsname
+ \else
+ \pydata@error{Invalid schema missing setting #1}%
+ \fi
+ \def\pydata@schemamissing{#1}}
+\pydatasetschemamissing{error}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\pydatasetschemakeytype}
+% Define a key's schema. For example, |\pydatasetschemakeytype{key}{int}|.
+% \begin{macrocode}
+\begingroup
+\catcode`\:=12\relax
+\catcode`\,=12\relax
+\gdef\pydatasetschemakeytype#1#2{%
+ \ifbool{pydata@hasmeta}{\pydata@error{Must create schema before writing metadata}}{}%
+ \ifbool{pydata@topexists}{\pydata@error{Must create schema before writing data}}{}%
+ \expandafter\def\expandafter\pydata@schema\expandafter{%
+ \pydata@schema\pydata@quotestr{#1}: \pydata@quotestr{#2}, }}
+\endgroup
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\pydataclearschema}
+% Delete existing schema. This isn't done automatically upon writing so that a schema can be defined and then reused.
+% \begin{macrocode}
+\def\pydataclearschema{%
+ \def\pydata@schema{}}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\pydataclearmeta}
+% Delete existing metadata. This isn't done automatically upon writing so that metadata can be defined and then reused.
+% \begin{macrocode}
+\def\pydataclearmeta{%
+ \pydatasetschemamissing{error}%
+ \pydataclearschema}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\pydatawritemeta}
+% Write metadata to file, including any schema.
+% \begin{macrocode}
+\begingroup
+\catcode`\:=12\relax
+\catcode`\#=12\relax
+\catcode`\,=12\relax
+\gdef\pydatawritemeta{%
+ \ifbool{pydata@canwrite}%
+ {}{\pydata@error{Data was already written; cannot write metadata}}%
+ \ifbool{pydata@hasmeta}{\pydata@error{Already wrote metadata}}{}%
+ \ifbool{pydata@topexists}{\pydata@error{Must write metadata before writing data}}{}%
+ \edef\pydata@meta@exp{%
+ # latex2pydata metadata:
+ \@charlb
+ \pydata@quotestr{schema_missing}:
+ \expandafter\pydata@quotestr\expandafter{\pydata@schemamissing},
+ \pydata@quotestr{schema}:
+ \ifx\pydata@schema\pydata@empty
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \fi
+ {None}{\@charlb\pydata@schema\@charrb},
+ \@charrb}%
+ \immediate\write\pydata@filehandle{\pydata@meta@exp}%
+ \booltrue{pydata@hasmeta}}
+\endgroup
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Collection delimiters}
+%
+% \begin{macro}{\pydatawritelistopen, \pydatawritelistclose}
+% Write list delimiters. These are only used when the top-level data structure is a list: |list[dict[str, str]]|.
+% \begin{macrocode}
+\begingroup
+\catcode`\[=12\relax
+\catcode`\]=12\relax
+\gdef\pydatawritelistopen{%
+ \pydata@checkfilehandle
+ \ifbool{pydata@canwrite}%
+ {}{\pydata@error{Data structure is closed; cannot write delim}}%
+ \ifbool{pydata@topexists}%
+ {\pydata@error{Top-level data structure already exists}}{}%
+ \immediate\write\pydata@filehandle{[}%
+ \booltrue{pydata@topexists}%
+ \booltrue{pydata@topislist}}
+\gdef\pydatawritelistclose{%
+ \ifbool{pydata@topexists}%
+ {}{\pydata@error{No data structure is open; cannot write delim}}%
+ \ifbool{pydata@topislist}%
+ {}{\pydata@error{Top-level data structure is not a list}}%
+ \ifbool{pydata@haskey}%
+ {\pydata@error{Cannot close data structure when key is waiting for value}}{}%
+ \immediate\write\pydata@filehandle{]}%
+ \boolfalse{pydata@topexists}%
+ \boolfalse{pydata@topislist}%
+ \boolfalse{pydata@hasmeta}%
+ \boolfalse{pydata@canwrite}}
+\endgroup
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\pydatawritedictopen, \pydatawritedictclose}
+% Write dict delimiters. These are not the top-level data structure for |list[dict[str, str]]| but are the top-level data structure for |dict[str, str]|.
+% \begin{macrocode}
+\begingroup
+\catcode`\,=12\relax
+\gdef\pydatawritedictopen{%
+ \ifbool{pydata@topislist}%
+ {\ifbool{pydata@indict}{\pydata@error{Already in a dict; cannot nest}}{}%
+ \immediate\write\pydata@filehandle{\@charlb}%
+ \booltrue{pydata@indict}}%
+ {\pydata@checkfilehandle
+ \ifbool{pydata@canwrite}%
+ {}{\pydata@error{Data structure is closed; cannot write delim}}%
+ \ifbool{pydata@topexists}%
+ {\pydata@error{Top-level data structure already exists}}{}%
+ \immediate\write\pydata@filehandle{\@charlb}%
+ \booltrue{pydata@topexists}%
+ \booltrue{pydata@indict}}}
+\gdef\pydatawritedictclose{%
+ \ifbool{pydata@indict}{}{\pydata@error{No dict is open; cannot write delim}}%
+ \ifbool{pydata@haskey}%
+ {\pydata@error{Cannot close data structure when key is waiting for value}}{}%
+ \ifbool{pydata@topislist}%
+ {\immediate\write\pydata@filehandle{\@charrb,}%
+ \boolfalse{pydata@indict}}%
+ {\immediate\write\pydata@filehandle{\@charrb}%
+ \boolfalse{pydata@indict}%
+ \boolfalse{pydata@topexists}%
+ \boolfalse{pydata@hasmeta}%
+ \boolfalse{pydata@canwrite}}}
+\endgroup
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Keys and values}
+%
+% \begin{macro}{\pydatawritekey, \pydatabufferkey}
+% Write key to file or append it to the buffer.
+% \begin{macrocode}
+\begingroup
+\catcode`\:=12\relax
+\gdef\pydatawritekey{%
+ \FVExtraReadVArg{\FVExtraDetokenizeVArg{\pydatawritekey@i}}}
+\gdef\pydatawritekey@i#1{%
+ \ifbool{pydata@indict}{}{\pydata@error{Cannot write a key unless in a dict}}%
+ \ifbool{pydata@haskey}{\pydata@error{Cannot write a key when waiting for a value}}{}%
+ \immediate\write\pydata@filehandle{%
+ \pydata@quotestr{#1}:%
+ }%
+ \booltrue{pydata@haskey}}
+\gdef\pydatabufferkey{%
+ \FVExtraReadVArg{\FVExtraDetokenizeVArg{\pydatabufferkey@i}}}
+\gdef\pydatabufferkey@i#1{%
+ \ifbool{pydata@bufferhaskey}%
+ {\pydata@error{Cannot buffer a key when waiting for a value}}{}%
+ \expandafter\stepcounter\expandafter{\pydata@bufferlengthname}%
+ \expandafter\edef\csname
+ \pydata@bufferlinename\expandafter\arabic\expandafter{\pydata@bufferlengthname}%
+ \endcsname{%
+ \pydata@quotestr{#1}:%
+ }%
+ \booltrue{pydata@bufferhaskey}}
+\endgroup
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\pydatawritevalue, \pydatabuffervalue}
+% Write a value to file or append it to the buffer.
+% \begin{macrocode}
+\begingroup
+\catcode`\,=12\relax
+\gdef\pydatawritevalue{%
+ \FVExtraReadVArg{\FVExtraDetokenizeVArg{\pydatawritevalue@i}}}
+\gdef\pydatawritevalue@i#1{%
+ \ifbool{pydata@haskey}{}{\pydata@error{Cannot write value when waiting for a key}}%
+ \immediate\write\pydata@filehandle{%
+ \pydata@quotestr{#1},%
+ }%
+ \boolfalse{pydata@haskey}}
+\gdef\pydatabuffervalue{%
+ \FVExtraReadVArg{\FVExtraDetokenizeVArg{\pydatabuffervalue@i}}}
+\gdef\pydatabuffervalue@i#1{%
+ \ifbool{pydata@bufferhaskey}%
+ {}{\pydata@error{Cannot buffer value when waiting for a key}}%
+ \expandafter\stepcounter\expandafter{\pydata@bufferlengthname}%
+ \expandafter\edef\csname
+ \pydata@bufferlinename\expandafter\arabic\expandafter{\pydata@bufferlengthname}%
+ \endcsname{%
+ \pydata@quotestr{#1},%
+ }%
+ \boolfalse{pydata@bufferhaskey}}
+\endgroup
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\pydatawritekeyvalue, \pydatabufferkeyvalue}
+% Write a key and a single-line value to file simultaneously, or append them to the buffer.
+% \begin{macrocode}
+\begingroup
+\catcode`\:=12\relax
+\catcode`\,=12\relax
+\gdef\pydatawritekeyvalue{%
+ \FVExtraReadVArg{\FVExtraDetokenizeVArg{\pydatawritekeyvalue@i}}}
+\gdef\pydatawritekeyvalue@i#1{%
+ \FVExtraReadVArg{\FVExtraDetokenizeVArg{\pydatawritekeyvalue@ii{#1}}}}
+\gdef\pydatawritekeyvalue@ii#1#2{%
+ \ifbool{pydata@indict}{}{\pydata@error{Cannot write a key unless in a dict}}%
+ \ifbool{pydata@haskey}{\pydata@error{Cannot write a key when waiting for a value}}{}%
+ \immediate\write\pydata@filehandle{%
+ \pydata@quotestr{#1}: \pydata@quotestr{#2},%
+ }}
+\gdef\pydatabufferkeyvalue{%
+ \FVExtraReadVArg{\FVExtraDetokenizeVArg{\pydatabufferkeyvalue@i}}}
+\gdef\pydatabufferkeyvalue@i#1{%
+ \FVExtraReadVArg{\FVExtraDetokenizeVArg{\pydatabufferkeyvalue@ii{#1}}}}
+\gdef\pydatabufferkeyvalue@ii#1#2{%
+ \ifbool{pydata@bufferhaskey}%
+ {\pydata@error{Cannot buffer a key when waiting for a value}}{}%
+ \expandafter\stepcounter\expandafter{\pydata@bufferlengthname}%
+ \expandafter\edef\csname
+ \pydata@bufferlinename\expandafter\arabic\expandafter{\pydata@bufferlengthname}%
+ \endcsname{%
+ \pydata@quotestr{#1}: \pydata@quotestr{#2},%
+ }}
+\endgroup
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\pydatawritemlvaluestart, \pydatawritemlvalueline, \pydatawritemlvalueend, \pydatabuffermlvaluestart, \pydatabuffermlvalueline, \pydatabuffermlvalueend}
+% Write a line of a multi-line value to file or append it to the buffer. Write the end delimiter of the value to file or append it to the buffer.
+% \begin{macrocode}
+\begingroup
+\catcode`\,=12\relax
+\gdef\pydatawritemlvaluestart{%
+ \ifbool{pydata@haskey}{}{\pydata@error{Cannot write value when waiting for a key}}%
+ \immediate\write\pydata@filehandle{%
+ \pydata@mlstropen
+ }}
+\gdef\pydatawritemlvalueline#1{%
+ \ifbool{pydata@haskey}{}{\pydata@error{Cannot write value when waiting for a key}}%
+ \immediate\write\pydata@filehandle{%
+ \pydata@escstrtext{#1}%
+ }}
+\gdef\pydatawritemlvalueend{%
+ \ifbool{pydata@haskey}{}{\pydata@error{Cannot write value when waiting for a key}}%
+ \immediate\write\pydata@filehandle{%
+ \pydata@mlstrclose,%
+ }%
+ \boolfalse{pydata@haskey}}
+\gdef\pydatabuffermlvaluestart{%
+ \ifbool{pydata@bufferhaskey}%
+ {}{\pydata@error{Cannot buffer value when waiting for a key}}%
+ \expandafter\stepcounter\expandafter{\pydata@bufferlengthname}%
+ \expandafter\edef\csname
+ \pydata@bufferlinename\expandafter\arabic\expandafter{\pydata@bufferlengthname}%
+ \endcsname{%
+ \pydata@mlstropen
+ }}
+\gdef\pydatabuffermlvalueline#1{%
+ \ifbool{pydata@bufferhaskey}%
+ {}{\pydata@error{Cannot buffer value when waiting for a key}}%
+ \expandafter\stepcounter\expandafter{\pydata@bufferlengthname}%
+ \expandafter\edef\csname
+ \pydata@bufferlinename\expandafter\arabic\expandafter{\pydata@bufferlengthname}%
+ \endcsname{%
+ \pydata@escstrtext{#1}%
+ }}
+\gdef\pydatabuffermlvalueend{%
+ \ifbool{pydata@bufferhaskey}%
+ {}{\pydata@error{Cannot buffer value when waiting for a key}}%
+ \expandafter\stepcounter\expandafter{\pydata@bufferlengthname}%
+ \expandafter\edef\csname
+ \pydata@bufferlinename\expandafter\arabic\expandafter{\pydata@bufferlengthname}%
+ \endcsname{%
+ \pydata@mlstrclose,%
+ }%
+ \boolfalse{pydata@bufferhaskey}}
+\endgroup
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{pydatawritemlvalue}
+% \begin{macrocode}
+\newenvironment{pydatawritemlvalue}%
+ {\VerbatimEnvironment
+ \pydatawritemlvaluestart
+ \begin{VerbatimWrite}[writer=\pydatawritemlvalueline]}%
+ {\end{VerbatimWrite}}
+\AfterEndEnvironment{pydatawritemlvalue}{\pydatawritemlvalueend}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{pydatabuffermlvalue}
+% \begin{macrocode}
+\newenvironment{pydatabuffermlvalue}%
+ {\VerbatimEnvironment
+ \begin{VerbatimBuffer}[buffername=pydata@tmpbuffer, globalbuffer=true]}%
+ {\end{VerbatimBuffer}}
+\AfterEndEnvironment{pydatabuffermlvalue}{%
+ \pydatabuffermlvaluestart
+ \setcounter{pydata@bufferindex}{1}%
+ \loop\unless\ifnum\value{pydata@bufferindex}>\value{pydata@tmpbufferlength}\relax
+ \expandafter\let\expandafter\pydata@tmpbufferline
+ \csname pydata@tmpbufferline\arabic{pydata@bufferindex}\endcsname
+ \expandafter\let
+ \csname pydata@tmpbufferline\arabic{pydata@bufferindex}\endcsname\pydata@undefined
+ \expandafter\pydatabuffermlvalueline\expandafter{\pydata@tmpbufferline}%
+ \stepcounter{pydata@bufferindex}%
+ \repeat
+ \setcounter{pydata@tmpbufferlength}{0}%
+ \setcounter{pydata@bufferindex}{0}%
+ \pydatabuffermlvalueend}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \iffalse
+%</package>
+% \fi
+%% \Finale
+\endinput
diff --git a/macros/latex/contrib/latex2pydata/latex2pydata.ins b/macros/latex/contrib/latex2pydata/latex2pydata.ins
new file mode 100644
index 0000000000..6367807032
--- /dev/null
+++ b/macros/latex/contrib/latex2pydata/latex2pydata.ins
@@ -0,0 +1,58 @@
+%% Copyright (C) 2023 by Geoffrey M. Poore <gpoore@gmail.com>
+%% --------------------------------------------------------------------------
+%% This work may be distributed and/or modified under the
+%% conditions of the LaTeX Project Public License, either version 1.3c
+%% of this license or (at your option) any later version.
+%% The latest version of this license is in
+%% http://www.latex-project.org/lppl.txt
+%% and version 1.3c or later is part of all distributions of LaTeX
+%% version 2008/05/04 or later.
+%%
+%% This work has the LPPL maintenance status `maintained'.
+%%
+%% The Current Maintainer of this work is Geoffrey M. Poore.
+%%
+%% This work consists of the files latex2pydata.dtx and latex2pydata.ins
+%% and the derived filebase latex2pydata.sty.
+%%
+
+\input docstrip.tex
+\keepsilent
+\askforoverwritefalse
+
+\usedir{tex/latex/latex2pydata}
+
+\preamble
+
+This is a generated file.
+
+Copyright (C) 2023 by Geoffrey M. Poore <gpoore@gmail.com>
+--------------------------------------------------------------------------
+This work may be distributed and/or modified under the
+conditions of the LaTeX Project Public License, either version 1.3c
+of this license or (at your option) any later version.
+The latest version of this license is in
+ http://www.latex-project.org/lppl.txt
+and version 1.3c or later is part of all distributions of LaTeX
+version 2008/05/04 or later.
+
+\endpreamble
+
+\generate{\file{latex2pydata.sty}{\from{latex2pydata.dtx}{package}}}
+
+\obeyspaces
+\Msg{***************************************************************}
+\Msg{* *}
+\Msg{* To finish the installation you have to move the following *}
+\Msg{* file into a directory searched by TeX: *}
+\Msg{* *}
+\Msg{* latex2pydata.sty *}
+\Msg{* *}
+\Msg{* To produce the documentation run the file latex2pydata.dtx *}
+\Msg{* through LaTeX. *}
+\Msg{* *}
+\Msg{* Happy TeXing! *}
+\Msg{* *}
+\Msg{***************************************************************}
+
+\endbatchfile
diff --git a/macros/latex/contrib/latex2pydata/latex2pydata.pdf b/macros/latex/contrib/latex2pydata/latex2pydata.pdf
new file mode 100644
index 0000000000..96eca7e89d
--- /dev/null
+++ b/macros/latex/contrib/latex2pydata/latex2pydata.pdf
Binary files differ
diff --git a/macros/latex/contrib/logoetalab/doc/logoetalab-doc.pdf b/macros/latex/contrib/logoetalab/doc/logoetalab-doc.pdf
index dc0bfc22d4..11afad20da 100644
--- a/macros/latex/contrib/logoetalab/doc/logoetalab-doc.pdf
+++ b/macros/latex/contrib/logoetalab/doc/logoetalab-doc.pdf
Binary files differ
diff --git a/macros/latex/contrib/logoetalab/doc/logoetalab-doc.tex b/macros/latex/contrib/logoetalab/doc/logoetalab-doc.tex
index b0de4f4c92..9fc712291d 100644
--- a/macros/latex/contrib/logoetalab/doc/logoetalab-doc.tex
+++ b/macros/latex/contrib/logoetalab/doc/logoetalab-doc.tex
@@ -1,6 +1,6 @@
% !TeX TXS-program:compile = txs:///arara
-% arara: pdflatex: {shell: yes, synctex: no, interaction: batchmode}
-% arara: pdflatex: {shell: yes, synctex: no, interaction: batchmode} if found('log', '(undefined references|Please rerun|Rerun to get)')
+% arara: pdflatex: {shell: no, synctex: no, interaction: batchmode}
+% arara: pdflatex: {shell: no, synctex: no, interaction: batchmode} if found('log', '(undefined references|Please rerun|Rerun to get)')
\documentclass[french,11pt,a4paper]{article}
\usepackage[utf8]{inputenc}
@@ -37,8 +37,8 @@
\usepackage[margin=2cm]{geometry}
\setlength{\parindent}{0pt}
-\def\TPversion{0.1.0}
-\def\TPdate{17 août 2023}
+\def\TPversion{0.1.1}
+\def\TPdate{19 novembre 2023}
\def\HtRet{0.45}\def\LgRect{1.5}
\usepackage{tcolorbox}
@@ -155,6 +155,10 @@ L'idée est de pouvoir intégrer, dans un document \LaTeX, un logo relatif à la
Les logos sont au format (vectoriel) \MontreCode{pdf}, et ont été obtenus à partir d'un fichier fichier \MontreCode{svg} sous licence CC BY 2.0 FR (\href{https://fr.m.wikipedia.org/wiki/Fichier:Logo-licence-ouverte2.svg}{[lien]}).
+\smallskip
+
+\texttt{(màj 0.1.1)} Une version \TikZ{} des logos est également disponible, ce qui permet d'utiliser des couleurs personnalisés.
+
\subsection{Chargement}
Le package se charge dans le préambule, via \MontreCode{\textbackslash usepackage\{logoetalab\}}.
@@ -165,9 +169,9 @@ Les seuls packages chargés sont \MontreCode{graphicx}, \MontreCode{calc} et \Mo
\usepackage{logoetalab}
\end{codehigh}
-\subsection{Masque de nommage des fichiers}
+\subsection{Masque de nommage des fichiers pdf}
-Chaque logo est nommé sous la forme \MontreCode{LogoLicenceOuverte-<Couleur>-<Orientation>.pdf}, de sorte que les logos peuvent être insérés directement via la commande \MontreCode{\textbackslash includegraphics} \textit{classique}.
+Chaque logo (pdf) est nommé sous la forme \MontreCode{LogoLicenceOuverte-<Couleur>-<Orientation>.pdf}, de sorte que les logos peuvent être insérés directement via la commande \MontreCode{\textbackslash includegraphics} \textit{classique}.
\begin{demohigh}[language=latex/latex3,style/main=cyan!10,style/code=cyan!10,style/demo=cyan!10]
\includegraphics[height=5cm]{LogoLicenceOuverte-Gris-V.pdf}\par
@@ -176,20 +180,27 @@ Chaque logo est nommé sous la forme \MontreCode{LogoLicenceOuverte-<Couleur>-<O
\subsection{Utilisation}
-Le package propose deux commandes :
+Le package propose deux commandes (et deux versions) :
\medskip
\begin{itemize}
\item \MontreCode{\textbackslash loetalab} pour un affichage du logo en mode \textit{en ligne} (raccourci de \textsc{\textbf{L}icence\textbf{O}uverte\textbf{Etalab}}) ;
- \item \MontreCode{\textbackslash affloetalab} pour un affichage \textit{autonome} (raccourci de \textsc{\textbf{Aff}iche\textbf{L}icence\textbf{O}uverte\textbf{Etalab}}).
+ \item \MontreCode{\textbackslash affloetalab} pour un affichage \textit{autonome} (raccourci de \textsc{\textbf{Aff}iche\textbf{L}icence\textbf{O}uverte\textbf{Etalab}}) ;
+ \item \MontreCode{\textbackslash loetalabtkz} pour un affichage du logo, version \TikZ, en mode \textit{en ligne} ;
+ \item \MontreCode{\textbackslash affloetalabtkz} pour un affichage \textit{autonome}, version \TikZ.
\end{itemize}
\medskip
\begin{codehigh}[language=latex/latex2,style/main=cyan!10,style/code=cyan!10]
+%version pdf
\loetalab(*)[Options]
\affloetalab(*)[Options]
+
+%version tikz
+\loetalabtkz(*)[Options]
+\affloetalabtkz(*)[Options]
\end{codehigh}
La différence entre les deux se situe au niveau de la taille et de l'alignement vertical du logo.
@@ -214,7 +225,29 @@ La différence entre les deux se situe au niveau de la taille et de l'alignement
\loetalab\loetalab*\affloetalab\affloetalab*
\end{demohigh}
-\section{Les commandes}
+\begin{demohigh}[language=latex/latex3,style/main=cyan!10,style/code=cyan!10,style/demo=cyan!10]
+\loetalabtkz
+\end{demohigh}
+
+\begin{demohigh}[language=latex/latex3,style/main=cyan!10,style/code=cyan!10,style/demo=cyan!10]
+\loetalabtkz*
+\end{demohigh}
+
+\begin{demohigh}[language=latex/latex3,style/main=cyan!10,style/code=cyan!10,style/demo=cyan!10]
+\affloetalabtkz
+\end{demohigh}
+
+\begin{demohigh}[language=latex/latex3,style/main=cyan!10,style/code=cyan!10,style/demo=cyan!10]
+\affloetalabtkz*
+\end{demohigh}
+
+\begin{demohigh}[language=latex/latex3,style/main=cyan!10,style/code=cyan!10,style/demo=cyan!10]
+\loetalabtkz\loetalabtkz*\affloetalabtkz\affloetalabtkz*
+\end{demohigh}
+
+\pagebreak
+
+\section{Les commandes en mode pdf}
\subsection{Affichage en mode \textit{en ligne}}
@@ -223,7 +256,7 @@ La commande dédiée à un affichage \textit{en ligne} est \MontreCode{\textback
\medskip
\begin{itemize}[leftmargin=*]
- \item La version étoilée force l'affichage du logo en format paysage.
+ \item La version étoilée force l'affichage du logo en format \textit{paysage}.
\item L'argument optionnel, et entre \MontreCode{[...]} propose les clés suivantes :
\begin{itemize}
\item la clé \MontreCode{Couleur} pour choisir une couleur, parmi \MontreCode{Noir/Bleu/Gris/Marron/Rouge/Vert/Violet}, et vaut \MontreCode{Noir} par défaut ;
@@ -236,7 +269,7 @@ La commande dédiée à un affichage \textit{en ligne} est \MontreCode{\textback
\medskip
-La hauteur du logo est calculée (et fixée) en fonction :
+La hauteur (auto) du logo est calculée (et fixée) en fonction :
\begin{itemize}
\item de 90\,\% de la hauteur globale, \underline{dans la police courante}, des lettres \fbox{qB} ;
@@ -364,11 +397,161 @@ La hauteur du logo est calculée (et fixée) en fonction :
\LARGE\sffamily\affloetalab[Couleur=Vert,Legende,TexteLegende={Licence Etalab 2.0}]
\end{demohigh}
+\pagebreak
+
+\section{Les commandes en mode TikZ}
+
+\subsection{Affichage en mode \textit{en ligne}}
+
+La commande dédiée à un affichage \textit{en ligne} est \MontreCode{\textbackslash loetalabtkz}.
+
+\medskip
+
+\begin{itemize}[leftmargin=*]
+ \item La version étoilée force l'affichage du logo en format \textit{paysage}.
+ \item L'argument optionnel, et entre \MontreCode{[...]} propose les clés suivantes :
+ \begin{itemize}
+ \item la clé \MontreCode{Couleur} pour choisir une couleur, et vaut \MontreCode{black} par défaut ;
+ \item la clé \MontreCode{Hauteur} pour la hauteur du logo, qui vaut \MontreCode{auto} par défaut ;
+ \item la clé \MontreCode{DecalageV} pour paramétrer le décalage vertical du logo, qui vaut \MontreCode{auto} par défaut.
+ \end{itemize}
+\end{itemize}
+
+\medskip
+
+La hauteur (auto) du logo est calculée (et fixée) en fonction :
+
+\begin{itemize}
+ \item de 90\,\% de la hauteur globale, \underline{dans la police courante}, des lettres \fbox{qB} ;
+ \item décalée vers le bas d'un peu moins que la profondeur, \underline{dans la police courante}, de la lettre \fbox{q}.
+\end{itemize}
+
+\medskip
+
+\begin{tblr}{hlines,width=\linewidth,colspec={Q[l,m]X[l,m]},row{1}={magenta!10},row{2-Z}={cyan!10}}
+ \SetCell[r=1,c=2]{c,m} \fakeverb{\loetalabtkz} & \\
+ {\tiny\fakeverb{\tiny}} & {\tiny Essai de logo \loetalabtkz{} en ligne} \\
+ {\scriptsize\fakeverb{\scriptsize}} & {\scriptsize Essai de logo \loetalabtkz{} en ligne} \\
+ {\footnotesize\fakeverb{\footnotesize}} & {\footnotesize Essai de logo \loetalabtkz{} en ligne} \\
+ {\small\fakeverb{\small}} & {\small Essai de logo \loetalabtkz{} en ligne} \\
+ {\normalsize\fakeverb{\normalsize}} & {\normalsize Essai de logo \loetalabtkz{} en ligne} \\
+ {\large\fakeverb{\large}} & {\large Essai de logo \loetalabtkz{} en ligne} \\
+ {\Large\fakeverb{\Large}} & {\Large Essai de logo \loetalabtkz{} en ligne} \\
+ {\LARGE\fakeverb{\LARGE}} & {\LARGE Essai de logo \loetalabtkz{} en ligne} \\
+ {\huge\fakeverb{\huge}} & {\huge Essai de logo \loetalabtkz{} en ligne} \\
+ {\Huge\fakeverb{\Huge}} & {\Huge Essai de logo \loetalabtkz{} en ligne} \\
+\end{tblr}
+
+\medskip
+
+\begin{tblr}{hlines,width=\linewidth,colspec={Q[l,m]X[l,m]},row{1}={magenta!10},row{2-Z}={cyan!10}}
+ \SetCell[r=1,c=2]{c,m} \fakeverb{\loetalab*} & \\
+ {\tiny\fakeverb{\tiny\sffamily}} & {\tiny\sffamily Essai de logo \loetalabtkz*{} en ligne} \\
+ {\scriptsize\fakeverb{\scriptsize\sffamily}} & {\scriptsize\sffamily Essai de logo \loetalabtkz*{} en ligne} \\
+ {\footnotesize\fakeverb{\footnotesize\sffamily}} & {\footnotesize\sffamily Essai de logo \loetalabtkz*{} en ligne} \\
+ {\small\fakeverb{\small\sffamily}} & {\small\sffamily Essai de logo \loetalabtkz*{} en ligne} \\
+ {\normalsize\fakeverb{\normalsize\sffamily}} & {\normalsize\sffamily Essai de logo \loetalabtkz*{} en ligne} \\
+ {\large\fakeverb{\large\sffamily}} & {\large\sffamily Essai de logo \loetalabtkz*{} en ligne} \\
+ {\Large\fakeverb{\Large\sffamily}} & {\Large\sffamily Essai de logo \loetalabtkz*{} en ligne} \\
+ {\LARGE\fakeverb{\LARGE\sffamily}} & {\LARGE\sffamily Essai de logo \loetalabtkz*{} en ligne} \\
+ {\huge\fakeverb{\huge\sffamily}} & {\huge\sffamily Essai de logo \loetalabtkz*{} en ligne} \\
+ {\Huge\fakeverb{\Huge\sffamily}} & {\Huge\sffamily Essai de logo \loetalabtkz*{} en ligne} \\
+\end{tblr}
+
+\begin{demohigh}[language=latex/latex2,style/main=cyan!10,style/code=cyan!10,style/demo=cyan!10]
+ \small Publication sous \loetalabtkz*[Couleur=teal]~Licence Etalab 2.0
+\end{demohigh}
+
+\begin{demohigh}[language=latex/latex2,style/main=cyan!10,style/code=cyan!10,style/demo=cyan!10]
+ \LARGE\sffamily Publication sous \loetalabtkz[Couleur=lime]~Licence Etalab 2.0
+\end{demohigh}
+
+\subsection{Affichage en mode \textit{autonome}}
+
+La commande dédiée à un affichage \textit{autonome} est \MontreCode{\textbackslash affloetalabtkz}.
+
+\medskip
+
+\begin{itemize}[leftmargin=*]
+ \item La version étoilée force l'affichage du logo en format paysage.
+ \item L'argument optionnel, et entre \MontreCode{[...]} propose les clés suivantes :
+ \begin{itemize}
+ \item la clé \MontreCode{Couleur} pour choisir une couleur, et vaut \MontreCode{Noir} par défaut ;
+ \item la clé \MontreCode{Hauteur} pour la hauteur du logo, qui vaut \MontreCode{auto} par défaut ;
+ \item la clé \MontreCode{DecalageV} pour paramétrer le décalage vertical du logo, qui vaut \MontreCode{auto} par défaut.
+ \end{itemize}
+\end{itemize}
+
+\medskip
+
+La hauteur du logo est calculée (et fixée) en fonction :
+
+\begin{itemize}
+ \item du double de la hauteur globale, \underline{dans la police courante}, de la boîte formée de la lettre \fbox{B} ;
+ \item décalée vers le bas de la moitié de la hauteur, \underline{dans la police courante}, de la boîte \fbox{B}.
+\end{itemize}
+
+\begin{tblr}{hlines,width=\linewidth,colspec={Q[l,m]X[l,m]},row{1}={magenta!10},row{2-Z}={cyan!10}}
+ \SetCell[r=1,c=2]{c,m} \fakeverb{\affloetalabtkz} & \\
+ {\tiny\fakeverb{\tiny}} & {\tiny \affloetalabtkz{} en mode autonome} \\
+ {\scriptsize\fakeverb{\scriptsize}} & {\scriptsize \affloetalabtkz{} en mode autonome} \\
+ {\footnotesize\fakeverb{\footnotesize}} & {\footnotesize \affloetalabtkz{} en mode autonome} \\
+ {\small\fakeverb{\small}} & {\small \affloetalabtkz{} en mode autonome} \\
+ {\normalsize\fakeverb{\normalsize}} & {\normalsize \affloetalabtkz{} en mode autonome} \\
+ {\large\fakeverb{\large}} & {\large \affloetalabtkz{} en mode autonome} \\
+ {\Large\fakeverb{\Large}} & {\Large \affloetalabtkz{} en mode autonome} \\
+ {\LARGE\fakeverb{\LARGE}} & {\LARGE \affloetalabtkz{} en mode autonome} \\
+ {\huge\fakeverb{\huge}} & {\huge \affloetalabtkz{} en mode autonome} \\
+ {\Huge\fakeverb{\Huge}} & {\Huge \affloetalabtkz{} en mode autonome} \\
+\end{tblr}
+
+\medskip
+
+\begin{tblr}{hlines,width=\linewidth,colspec={Q[l,m]X[l,m]},row{1}={magenta!10},row{2-Z}={cyan!10}}
+ \SetCell[r=1,c=2]{c,m} \fakeverb{\affloetalabtkz*} & \\
+ {\tiny\fakeverb{\tiny}} & {\tiny \affloetalabtkz*{} en mode autonome} \\
+ {\scriptsize\fakeverb{\scriptsize}} & {\scriptsize \affloetalabtkz*{} en mode autonome} \\
+ {\footnotesize\fakeverb{\footnotesize}} & {\footnotesize \affloetalabtkz*{} en mode autonome} \\
+ {\small\fakeverb{\small}} & {\small \affloetalabtkz*{} en mode autonome} \\
+ {\normalsize\fakeverb{\normalsize}} & {\normalsize \affloetalabtkz*{} en mode autonome} \\
+ {\large\fakeverb{\large}} & {\large \affloetalabtkz*{} en mode autonome} \\
+ {\Large\fakeverb{\Large}} & {\Large \affloetalabtkz*{} en mode autonome} \\
+ {\LARGE\fakeverb{\LARGE}} & {\LARGE \affloetalabtkz*{} en mode autonome} \\
+ {\huge\fakeverb{\huge}} & {\huge \affloetalabtkz*{} en mode autonome} \\
+ {\Huge\fakeverb{\Huge}} & {\Huge \affloetalabtkz*{} en mode autonome} \\
+\end{tblr}
+
+\medskip
+
+\begin{tblr}{hlines,width=\linewidth,colspec={Q[l,m]X[l,m]},row{1}={magenta!10},row{2-Z}={cyan!10}}
+ \SetCell[r=1,c=2]{c,m} \fakeverb{\affloetalabtkz*[Couleur=gray]} & \\
+ {\tiny\fakeverb{\tiny}} & {\tiny \affloetalabtkz*[Couleur=gray] en mode autonome} \\
+ {\scriptsize\fakeverb{\scriptsize}} & {\scriptsize \affloetalabtkz*[Couleur=gray] en mode autonome} \\
+ {\footnotesize\fakeverb{\footnotesize}} & {\footnotesize \affloetalabtkz*[Couleur=gray] en mode autonome} \\
+ {\small\fakeverb{\small}} & {\small \affloetalabtkz*[Couleur=gray] en mode autonome} \\
+ {\normalsize\fakeverb{\normalsize}} & {\normalsize \affloetalabtkz*[Couleur=gray] en mode autonome} \\
+ {\large\fakeverb{\large}} & {\large \affloetalabtkz*[Couleur=gray] en mode autonome} \\
+ {\Large\fakeverb{\Large}} & {\Large \affloetalabtkz*[Couleur=gray] en mode autonome} \\
+ {\LARGE\fakeverb{\LARGE}} & {\LARGE \affloetalabtkz*[Couleur=gray] en mode autonome} \\
+ {\huge\fakeverb{\huge}} & {\huge \affloetalabtkz*[Couleur=gray] en mode autonome} \\
+ {\Huge\fakeverb{\Huge}} & {\Huge \affloetalabtkz*[Couleur=gray] en mode autonome} \\
+\end{tblr}
+
+\begin{demohigh}[language=latex/latex2,style/main=cyan!10,style/code=cyan!10,style/demo=cyan!10]
+ \small\affloetalabtkz[Couleur=magenta]
+\end{demohigh}
+
+\begin{demohigh}[language=latex/latex2,style/main=cyan!10,style/code=cyan!10,style/demo=cyan!10]
+ \LARGE\sffamily\affloetalabtkz[Couleur=teal]~Licence Etalab 2.0
+\end{demohigh}
+
\vfill
\section{Historique}
-\verb|v0.1.0|~:~~~~Version initiale
+\verb|v0.1.1|~:~~~~Ajout d'une version \TikZ.
+
+\verb|v0.1.0|~:~~~~Version initiale.
\vspace*{15mm}
diff --git a/macros/latex/contrib/logoetalab/tex/logoetalab.sty b/macros/latex/contrib/logoetalab/tex/logoetalab.sty
index 29303cf7c8..f21ddde782 100644
--- a/macros/latex/contrib/logoetalab/tex/logoetalab.sty
+++ b/macros/latex/contrib/logoetalab/tex/logoetalab.sty
@@ -3,13 +3,17 @@
% licence svg : CC BY 2.0 FR
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{logoetalab}[2023/08/17 0.1.0 Logo vectoriel de la licence 'Licence Ouverte Etalab 2.0']
+\ProvidesPackage{logoetalab}[2023/11/19 0.1.1 Logo vectoriel ou tikz de la licence 'Licence Ouverte Etalab 2.0']
%====HISTORIQUE
+% v 0.1.1 Ajout d'une version full tikz
% v 0.1.0 Version initiale
%====BASE
\RequirePackage{graphicx}
+\RequirePackage{tikz}
+\usetikzlibrary{calc}
+\RequirePackage{xstring}
\RequirePackage{calc}
\RequirePackage{simplekv}
@@ -83,4 +87,134 @@
\ifboolKV[iconetalab]{Legende}{~\tmplogotextleg}{}%
}
+%====TIKZ
+\defKV[logoetalabtikz]{%
+ Hauteur=\def\LogoEtalabTikzHauteur{#1},%
+ Couleur=\def\LogoEtalabTikzCouleur{#1},%
+ DecalageV=\def\LogoEtalabTikzOffset{#1}
+}
+
+\setKVdefault[logoetalabtikz]{%
+ Hauteur=auto,%
+ Couleur=black,%
+ DecalageV=auto
+}
+
+\newlength{\tmplogoprofondeur}
+\newlength{\tmplogohauteurtotale}
+\newlength{\tmplogooffset}
+
+\NewDocumentCommand\loetalabtkz{ s O{} D<>{} }{%
+ \settodepth{\tmplogoprofondeur}{\hbox{q}}%
+ \useKVdefault[logoetalabtikz]%
+ \setKV[logoetalabtikz]{#2}%
+ \IfStrEq{\LogoEtalabTikzHauteur}{auto}%
+ {%
+ \settototalheight{\tmplogohauteurtotale}{\hbox{qB}}%
+ \IfStrEq{\LogoEtalabTikzOffset}{auto}%
+ {%
+ \setlength{\tmplogooffset}{-\tmplogoprofondeur+0.05\tmplogohauteurtotale}%
+ }%
+ {%
+ \setlength{\tmplogooffset}{\LogoEtalabTikzOffset}%
+ }%
+ \def\tmplogoscale{1}%
+ }%
+ {%
+ \setlength{\tmplogohauteurtotale}{\LogoEtalabTikzHauteur}%
+ \IfStrEq{\LogoEtalabTikzOffset}{auto}%
+ {%
+ \setlength{\tmplogooffset}{0pt}%
+ }%
+ {%
+ \setlength{\tmplogooffset}{\LogoEtalabTikzOffset}%
+ }%
+ \def\tmplogoscale{1}%
+ }%
+ \raisebox{\tmplogooffset}{%
+ \IfBooleanTF{#1}%
+ {%
+ \begin{tikzpicture}[scale={0.9*\tmplogoscale},x={\tmplogohauteurtotale},y={\tmplogohauteurtotale},outer sep=0pt,#3]
+ %cadre
+ \draw[draw=none,fill=\LogoEtalabTikzCouleur,rounded corners={1.5*0.125*\tmplogohauteurtotale}] (0,0) rectangle (2,1) ;
+ %cadre haut
+ \draw[draw=none,fill=white,rounded corners={1.5*0.125*0.875*\tmplogohauteurtotale}] ({0.5*0.125},{0.0625}) rectangle++ ({0.875},{0.875}) ;
+ %I gauche
+ \draw[draw=none,fill=\LogoEtalabTikzCouleur] ({0.15},{0.25}) rectangle++ ({0.1},{0.5}) ;
+ %I droit
+ \draw[draw=none,fill=white] ({1.85},{0.25}) rectangle++ ({-0.1},{0.5}) ;
+ %O gauche
+ \draw[draw=none,fill=\LogoEtalabTikzCouleur] ({0.6},{0.5}) circle[radius={0.25}] ;
+ \draw[draw=none,fill=white] ({0.6},{0.5}) circle[radius={0.15}] ;
+ %O droit
+ \draw[draw=none,fill=white] ({1.4},{0.5}) circle[radius={0.25}] ;
+ \draw[draw=none,fill=\LogoEtalabTikzCouleur] ({1.4},{0.5}) circle[radius={0.15}] ;
+ \end{tikzpicture}%
+ }%
+ {%
+ \begin{tikzpicture}[scale={0.5*0.9*\tmplogoscale},x={\tmplogohauteurtotale},y={\tmplogohauteurtotale},#3]
+ %cadre
+ \draw[draw=none,fill=\LogoEtalabTikzCouleur,rounded corners={0.75*0.125*\tmplogohauteurtotale}] (0,0) rectangle (1,2) ;
+ %cadre haut
+ \draw[draw=none,fill=white,rounded corners={0.75*0.125*0.875*\tmplogohauteurtotale}] ({0.5*0.125},{1.0625}) rectangle++ ({0.875},{0.875}) ;
+ %I haut
+ \draw[draw=none,fill=\LogoEtalabTikzCouleur] ({0.15},{1.25}) rectangle++ ({0.1},{0.5}) ;
+ %I bas
+ \draw[draw=none,fill=white] ({0.85},{0.25}) rectangle++({-0.1},{0.5}) ;
+ %O haut
+ \draw[draw=none,fill=\LogoEtalabTikzCouleur] ({0.6},{1.5}) circle[radius={0.25}] ;
+ \draw[draw=none,fill=white] ({0.6},{1.5}) circle[radius={0.15}] ;
+ %O bas
+ \draw[draw=none,fill=white] ({0.4},{0.5}) circle[radius={0.25}] ;
+ \draw[draw=none,fill=\LogoEtalabTikzCouleur] ({0.4},{0.5}) circle[radius={0.15}] ;
+ \end{tikzpicture}%
+ }%
+ }%
+}
+
+\NewDocumentCommand\affloetalabtkz{ s O{} D<>{} }{%
+ \settototalheight{\tmplogohauteurtotale}{\hbox{B}}%
+ \useKVdefault[logoetalabtikz]%
+ \setKV[logoetalabtikz]{#2}%
+ \raisebox{-0.5\tmplogohauteurtotale}{%
+ \IfBooleanTF{#1}%H, sinon V
+ {%
+ \begin{tikzpicture}[x={2*\tmplogohauteurtotale},y={2*\tmplogohauteurtotale},outer sep=0pt,#3]
+ %cadre
+ \draw[draw=none,fill=\LogoEtalabTikzCouleur,rounded corners={2.22*0.125*\tmplogohauteurtotale}] (0,0) rectangle (2,1) ;
+ %cadre haut
+ \draw[draw=none,fill=white,rounded corners={2.22*0.125*0.875*\tmplogohauteurtotale}] ({0.5*0.125},{0.0625}) rectangle++ ({0.875},{0.875}) ;
+ %I gauche
+ \draw[draw=none,fill=\LogoEtalabTikzCouleur] ({0.15},{0.25}) rectangle++ ({0.1},{0.5}) ;
+ %I droit
+ \draw[draw=none,fill=white] ({1.85},{0.25}) rectangle++ ({-0.1},{0.5}) ;
+ %O gauche
+ \draw[draw=none,fill=\LogoEtalabTikzCouleur] ({0.6},{0.5}) circle[radius={0.25}] ;
+ \draw[draw=none,fill=white] ({0.6},{0.5}) circle[radius={0.15}] ;
+ %O droit
+ \draw[draw=none,fill=white] ({1.4},{0.5}) circle[radius={0.25}] ;
+ \draw[draw=none,fill=\LogoEtalabTikzCouleur] ({1.4},{0.5}) circle[radius={0.15}] ;
+ \end{tikzpicture}%
+ }%
+ {%
+ \begin{tikzpicture}[x={\tmplogohauteurtotale},y={\tmplogohauteurtotale},#3]
+ %cadre
+ \draw[draw=none,fill=\LogoEtalabTikzCouleur,rounded corners={1.11*0.125*\tmplogohauteurtotale}] (0,0) rectangle (1,2) ;
+ %cadre haut
+ \draw[draw=none,fill=white,rounded corners={1.11*0.125*0.875*\tmplogohauteurtotale}] ({0.5*0.125},{1.0625}) rectangle++ ({0.875},{0.875}) ;
+ %I haut
+ \draw[draw=none,fill=\LogoEtalabTikzCouleur] ({0.15},{1.25}) rectangle++ ({0.1},{0.5}) ;
+ %I bas
+ \draw[draw=none,fill=white] ({0.85},{0.25}) rectangle++({-0.1},{0.5}) ;
+ %O haut
+ \draw[draw=none,fill=\LogoEtalabTikzCouleur] ({0.6},{1.5}) circle[radius={0.25}] ;
+ \draw[draw=none,fill=white] ({0.6},{1.5}) circle[radius={0.15}] ;
+ %O bas
+ \draw[draw=none,fill=white] ({0.4},{0.5}) circle[radius={0.25}] ;
+ \draw[draw=none,fill=\LogoEtalabTikzCouleur] ({0.4},{0.5}) circle[radius={0.15}] ;
+ \end{tikzpicture}%
+ }%
+ }%
+}
+
\endinput \ No newline at end of file
diff --git a/macros/latex/contrib/uni-titlepage/README.md b/macros/latex/contrib/uni-titlepage/README.md
index a4a9425c8b..af23489724 100644
--- a/macros/latex/contrib/uni-titlepage/README.md
+++ b/macros/latex/contrib/uni-titlepage/README.md
@@ -2,7 +2,7 @@
Copyright (c) Markus Kohm <komascript at gmx.info>
-Release: 2022/09/06 v1.1a
+Release: 2023-11-20 v1.2
License: LPPL 1.3c
diff --git a/macros/latex/contrib/uni-titlepage/titlepage-DHBW.pdf b/macros/latex/contrib/uni-titlepage/titlepage-DHBW.pdf
index 177b86beff..0c8549d947 100644
--- a/macros/latex/contrib/uni-titlepage/titlepage-DHBW.pdf
+++ b/macros/latex/contrib/uni-titlepage/titlepage-DHBW.pdf
Binary files differ
diff --git a/macros/latex/contrib/uni-titlepage/titlepage-JT-Aufsaetze.pdf b/macros/latex/contrib/uni-titlepage/titlepage-JT-Aufsaetze.pdf
index 8bdaf5a352..b241d5273e 100644
--- a/macros/latex/contrib/uni-titlepage/titlepage-JT-Aufsaetze.pdf
+++ b/macros/latex/contrib/uni-titlepage/titlepage-JT-Aufsaetze.pdf
Binary files differ
diff --git a/macros/latex/contrib/uni-titlepage/titlepage-JT-Geschichte.pdf b/macros/latex/contrib/uni-titlepage/titlepage-JT-Geschichte.pdf
index 04c8be63c0..e8740a6c01 100644
--- a/macros/latex/contrib/uni-titlepage/titlepage-JT-Geschichte.pdf
+++ b/macros/latex/contrib/uni-titlepage/titlepage-JT-Geschichte.pdf
Binary files differ
diff --git a/macros/latex/contrib/uni-titlepage/titlepage-JT-Typography.pdf b/macros/latex/contrib/uni-titlepage/titlepage-JT-Typography.pdf
index af47549922..658650ef99 100644
--- a/macros/latex/contrib/uni-titlepage/titlepage-JT-Typography.pdf
+++ b/macros/latex/contrib/uni-titlepage/titlepage-JT-Typography.pdf
Binary files differ
diff --git a/macros/latex/contrib/uni-titlepage/titlepage-KIT.pdf b/macros/latex/contrib/uni-titlepage/titlepage-KIT.pdf
index e2336f77f8..470eb16831 100644
--- a/macros/latex/contrib/uni-titlepage/titlepage-KIT.pdf
+++ b/macros/latex/contrib/uni-titlepage/titlepage-KIT.pdf
Binary files differ
diff --git a/macros/latex/contrib/uni-titlepage/titlepage-KOMAScript.pdf b/macros/latex/contrib/uni-titlepage/titlepage-KOMAScript.pdf
index 8ff62881bf..b96ad73617 100644
--- a/macros/latex/contrib/uni-titlepage/titlepage-KOMAScript.pdf
+++ b/macros/latex/contrib/uni-titlepage/titlepage-KOMAScript.pdf
Binary files differ
diff --git a/macros/latex/contrib/uni-titlepage/titlepage-Markus-1.pdf b/macros/latex/contrib/uni-titlepage/titlepage-Markus-1.pdf
index 4d1e2d6511..2c99b77f2a 100644
--- a/macros/latex/contrib/uni-titlepage/titlepage-Markus-1.pdf
+++ b/macros/latex/contrib/uni-titlepage/titlepage-Markus-1.pdf
Binary files differ
diff --git a/macros/latex/contrib/uni-titlepage/titlepage-Markus-2.pdf b/macros/latex/contrib/uni-titlepage/titlepage-Markus-2.pdf
index b03f4d09e3..a668931107 100644
--- a/macros/latex/contrib/uni-titlepage/titlepage-Markus-2.pdf
+++ b/macros/latex/contrib/uni-titlepage/titlepage-Markus-2.pdf
Binary files differ
diff --git a/macros/latex/contrib/uni-titlepage/titlepage-Spacer.pdf b/macros/latex/contrib/uni-titlepage/titlepage-Spacer.pdf
index 219e837698..4c06a94abc 100644
--- a/macros/latex/contrib/uni-titlepage/titlepage-Spacer.pdf
+++ b/macros/latex/contrib/uni-titlepage/titlepage-Spacer.pdf
Binary files differ
diff --git a/macros/latex/contrib/uni-titlepage/titlepage-TU-DD.pdf b/macros/latex/contrib/uni-titlepage/titlepage-TU-DD.pdf
index 384c68259c..36e973b43e 100644
--- a/macros/latex/contrib/uni-titlepage/titlepage-TU-DD.pdf
+++ b/macros/latex/contrib/uni-titlepage/titlepage-TU-DD.pdf
Binary files differ
diff --git a/macros/latex/contrib/uni-titlepage/titlepage-TU-HH.pdf b/macros/latex/contrib/uni-titlepage/titlepage-TU-HH.pdf
index 71c71c5c2b..1158147a46 100644
--- a/macros/latex/contrib/uni-titlepage/titlepage-TU-HH.pdf
+++ b/macros/latex/contrib/uni-titlepage/titlepage-TU-HH.pdf
Binary files differ
diff --git a/macros/latex/contrib/uni-titlepage/titlepage-UKoLa.pdf b/macros/latex/contrib/uni-titlepage/titlepage-UKoLa.pdf
index bb84fa68d6..20d1e27920 100644
--- a/macros/latex/contrib/uni-titlepage/titlepage-UKoLa.pdf
+++ b/macros/latex/contrib/uni-titlepage/titlepage-UKoLa.pdf
Binary files differ
diff --git a/macros/latex/contrib/uni-titlepage/titlepage-WWUM.pdf b/macros/latex/contrib/uni-titlepage/titlepage-WWUM.pdf
index d49c8e3610..92452c010c 100644
--- a/macros/latex/contrib/uni-titlepage/titlepage-WWUM.pdf
+++ b/macros/latex/contrib/uni-titlepage/titlepage-WWUM.pdf
Binary files differ
diff --git a/macros/latex/contrib/uni-titlepage/uni-titlepage.dtx b/macros/latex/contrib/uni-titlepage/uni-titlepage.dtx
index b742e18303..189f6ca1d8 100644
--- a/macros/latex/contrib/uni-titlepage/uni-titlepage.dtx
+++ b/macros/latex/contrib/uni-titlepage/uni-titlepage.dtx
@@ -60,10 +60,10 @@
}[%
%</!README>
%<README>
-%<README>Release: 2022/09/06 v1.1a
+%<README>Release: 2023-11-20 v1.2
%<README>
%<README>License: LPPL 1.3c
-%<!README>2022/09/06 v1.1a
+%<!README>2023-11-20 v1.2
%<README>
KOMA presents the title page project
%<*!README>
@@ -243,7 +243,7 @@ KOMA presents the title page project
% \texttt{UKoLa}) multiple
% referees may be seperated with \cs{and}
% \tabularnewline
-% sience & WWUM & kind of sience,
+% science\footnotemark & WWUM & kind of science,
% e.\,g., ``Naturwissenschaften''
% \tabularnewline
% student & \normalfont\emph{see \texttt{author}}
@@ -275,6 +275,10 @@ KOMA presents the title page project
% presented your work
% \tabularnewline
% \end{xltabular}
+% \footnotetext{Due to a typing error, this option was named `sience' until
+% version 1.1a. If the obsolete option or the corresponding command is used,
+% a warning is issued from version 1.2 onwards. The correct spelling
+% documented here should be used instead.\label{ftn:sience}}
%
% \begin{description}
% \item[Note:] Depending on the used style some elements are mandatory. You will get
@@ -700,8 +704,9 @@ KOMA presents the title page project
% \item cover page with \texttt{author}, \texttt{title}, \cs{the}\cs{year}
% \item the backside of the cover page is empty if it exists
% \item main title page with \texttt{chair}, \texttt{title},
-% \texttt{subject}, \texttt{academicgrade}, \texttt{sience}, \texttt{discipline},
-% \texttt{faculty}
+% \texttt{subject}, \texttt{academicgrade},
+% \texttt{science}\footref{ftn:sience},
+% \texttt{discipline}, \texttt{faculty}
% \item main title back side with \texttt{professor}, \texttt{referee},
% \texttt{oralexaminationdate} (normaly empty)
% \end{enumerate}
@@ -1371,14 +1376,59 @@ You may however distribute the file `uni-titlepage.dtx' without this file.
\DefineReplaceTitleKey{student}{author}
% \end{macrocode}
% \end{option}
+% \begin{imacro}{\science}
+% \changes{v0.5}{2016/06/21}{added}
+% \changes{v1.2}{2023/11/20}{\cs{sience} renamed}
+% \begin{macro}{\@science}
+% \changes{v0.5}{2016/06/21}{added}
+% \changes{v1.2}{2023/11/20}{\cs{@sience} renamed}
+% \begin{option}{science}
+% \changes{v0.5}{2016/06/21}{added}
+% \changes{v1.2}{2023/11/20}{\texttt{sience} renamed}
+% \begin{macrocode}
+\DefineSimpleTitleKey{science}
+% \end{macrocode}
+% \end{option}
+% \end{macro}
+% \end{imacro}
% \begin{imacro}{\sience}
% \changes{v0.5}{2016/06/21}{added}
+% \changes{v1.2}{2023/11/20}{deprecated}
% \begin{macro}{\@sience}
% \changes{v0.5}{2016/06/21}{added}
+% \changes{v1.2}{2023/11/20}{deprecated}
% \begin{option}{sience}
% \changes{v0.5}{2016/06/21}{added}
+% \changes{v1.2}{2023/11/20}{deprecated}
% \begin{macrocode}
-\DefineSimpleTitleKey{sience}
+\providecommand*{\sience}{%
+ \PackageWarning{uni-titlepage}{%
+ \string\sience\space internally replaced by \string\science.\MessageBreak
+ Please note, that \string\sience\space was a typing mistake\MessageBreak
+ and should not be used any longer.\MessageBreak
+ You should replace it by \string\science
+ }%
+ \science
+}
+\providecommand*{\@sience}{%
+ \PackageWarning{uni-titlepage}{%
+ internal \string\@sience\space replaced by \string\@science.\MessageBreak
+ Please note, that \string\@sience was a typing mistake\MessageBreak
+ and should not be used any longer.\MessageBreak
+ You should replace it by \srting\@science%
+ }%
+ \@science
+}
+\DefineFamilyKey{title}{sience}{%
+ \PackageWarning{uni-titlepage}{%
+ deprecated option `sience' used.\MessageBreak
+ Please note, that `sience' was a typing mistake\MessageBreak
+ and should not be used any longer.\MessageBreak
+ You should replace it by `science'%
+ }%
+ \science{#1}%
+ \FamilyKeyStateProcessed
+}
% \end{macrocode}
% \end{option}
% \end{macro}
@@ -2245,12 +2295,15 @@ You may however distribute the file `uni-titlepage.dtx' without this file.
\strut\ignorespaces\@chair\\
}%
%</KIT>
-%<*WWUM>
+% \end{macrocode}
+% \changes{v1.2}{2023/11/20}{\texttt{science} fixed}
+% \begin{macrocode}
+%<*WWUM>
\providecommand*{\presentationinformationWWUM}{%
\usenonemptytitleelement{subject}\\
to the Aquisition of the Academic Degree\\
\usenonemptytitleelement{academicgrade}\\
- of the \usenonemptytitleelement{sience} of \usenonemptytitleelement{discipline}\\
+ of the \usenonemptytitleelement{science} of \usenonemptytitleelement{discipline}\\
of the \usenonemptytitleelement{faculty} faculty\\
of the \usenonemptytitleelement{university}%
}
@@ -2259,7 +2312,7 @@ You may however distribute the file `uni-titlepage.dtx' without this file.
\usenonemptytitleelement{subject}\\
to the Aquisition of the Academic Degree\\
\usenonemptytitleelement{academicgrade}\\
- of the \usenonemptytitleelement{sience} of \usenonemptytitleelement{discipline}\\
+ of the \usenonemptytitleelement{science} of \usenonemptytitleelement{discipline}\\
of the \usenonemptytitleelement{faculty} faculty\\
of the \usenonemptytitleelement{university}%
}
@@ -2267,7 +2320,7 @@ You may however distribute the file `uni-titlepage.dtx' without this file.
swissgerman,nswissgerman}{\presentationinformationWWUM}{%
\usenonemptytitleelement{subject}\\
zur Erlangung des \usenonemptytitleelement{academicgrade}\\
- der \usenonemptytitleelement{sience} im Fachbereich
+ der \usenonemptytitleelement{science} im Fachbereich
\usenonemptytitleelement{discipline}\\
der \usenonemptytitleelement{faculty} Fakult\"at\\
der \usenonemptytitleelement{university}%
@@ -3407,6 +3460,9 @@ You may however distribute the file `uni-titlepage.dtx' without this file.
% See Markus-2 for more information about those.
]
%</JT-Typography>
+% \end{macrocode}
+% \changes{v1.2}{2023/11/20}{\texttt{science} fixed}
+% \begin{macrocode}
%<*WWUM>
\TitlePageStyle{WWUM}
\renewcaptionname{ngerman}{\examinationdatename}{Tag der Promotion}
@@ -3418,7 +3474,7 @@ You may however distribute the file `uni-titlepage.dtx' without this file.
subject={\textcolor{red}{Inaugural-Dissertation}},
academicgrade={\textcolor{red}{Doktorgrades}},
discipline={\textcolor{red}{Physik}},
- sience={\textcolor{red}{Naturwissenschaften}},
+ science={\textcolor{red}{Naturwissenschaften}},
chair={\textcolor{red}{Experimentelle Physik}},
faculty={\textcolor{red}{Mathematisch-Naturwissenschaftlichen}},
author={\textcolor{red}{Mein Name}},
@@ -3634,7 +3690,8 @@ translating them). The coding style and quality is also a criterion.
\endinput
%% Local Variables:
+%% mode: doctex
+%% eval: (flyspell-mode 1)
+%% ispell-local-dictionary: "en_GB"
%% TeX-master: t
-%% TeX-PDF-mode: t
-%% flyspell-mode: t
%% End:
diff --git a/macros/latex/contrib/uni-titlepage/uni-titlepage.pdf b/macros/latex/contrib/uni-titlepage/uni-titlepage.pdf
index 40de62cf10..f8be4dd066 100644
--- a/macros/latex/contrib/uni-titlepage/uni-titlepage.pdf
+++ b/macros/latex/contrib/uni-titlepage/uni-titlepage.pdf
Binary files differ