summaryrefslogtreecommitdiff
path: root/macros
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2022-03-04 03:01:04 +0000
committerNorbert Preining <norbert@preining.info>2022-03-04 03:01:04 +0000
commit575ab7d0e7534edd510bbc89a2ef4b04582af591 (patch)
tree9fc4cf55b7ca8b168bdfd747be21de4c9ef2b30e /macros
parent6b9ed20cb01cb52c7aaf2a48202f5d8aa588ff79 (diff)
CTAN sync 202203040301
Diffstat (limited to 'macros')
-rw-r--r--[l---------]macros/latex/contrib/biblatex-contrib/biblatex-software/Changes17
-rw-r--r--macros/latex/contrib/biblatex-contrib/biblatex-software/biblio.bib38
-rw-r--r--macros/latex/contrib/biblatex-contrib/biblatex-software/history.tex3
-rw-r--r--macros/latex/contrib/biblatex-contrib/biblatex-software/sample-content.tex2
-rw-r--r--macros/latex/contrib/biblatex-contrib/biblatex-software/sample-use-sty.pdfbin128718 -> 129373 bytes
-rw-r--r--macros/latex/contrib/biblatex-contrib/biblatex-software/software-biblatex.pdfbin171367 -> 172786 bytes
-rw-r--r--macros/latex/contrib/biblatex-contrib/biblatex-software/software-biblatex.tex15
-rw-r--r--macros/latex/contrib/biblatex-contrib/biblatex-software/software.bbx21
-rw-r--r--macros/latex/contrib/biblatex-contrib/biblatex-software/software.dbx1
-rw-r--r--macros/latex/contrib/biblatex-contrib/biblatex-software/swentries.tex45
-rw-r--r--macros/luatex/generic/minim-math/README17
-rw-r--r--macros/luatex/generic/minim-math/minim-math-table.lua15
-rw-r--r--macros/luatex/generic/minim-math/minim-math.doc16
-rw-r--r--macros/luatex/generic/minim-math/minim-math.lua6
-rw-r--r--macros/luatex/generic/minim-math/minim-math.pdfbin106915 -> 110408 bytes
-rw-r--r--macros/luatex/generic/minim-math/minim-math.tex4
-rw-r--r--macros/luatex/generic/minim-mp/README32
-rw-r--r--macros/luatex/generic/minim-mp/minim-lamp.ini20
-rw-r--r--macros/luatex/generic/minim-mp/minim-mp.doc112
-rw-r--r--macros/luatex/generic/minim-mp/minim-mp.ini1
-rw-r--r--macros/luatex/generic/minim-mp/minim-mp.lua390
-rw-r--r--macros/luatex/generic/minim-mp/minim-mp.pdfbin82287 -> 94557 bytes
-rw-r--r--macros/luatex/generic/minim-mp/minim-mp.tex3
-rw-r--r--macros/luatex/generic/minim-mp/minim.mp81
-rw-r--r--macros/luatex/generic/minim-pdf/README27
-rw-r--r--macros/luatex/generic/minim-pdf/minim-languagecodes.lua8
-rw-r--r--macros/luatex/generic/minim-pdf/minim-pdf.doc86
-rw-r--r--macros/luatex/generic/minim-pdf/minim-pdf.lua294
-rw-r--r--macros/luatex/generic/minim-pdf/minim-pdf.pdfbin108362 -> 110458 bytes
-rw-r--r--macros/luatex/generic/minim-pdf/minim-pdf.tex62
-rw-r--r--macros/luatex/generic/minim-xmp/README17
-rw-r--r--macros/luatex/generic/minim-xmp/minim-xmp.doc68
-rw-r--r--macros/luatex/generic/minim-xmp/minim-xmp.lua7
-rw-r--r--macros/luatex/generic/minim-xmp/minim-xmp.pdfbin61507 -> 72506 bytes
-rw-r--r--macros/luatex/generic/minim-xmp/minim-xmp.tex4
-rw-r--r--macros/luatex/generic/minim/README28
-rw-r--r--macros/luatex/generic/minim/minim-alloc.doc105
-rw-r--r--macros/luatex/generic/minim/minim-alloc.lua183
-rw-r--r--macros/luatex/generic/minim/minim-alloc.tex107
-rw-r--r--macros/luatex/generic/minim/minim-callbacks.lua175
-rw-r--r--macros/luatex/generic/minim/minim-doc.sty64
-rw-r--r--macros/luatex/generic/minim/minim-hooks.lua18
-rw-r--r--macros/luatex/generic/minim/minim-hooks.tex8
-rw-r--r--macros/luatex/generic/minim/minim-lmodern.tex18
-rw-r--r--macros/luatex/generic/minim/minim-pdfresources.lua154
-rw-r--r--macros/luatex/generic/minim/minim-pdfresources.tex51
-rw-r--r--macros/luatex/generic/minim/minim-plain.tex14
-rw-r--r--macros/luatex/generic/minim/minim.doc11
-rw-r--r--macros/luatex/generic/minim/minim.pdfbin285949 -> 317085 bytes
-rw-r--r--macros/luatex/generic/penlight/README.md4
-rw-r--r--macros/luatex/generic/penlight/penlight.pdfbin38237 -> 38311 bytes
-rw-r--r--macros/luatex/generic/penlight/penlight.sty22
-rw-r--r--macros/luatex/generic/penlight/penlight.tex4
-rw-r--r--macros/luatex/generic/penlight/penlightextras.lua75
-rw-r--r--macros/luatex/latex/yamlvars/yamlvars.lua54
-rw-r--r--macros/luatex/latex/yamlvars/yamlvars.pdfbin69483 -> 69460 bytes
-rw-r--r--macros/luatex/latex/yamlvars/yamlvars.sty19
-rw-r--r--macros/luatex/latex/yamlvars/yamlvars.tex4
-rw-r--r--macros/xetex/latex/ucharclasses/README7
-rw-r--r--macros/xetex/latex/ucharclasses/ucharclasses.pdfbin135627 -> 136780 bytes
-rw-r--r--macros/xetex/latex/ucharclasses/ucharclasses.sty78
-rw-r--r--macros/xetex/latex/ucharclasses/ucharclasses.tex26
62 files changed, 1792 insertions, 849 deletions
diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-software/Changes b/macros/latex/contrib/biblatex-contrib/biblatex-software/Changes
index 3c0375f0f7..76f1661405 120000..100644
--- a/macros/latex/contrib/biblatex-contrib/biblatex-software/Changes
+++ b/macros/latex/contrib/biblatex-contrib/biblatex-software/Changes
@@ -1 +1,16 @@
-history.tex \ No newline at end of file
+\begin{release}{bltx-v1.2-4}{2022-03-03} \item Add support for displaying short SWHID \end{release}
+\begin{release}{bltx-v1.2-3}{2021-08-20} \item Support backrefs. \end{release}
+\begin{release}{bltx-v1.2-2}{2020-06-27} \item Fix handling of related field; use date instead of year/month in examples; add swMATH definition \end{release}
+\begin{release}{bltx-v1.2-1}{2020-06-01} \item Fix mishandling of SWHIDs and HALids when hyperref is not loaded. Fix wrong origins in some SWHIDs in the examples. Improve ASCL example. \end{release}
+\begin{release}{bltx-v1.2}{2020-05-29} \item Bump version to 1.2 with clean support of multiline SWHIDs \end{release}
+\begin{release}{bltx-v1.1}{2020-04-29} \item Add support for the institution, organization, eprint, eprinttype and eprintclass fields Force urls output when they are the only reference available Updates to the documentation \end{release}
+\begin{release}{bltx-v1.0}{2020-04-25} \item First public release \end{release}
+\begin{release}{bltx-v0.9}{2020-04-25} \item Preparing for public release: Licence, Readme, update documentation, handle suggestions from the Working Group \end{release}
+\begin{release}{bltx-v0.8}{2020-04-09} \item Make the style usable as an extension, and keep possibility of generating extended styles \end{release}
+\begin{release}{bltx-v0.7}{2020-04-09} \item Move to diff model approach to be more portable \end{release}
+\begin{release}{bltx-v0.6}{2020-04-08} \item Standardise file names, make softwarebib.tex self contained, separate out sample.tex, update Makefile, use printdate macro \end{release}
+\begin{release}{bltx-v0.5}{2020-04-08} \item Added standard list format for licenses \end{release}
+\begin{release}{bltx-v0.4}{2020-04-07} \item Added repository and licence field \end{release}
+\begin{release}{bltx-v0.3}{2020-04-05} \item Biblatex style with first complete example \end{release}
+\begin{release}{bltx-v0.2}{2020-04-02} \item Biblatex style sent for review \end{release}
+\begin{release}{bltx-v0.1}{2020-04-02} \item First version of the biblatex style \end{release}
diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-software/biblio.bib b/macros/latex/contrib/biblatex-contrib/biblatex-software/biblio.bib
index a1e54b3c19..89b85578ed 100644
--- a/macros/latex/contrib/biblatex-contrib/biblatex-software/biblio.bib
+++ b/macros/latex/contrib/biblatex-contrib/biblatex-software/biblio.bib
@@ -80,18 +80,46 @@
@software {parmap,
title = {The Parmap library},
author = {Di Cosmo, Roberto and Marco Danelutto},
- date = {2020},
- version = {1.1.1},
+ date = {2012},
institution = {{Inria} and {University of Paris} and {University of Pisa}},
license = {LGPL-2.0},
url = {https://rdicosmo.github.io/parmap/},
repository= {https://github.com/rdicosmo/parmap},
}
+@softwareversion {parmap-1.1.1,
+ crossref = {parmap},
+ date = {2020},
+ version = {1.1.1},
+ swhid = {swh:1:rel:373e2604d96de4ab1d505190b654c5c4045db773;
+ origin=https://github.com/rdicosmo/parmap;
+ visit=swh:1:snp:2a6c348c53eb77d458f24c9cbcecaf92e3c45615},
+}
+
@codefragment {simplemapper,
subtitle = {Core mapping routine},
swhid = {swh:1:cnt:43a6b232768017b03da934ba22d9cc3f2726a6c5;
- lines=192-228;
- origin=https://github.com/rdicosmo/parmap},
- crossref = {parmap}
+ origin=https://github.com/rdicosmo/parmap;
+ visit=swh:1:snp:2a6c348c53eb77d458f24c9cbcecaf92e3c45615;
+ anchor=swh:1:rel:373e2604d96de4ab1d505190b654c5c4045db773;
+ path=/src/parmap.ml;
+ lines=192-228},
+ crossref = {parmap-1.1.1}
+}
+@codefragment {simplemapper-condensed,
+ title = {The Parmap library},
+ author = {Di Cosmo, Roberto and Marco Danelutto},
+ date = {2020},
+ institution = {{Inria} and {University of Paris} and {University of Pisa}},
+ license = {LGPL-2.0},
+ url = {https://rdicosmo.github.io/parmap/},
+ repository= {https://github.com/rdicosmo/parmap},
+ version = {1.1.1},
+ subtitle = {Core mapping routine},
+ swhid = {swh:1:cnt:43a6b232768017b03da934ba22d9cc3f2726a6c5;
+ origin=https://github.com/rdicosmo/parmap;
+ visit=swh:1:snp:2a6c348c53eb77d458f24c9cbcecaf92e3c45615;
+ anchor=swh:1:rel:373e2604d96de4ab1d505190b654c5c4045db773;
+ path=/src/parmap.ml;
+ lines=192-228}
}
diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-software/history.tex b/macros/latex/contrib/biblatex-contrib/biblatex-software/history.tex
index 37f075302e..76f1661405 100644
--- a/macros/latex/contrib/biblatex-contrib/biblatex-software/history.tex
+++ b/macros/latex/contrib/biblatex-contrib/biblatex-software/history.tex
@@ -1,4 +1,5 @@
-\begin{release}{bltx-v1.2-3}{2021-01-09} \item Add support for backrefs. \end{release}
+\begin{release}{bltx-v1.2-4}{2022-03-03} \item Add support for displaying short SWHID \end{release}
+\begin{release}{bltx-v1.2-3}{2021-08-20} \item Support backrefs. \end{release}
\begin{release}{bltx-v1.2-2}{2020-06-27} \item Fix handling of related field; use date instead of year/month in examples; add swMATH definition \end{release}
\begin{release}{bltx-v1.2-1}{2020-06-01} \item Fix mishandling of SWHIDs and HALids when hyperref is not loaded. Fix wrong origins in some SWHIDs in the examples. Improve ASCL example. \end{release}
\begin{release}{bltx-v1.2}{2020-05-29} \item Bump version to 1.2 with clean support of multiline SWHIDs \end{release}
diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-software/sample-content.tex b/macros/latex/contrib/biblatex-contrib/biblatex-software/sample-content.tex
index b18f544631..dc014a7817 100644
--- a/macros/latex/contrib/biblatex-contrib/biblatex-software/sample-content.tex
+++ b/macros/latex/contrib/biblatex-contrib/biblatex-software/sample-content.tex
@@ -45,7 +45,7 @@ extended with the \texttt{software} module.
\item softwareversion Scilab 1.1.1 : from the chain of crossrefs \cite{delebecque:hal-02090402v1}, and from the condensed bibtem \cite{delebecque:hal-02090402-condensed} (they should be identical)
\item softwaremodule entry Voronoi: from the chain of crossrefs \cite{cgal:lp-gi-20a}, and the from the condensed bibtem \cite{cgal:lp-gi-20a-condensed} (they should be identical)
\item software entry Parmap \cite{parmap}
-\item codefragment entry simplemapper \cite{simplemapper}
+\item codefragment entry simplemapper: from the chain of crossrefs \cite{simplemapper}, and from the condensed bibitem \cite{simplemapper-condensed} (they should be identical)
\item software entry from the Astrophysics Source Code Library, using the eprint field \cite{2013ascl.soft05002P}
\item software entry from the swMATH catalog, using the eprint field \cite{sw01091}
\item documentation in a software entry \cite{scilabdoc}
diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-software/sample-use-sty.pdf b/macros/latex/contrib/biblatex-contrib/biblatex-software/sample-use-sty.pdf
index f89eedd265..b4edeebf1b 100644
--- a/macros/latex/contrib/biblatex-contrib/biblatex-software/sample-use-sty.pdf
+++ b/macros/latex/contrib/biblatex-contrib/biblatex-software/sample-use-sty.pdf
Binary files differ
diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-software/software-biblatex.pdf b/macros/latex/contrib/biblatex-contrib/biblatex-software/software-biblatex.pdf
index 67adf9f35e..e032a40d8c 100644
--- a/macros/latex/contrib/biblatex-contrib/biblatex-software/software-biblatex.pdf
+++ b/macros/latex/contrib/biblatex-contrib/biblatex-software/software-biblatex.pdf
Binary files differ
diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-software/software-biblatex.tex b/macros/latex/contrib/biblatex-contrib/biblatex-software/software-biblatex.tex
index 4e0aad191c..bead6d683a 100644
--- a/macros/latex/contrib/biblatex-contrib/biblatex-software/software-biblatex.tex
+++ b/macros/latex/contrib/biblatex-contrib/biblatex-software/software-biblatex.tex
@@ -11,10 +11,10 @@
\titlepage{%
title={Bib\LaTeX\ style extension for Software},
subtitle={Citation and References macros for Bib\LaTeX},
- url={http://mirror.ctan.org/macros/latex/exptl/biblatex-contrib/biblatex-software/},
+ url={https://www.ctan.org/tex-archive/macros/latex/contrib/biblatex-contrib/biblatex-software},
author={Roberto Di Cosmo},
email={roberto@dicosmo.org},
- revision={1.2-3},
+ revision={1.2-4},
date={\today}}
\hypersetup{%
@@ -114,6 +114,7 @@ existing Bib\LaTeX\ style by just doing the following:
\ExecuteBibliographyOptions{
halid=true,
swhid=true,
+ shortswhid=false,
swlabels=true,
vcs=true,
license=true}
@@ -190,7 +191,15 @@ metadata record for the software described in the entry. The default is |true|.
\end{ltxcode}
\noindent This option controls the inclusion of the identifier on the Software Heritage archive
-of the source code of the software described in the entry. The default is |true|.
+(SWHID) of the source code of the software described in the entry. The default is |true|.
+
+\begin{ltxcode}
+ shortswhid=true|false
+\end{ltxcode}
+
+\noindent This option controls the way the SWHID is displayed. Setting it to true will include
+only the core part of the SWHID in the printed version, and keep the full SWHID, with all contextual
+information, in the hyperlink. The default is |false|.
\begin{ltxcode}
vcs=true|false
diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-software/software.bbx b/macros/latex/contrib/biblatex-contrib/biblatex-software/software.bbx
index c33e114347..f7d27f471b 100644
--- a/macros/latex/contrib/biblatex-contrib/biblatex-software/software.bbx
+++ b/macros/latex/contrib/biblatex-contrib/biblatex-software/software.bbx
@@ -1,3 +1,4 @@
+\ProvidesFile{software.bbx}[2020/04/02 bibliography driver extension for software entries, Roberto Di Cosmo]
%
% Reference implementation of a BibLaTeX style for the software family of bibliographic entries
%
@@ -10,6 +11,7 @@
%
\newtoggle{bbx:halid}
\newtoggle{bbx:swhid}
+\newtoggle{bbx:shortswhid}
\newtoggle{bbx:vcs}
\newtoggle{bbx:swlabels}
\newtoggle{bbx:license}
@@ -18,6 +20,8 @@
\settoggle{bbx:halid}{#1}}
\DeclareBibliographyOption[boolean]{swhid}[true]{%
\settoggle{bbx:swhid}{#1}}
+\DeclareBibliographyOption[boolean]{shortswhid}[false]{%
+ \settoggle{bbx:shortswhid}{#1}}
\DeclareBibliographyOption[boolean]{swlabels}[true]{%
\settoggle{bbx:swlabels}{#1}}
\DeclareBibliographyOption[boolean]{vcs}[true]{%
@@ -25,7 +29,7 @@
\DeclareBibliographyOption[boolean]{license}[true]{%
\settoggle{bbx:license}{#1}}
-\ExecuteBibliographyOptions{halid,swhid,swlabels,vcs,license}
+\ExecuteBibliographyOptions{halid,swhid,shortswhid,swlabels,vcs,license}
%
% Declare inheritance rules (valid only in LaTeX preamble!)
@@ -58,13 +62,18 @@
\usebibmacro{urldate}}}
%
-% Support multiline SWHIDs
+% Support multiline SWHIDs and create swhidcore field from swhid if missing
%
\DeclareStyleSourcemap{
\maps[datatype=bibtex,overwrite=true]{
\map{
\step[fieldsource=swhid, match=\regexp{\s}, replace={}]
}
+ \map{
+ \step[fieldsource=swhid]
+ \step[fieldset=swhidcore, origfieldval]
+ \step[fieldsource=swhidcore, match=\regexp{;.*}, replace={}]
+ }
}
}
@@ -91,8 +100,12 @@
\iftoggle{bbx:swhid}%
{\mkbibacro{SWHID}\addcolon\addspace%
\ifhyperref%
- {\href{http://archive.softwareheritage.org/#1}{\(\langle\)\nolinkurl{#1}\(\rangle\)}}%
- {\(\langle\)\nolinkurl{#1}\(\rangle\)}%
+ {\href{http://archive.softwareheritage.org/#1}{\(\langle\)\nolinkurl{%
+ \iftoggle{bbx:shortswhid}{\thefield{swhidcore}}{#1}%
+ }\(\rangle\)}}%
+ {\(\langle\)\nolinkurl{%
+ \iftoggle{bbx:shortswhid}{\thefield{swhidcore}}{#1}%
+ }\(\rangle\)}%
}%
{}%
}
diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-software/software.dbx b/macros/latex/contrib/biblatex-contrib/biblatex-software/software.dbx
index 4d45bc7fcc..f3861cfedf 100644
--- a/macros/latex/contrib/biblatex-contrib/biblatex-software/software.dbx
+++ b/macros/latex/contrib/biblatex-contrib/biblatex-software/software.dbx
@@ -17,6 +17,7 @@
hal_id,
hal_version,
swhid,
+ swhidcore,
}
%
diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-software/swentries.tex b/macros/latex/contrib/biblatex-contrib/biblatex-software/swentries.tex
index e9437d3329..8679263162 100644
--- a/macros/latex/contrib/biblatex-contrib/biblatex-software/swentries.tex
+++ b/macros/latex/contrib/biblatex-contrib/biblatex-software/swentries.tex
@@ -229,19 +229,54 @@ we can do this as follows:
@software {parmap,
title = {The Parmap library},
author = {Di Cosmo, Roberto and Marco Danelutto},
- date = {2020},
- version = {1.1.1},
+ date = {2012},
institution = {{Inria} and {University of Paris} and {University of Pisa}},
license = {LGPL-2.0},
url = {https://rdicosmo.github.io/parmap/},
repository= {https://github.com/rdicosmo/parmap},
}
+@softwareversion {parmap-1.1.1,
+ crossref = {parmap},
+ date = {2020},
+ version = {1.1.1},
+ swhid = {swh:1:rel:373e2604d96de4ab1d505190b654c5c4045db773;
+ origin=https://github.com/rdicosmo/parmap;
+ visit=swh:1:snp:2a6c348c53eb77d458f24c9cbcecaf92e3c45615},
+}
+
@codefragment {simplemapper,
subtitle = {Core mapping routine},
swhid = {swh:1:cnt:43a6b232768017b03da934ba22d9cc3f2726a6c5;
- lines=192-228;
- origin=https://github.com/rdicosmo/parmap},
- crossref = {parmap}
+ origin=https://github.com/rdicosmo/parmap;
+ visit=swh:1:snp:2a6c348c53eb77d458f24c9cbcecaf92e3c45615;
+ anchor=swh:1:rel:373e2604d96de4ab1d505190b654c5c4045db773;
+ path=/src/parmap.ml;
+ lines=192-228},
+ crossref = {parmap-1.1.1}
+}
+\end{verbatim}
+
+Of course, it is always be possible to use only one entry to get an equivalent
+result; here one would use just \texttt{@codefragment} with all the needed data
+fields as follows:
+
+\begin{verbatim}
+@codefragment {simplemapper-condensed,
+ title = {The Parmap library},
+ author = {Di Cosmo, Roberto and Marco Danelutto},
+ date = {2020},
+ institution = {{Inria} and {University of Paris} and {University of Pisa}},
+ license = {LGPL-2.0},
+ url = {https://rdicosmo.github.io/parmap/},
+ repository= {https://github.com/rdicosmo/parmap},
+ version = {1.1.1},
+ subtitle = {Core mapping routine},
+ swhid = {swh:1:cnt:43a6b232768017b03da934ba22d9cc3f2726a6c5;
+ origin=https://github.com/rdicosmo/parmap;
+ visit=swh:1:snp:2a6c348c53eb77d458f24c9cbcecaf92e3c45615;
+ anchor=swh:1:rel:373e2604d96de4ab1d505190b654c5c4045db773;
+ path=/src/parmap.ml;
+ lines=192-228}
}
\end{verbatim}
diff --git a/macros/luatex/generic/minim-math/README b/macros/luatex/generic/minim-math/README
index b463a8bad3..2463570ef8 100644
--- a/macros/luatex/generic/minim-math/README
+++ b/macros/luatex/generic/minim-math/README
@@ -1,4 +1,4 @@
-Version: 2021/1.0
+Version: 2022/1.1
SUMMARY
@@ -16,9 +16,22 @@ In order to obtain the typeset manual of this package, simply say:
luatex minim-math.doc
+HISTORY
+
+2022/1.1 (1/1/2022)
+
+ Minor changes:
+
+ * Made \setminus refer to the proper symbol.
+
+2021/1.0 (1/6/2021)
+
+ This was the original release.
+
+
COPYING
-(c) 2021 Esger Renkema
+(c) 2022 Esger Renkema
These files may be distributed under the terms of the European Union Public
Licence (EUPL) version 1.2 or later. A copy can be obtained at:
diff --git a/macros/luatex/generic/minim-math/minim-math-table.lua b/macros/luatex/generic/minim-math/minim-math-table.lua
index 3a12d1da99..5e6a70036c 100644
--- a/macros/luatex/generic/minim-math/minim-math-table.lua
+++ b/macros/luatex/generic/minim-math/minim-math-table.lua
@@ -106,13 +106,22 @@ return
, { code = 0x00308, char = ' ̈', class = 'accent', cs = 'ddot' } -- combining diaeresis
, { code = 0x00309, char = ' ̉', class = 'accent', cs = 'ovhook' } -- combining hook above
, { code = 0x0030A, char = ' ̊', class = 'accent', cs = 'ocirc' } -- combining ring above
+ , { code = 0x0030B, char = ' ̋', class = 'accent', cs = 'dacute' } -- combining double acute accent
, { code = 0x0030C, char = ' ̌', class = 'accent', cs = 'check' } -- combining caron
, { code = 0x00310, char = ' ̐', class = 'accent', cs = 'candra' } -- combining candrabindu
, { code = 0x00312, char = ' ̒', class = 'accent', cs = 'oturnedcomma' } -- combining turned comma above
, { code = 0x00315, char = ' ̕', class = 'accent', cs = 'ocommatopright' } -- combining comma above right
, { code = 0x0031A, char = ' ̚', class = 'accent', cs = 'droang' } -- combining left angle above
+ , { code = 0x00323, char = ' ̣', class = 'botaccent', cs = 'dotbelow' } -- combining dot below
+ , { code = 0x00324, char = ' ̤', class = 'botaccent', cs = 'ddotbelow' } -- combining diaeresis below
+ , { code = 0x00325, char = ' ̥', class = 'botaccent', cs = 'ocircbelow' } -- combining ring below
+ , { code = 0x00326, char = ' ̦', class = 'botaccent', cs = 'commabelow' } -- combining comma below
+ , { code = 0x00327, char = ' ̧', class = 'botaccent', cs = 'cedilla' } -- combining cedilla
+ , { code = 0x00328, char = ' ̨', class = 'botaccent', cs = 'ogonek' } -- combining ogonek
+ , { code = 0x00329, char = ' ̩', class = 'botaccent', cs = 'vlinebelow' } -- combining vertical line below
, { code = 0x00330, char = ' ̰', class = 'botaccent', cs = 'wideutilde' } -- combining tilde below
, { code = 0x00331, char = ' ̱', class = 'botaccent', cs = 'underbar' } -- combining macron below
+ , { code = 0x00336, char = ' ̶', class = 'overlay', cs = 'strike' } -- combining long stroke overlay
, { code = 0x00338, char = ' ̸', class = 'overlay', cs = 'not' } -- combining long solidus overlay
, { code = 0x00391, char = 'Α', class = 'var', cs = 'Alpha', alphabet = 'Greek' } -- greek capital letter alpha
, { code = 0x00392, char = 'Β', class = 'var', cs = 'Beta', alphabet = 'Greek' } -- greek capital letter beta
@@ -236,7 +245,7 @@ return
, { code = 0x02110, char = 'ℐ', class = 'ord', cs = 'mscrI', alphabet = 'script' } -- script capital i
, { code = 0x02111, char = 'ℑ', class = 'ord', cs = 'Im' } -- black-letter capital i
, { code = 0x02112, char = 'ℒ', class = 'ord', cs = 'mscrL', alphabet = 'script' } -- script capital l
- , { code = 0x02113, char = 'ℓ', class = 'ord', cs = 'ell', alphabet = 'script' } -- script small l
+ , { code = 0x02113, char = 'ℓ', class = 'ord', cs = 'ell' } -- script small l
, { code = 0x02115, char = 'ℕ', class = 'ord', cs = 'BbbN', alphabet = 'blackboard' } -- double-struck capital n
, { code = 0x02118, char = '℘', class = 'ord', cs = 'wp', } -- weierstrass elliptic function
, { code = 0x02119, char = 'ℙ', class = 'ord', cs = 'BbbP', alphabet = 'blackboard' } -- double-struck capital p
@@ -402,7 +411,7 @@ return
, { code = 0x02213, char = '∓', class = 'bin', cs = 'mp' } -- minus-or-plus sign
, { code = 0x02214, char = '∔', class = 'bin', cs = 'dotplus' } -- dot plus
, { code = 0x02215, char = '∕', class = 'bin', cs = 'divslash' } -- division slash
- , { code = 0x02216, char = '∖', class = 'bin', cs = 'smallsetminus' } -- set minus
+ , { code = 0x02216, char = '∖', class = 'bin', cs = 'setminus' } -- set minus
, { code = 0x02217, char = '∗', class = 'bin', cs = 'ast' } -- asterisk operator
, { code = 0x02218, char = '∘', class = 'bin', cs = 'vysmwhtcircle' } -- ring operator
, { code = 0x02219, char = '∙', class = 'bin', cs = 'vysmblkcircle' } -- bullet operator
@@ -1171,7 +1180,7 @@ return
, { code = 0x029F2, char = '⧲', class = 'ord', cs = 'errbarcircle' } -- error-barred white circle
, { code = 0x029F3, char = '⧳', class = 'ord', cs = 'errbarblackcircle' } -- error-barred black circle
, { code = 0x029F4, char = '⧴', class = 'rel', cs = 'ruledelayed' } -- rule-delayed
- , { code = 0x029F5, char = '⧵', class = 'bin', cs = 'setminus' } -- reverse solidus operator
+ , { code = 0x029F5, char = '⧵', class = 'bin', cs = 'rsolop' } -- reverse solidus operator
, { code = 0x029F6, char = '⧶', class = 'bin', cs = 'dsol' } -- solidus with overbar
, { code = 0x029F7, char = '⧷', class = 'bin', cs = 'rsolbar' } -- reverse solidus with horizontal stroke
, { code = 0x029F8, char = '⧸', class = 'op', cs = 'xsol' } -- big solidus
diff --git a/macros/luatex/generic/minim-math/minim-math.doc b/macros/luatex/generic/minim-math/minim-math.doc
index a176c9b1d0..79ff1dee71 100644
--- a/macros/luatex/generic/minim-math/minim-math.doc
+++ b/macros/luatex/generic/minim-math/minim-math.doc
@@ -8,8 +8,8 @@
\else \startmetadata
author {Esger Renkema}
title {minim-math}
- date {2021-06-01}
- version {2021/1.0}
+ date {2022-03-03}
+ version {2022/1.1}
keywords {LuaTeX; Plain TeX; Unicode mathematics}
stopmetadata
\maketitle \fi
@@ -49,7 +49,7 @@ Shorthand\quad\strut & Value of ⟦style⟧\quad\strut & Result \cr
Styles without shorthand are ⟦sans⟧/⟦sf⟧, ⟦sfit⟧, ⟦sfbf⟧, ⟦sfbfit⟧, ⟦tt⟧/⟦mono⟧
and finally the special value ⟦*clear⟧ for using the default style.
You can use the shorthands directly in sub- and superscripts: ⟦v^\scr F⟧ will
-result in $v^\scr F$.
+result in $v^\scr F$\kern-4pt.
While math families are not used anymore for switching between styles (see
below), you still can use ⟦\fam⟧ with the values 0, 1, 2, 4, 5, 6 or~7 for
@@ -135,11 +135,11 @@ this has been made so with ⟦*\mathdef ħ {\hbar}⟧ (you could also have said
The minimum you need do to set up a mathematical font is this:
⟦*\font\tenmath
- {Latin Modern Math:mode=base;script=math;ssty=0} at 10pt
+ {Latin Modern Math:mode=base;script=math;ssty=0;} at 10pt
\font\tenmaths
- {Latin Modern Math:mode=base;script=math;ssty=1} at 7pt
+ {Latin Modern Math:mode=base;script=math;ssty=1;} at 7pt
\font\tenmathss
- {Latin Modern Math:mode=base;script=math;ssty=2} at 5pt
+ {Latin Modern Math:mode=base;script=math;ssty=2;} at 5pt
\textfont 0 = \tenmath
\scriptfont 0 = \tenmaths
\scriptscriptfont 0 = \tenmathss⟧
@@ -159,6 +159,10 @@ family
⟦*\accentfam⟧, ⟦*\radicalfam⟧ and ⟦*\extensiblefam⟧ that control the family of
all accents, radicals and extensibles.
+Do note that various spacing constants are set according to the \emph{last}
+math family that is assigned to. Therefore, you should assign your main math
+font to a family after all others.
+
\section Shorthands and additions
diff --git a/macros/luatex/generic/minim-math/minim-math.lua b/macros/luatex/generic/minim-math/minim-math.lua
index 194e938819..6373809e43 100644
--- a/macros/luatex/generic/minim-math/minim-math.lua
+++ b/macros/luatex/generic/minim-math/minim-math.lua
@@ -2,7 +2,7 @@
local M = {}
local alloc = require ('minim-alloc')
-local callbacks = require ('minim-callbacks')
+local cb = require ('minim-callbacks')
alloc.remember('minim-math')
@@ -312,7 +312,7 @@ local transformcodes = alloc.saved_table ('math:transformcodes')
-- set a character as transformable
local function set_transform (num, char)
- c = alloc.new_count ('math transform '..char)
+ local c = alloc.new_count ('math transform '..char)
transformcodes[num] = c
tex.setcount ('global', c, num)
end
@@ -403,7 +403,7 @@ local function inspect_noads (h,d,n)
return true
end
-callbacks.register ('mlist_to_mlist', inspect_noads)
+cb.register ('mlist_to_mlist', inspect_noads)
-- 1 Reading the math character table
diff --git a/macros/luatex/generic/minim-math/minim-math.pdf b/macros/luatex/generic/minim-math/minim-math.pdf
index b5269815dc..33e9aec9f6 100644
--- a/macros/luatex/generic/minim-math/minim-math.pdf
+++ b/macros/luatex/generic/minim-math/minim-math.pdf
Binary files differ
diff --git a/macros/luatex/generic/minim-math/minim-math.tex b/macros/luatex/generic/minim-math/minim-math.tex
index e05ce17f7c..06fb632a5c 100644
--- a/macros/luatex/generic/minim-math/minim-math.tex
+++ b/macros/luatex/generic/minim-math/minim-math.tex
@@ -156,6 +156,10 @@
\mathlet · \cdot
\Umathchardef\cdotp "6"0"B7
+% move a macro over
+\protected\def\*{\discretionary{\thinspace
+ \the\textfont\Umathcharfam`\×\Uchar`\×}{}{}}
+
% some aliases
\let\neq = \ne
\let\le = \leq
diff --git a/macros/luatex/generic/minim-mp/README b/macros/luatex/generic/minim-mp/README
index dee13d1bfe..2e04ee1050 100644
--- a/macros/luatex/generic/minim-mp/README
+++ b/macros/luatex/generic/minim-mp/README
@@ -1,4 +1,4 @@
-Version: 2021/1.0
+Version: 2022/1.1
SUMMARY
@@ -17,9 +17,37 @@ In order to obtain the typeset manual of this package, simply say:
luatex minim-mp.doc
+HISTORY
+
+2022/1.1 (3/3/2022)
+
+ New features:
+
+ * Made instance initialisation more flexible; this replaces M.init_files
+ with M.init_code (see manual).
+ * Add support for the glyph of operator.
+ * Add support for the even-odd rule of filling and noncontinuous paths.
+ * Add experimental latex support (the minim-lamp format).
+ * Make minim-mp compatible with tikz/pgf.
+ * Expand the plain macro set slightly.
+
+ Minor changes:
+
+ * Improved display of metapost logs.
+ * Redefine units to fit other numerical engines better.
+ * Fixed a bug in pattern generation that prevented simplifying patterns
+ into raw pdf code.
+ * No longer write out superfluous line widths.
+
+
+2021/1.0 (1/6/2021)
+
+ This was the original release.
+
+
COPYING
-(c) 2021 Esger Renkema
+(c) 2022 Esger Renkema, Michal Vlasák
These files may be distributed under the terms of the European Union Public
Licence (EUPL) version 1.2 or later. A copy can be obtained at:
diff --git a/macros/luatex/generic/minim-mp/minim-lamp.ini b/macros/luatex/generic/minim-mp/minim-lamp.ini
new file mode 100644
index 0000000000..7900b3936a
--- /dev/null
+++ b/macros/luatex/generic/minim-mp/minim-lamp.ini
@@ -0,0 +1,20 @@
+
+\let\DUMP=\dump
+\let\dump=\endinput
+
+\input lualatex.ini
+
+\toksapp\everyjob{%
+ \documentclass{article}
+ \input minim-mp
+ \message{This is the minim-latex metapost processor.}\relax
+ \directlua {require('minim-mp').on_line = true}%
+ \newmetapostinstance[jobname="\jobname", mathmode="scaled"]\MP
+ \runmetapost\MP{input "\jobname";}%
+ \directlua {require('minim-mp').shipout(\the\MP)}%
+ \closemetapostinstance\MP
+ \csname @fileswfalse\endcsname\end{document}}
+
+\let\dump=\DUMP
+\dump
+
diff --git a/macros/luatex/generic/minim-mp/minim-mp.doc b/macros/luatex/generic/minim-mp/minim-mp.doc
index 788d26b6a0..b7fb47f416 100644
--- a/macros/luatex/generic/minim-mp/minim-mp.doc
+++ b/macros/luatex/generic/minim-mp/minim-mp.doc
@@ -8,8 +8,8 @@
\else \startmetadata
author {Esger Renkema}
title {minim-mp}
- date {2021-06-01}
- version {2021/1.0}
+ date {2022-03-03}
+ version {2022/1.1}
keywords {LuaTeX; Plain TeX; MetaPost; mplib}
stopmetadata
\maketitle \fi
@@ -35,7 +35,11 @@ error occurs, the logging will also be shown on the terminal.
This package can also be used as a stand-alone metapost compiler. Saying
\stopformulatagging$$\hbox{⟦luatex --fmt=minim-mp your_file.mp⟧}$$\startformulatagging
will create a pdf file of all images in ⟦your_file.mp⟧, in order, with page
-sizes adjusted to image dimensions.
+sizes adjusted to image dimensions. You might need generate the format first,
+this is done with
+\stopformulatagging$$\hbox{⟦luatex --ini minim-mp.ini⟧}$$\startformulatagging
+Use minim-lamp instead of minim-mp for an experimental latex-based version
+of the minim-mp format.
\section Metapost instances % 1
@@ -95,10 +99,15 @@ Arbitrary tex statements may be included in ⟦*verbatimtex ... etex⟧, which m
occur anywhere. These ⟦btex⟧ and ⟦verbatimtex⟧ statements are executed in the
order they are given.
+Previously-defined box resources can be included with ⟦*boxresource(nr)⟧. The
+result will be an image object with the proper dimensions. This image can be
+transformed in any way you like, but you cannot inspect the contents of the
+resource within metapost.
+
You can also use metapost’s ⟦*infont⟧ operator, which restricts the text
to-be-typeset to a single font, but returns an ⟦picture⟧ containing a ⟦picture⟧
for each character. The right-hand argument of ⟦infont⟧ should either be
-a (numerical) font id or the (cs)name of a font.
+a (numerical) font~id or the (cs)name of a font (without backslash).
One possible use of the ⟦infont⟧ operator is setting text along curves:
@@ -129,6 +138,52 @@ beginfig(1)
endfor
endfig;}\starttagging \stopelement{Figure}
+For the greatest amount of control, however, you will need the ⟦*glyph g of f⟧
+operator, which returns the contours that make up a glyph. It is a bit more
+versatile than its traditional metapost counterpart: ⟦g⟧ may also be the name
+of the glyph instead of its index, while ⟦f⟧ can be a font~id or font name (as
+with ⟦infont⟧).
+
+A variant of ⟦glyph of⟧ is the ⟦*contours t of f⟧ macro: it first typesets the
+string ⟦t⟧ in the same way as ⟦infont⟧ does (so that kerning and font shaping
+are applied), but returns a (comma-separated) list of contours, such as may be
+used in a ⟦for⟧ loop. Due to rounding errors, the glyphs will not match exactly.
+
+Be aware that the contours returned by these operators may be disjoint:
+a letter ⟦o⟧, for example, will consists of two. This means you cannot recreate
+the characters by just filling each contour: this would turn the ⟦o⟧ into
+a filled-in circle. Instead, you must use ⟦multifill⟧ on the entire output of
+⟦glyph of⟧ or ⟦contours of⟧ (see the next section).
+
+
+\section Partial paths and the even-odd rule % 1
+
+You can fill or draw two or more disjoint paths in one go by using ⟦*nofill⟧ as
+drawing operator for all paths but the last. This may make it easier to cut
+something out of a shape, since you do not have to worry about stitching the
+paths together.
+
+While metapost fills paths according to the winding number, the pdf format also
+supports filling according to the even-odd rule. This has been made possible
+with the ⟦*eofill⟧ and ⟦*eofilldraw⟧ drawing statements, which can of course
+also be used as the final statement after a series of nofills.
+
+The macros ⟦*multi(draw|fill|filldraw|eofill|eofilldraw)⟧ take a list of paths
+between parentheses and can be followed by the usual drawing options.
+For example,
+⟦multidraw (contours "example" of "tenbf") withpen currentpen scaled 1/10;⟧
+will give the word%
+\markelement{Span}{\setactualtext{example }
+\directmetapost{beginfig(1) multidraw (contours "example" of "tenbf")
+withpen currentpen scaled 1/10; baseline 0; endfig;}}
+in a thin outline.
+
+Finally, two handy clipping macros have been added:
+⟦*clipout⟧ and ⟦*clipto⟧, which both receive a list of paths as a ‘text’
+parameter and either clip their ensemble out of the picture, or the picture to
+the ensemble.
+
+
\section Running lua from within metapost % 1
You can call out to lua with ⟦*runscript "lua code"⟧. For this purpose, each
@@ -194,7 +249,7 @@ beginfig(1)
fill fullcircle scaled 3cm withpattern(a) withcolor 3/4red;
draw fullcircle scaled 3cm withpen pencircle scaled 1;
endfig;}\stopelement{Figure}\vss}\hskip10pt\strut
-
+\par\nobreak
⟦% define the pattern
picture letter; letter = maketext("a");
beginpattern(a)
@@ -209,25 +264,16 @@ endfig;⟧
A small pattern library is available in the ⟦*minim-hatching.mp⟧ file; see the
accompanying documentation sheet for an overview of patterns.
-Tiling patterns cannot be used together with tikz/pgf; see below under
-‘Resource management’.
\section Other metapost extensions % 1
-There is currently no support for the ⟦*glyph of⟧ operator.
-
You can set the baseline of an image with ⟦*baseline(p)⟧. There, ⟦p⟧ must
either be a point through which the baseline should pass, or a number (where an
x~coordinate of zero will be added). Transformations will be taken into
account, hence the specification of two coordinates. The last given baseline
will be used.
-Previously-defined box resources can be included with ⟦*boxresource(nr)⟧. The
-result will be an image object with the proper dimensions. This image can be
-transformed in any way you like, but you cannot inspect the contents of the
-resource within metapost.
-
You can write to tex’s log directly with ⟦*texmessage "hello"⟧.
You can write direct pdf statements with ⟦*special "pdf: statements"⟧ and you
@@ -235,6 +281,15 @@ can add comments to the pdf file with ⟦*special "pdfcomment: comments"⟧.
Say ⟦*special "latelua: lua code"⟧ to insert a ⟦late_lua⟧ whatsit.
All three specials can also be given as pre- or postscripts to another object.
In that case, they will be added before or after the object they are attached to.
+Do note that all ⟦special⟧ statements will appear at the beginning of the
+image; use pre- and postscripts to drawing statements if the order matters.
+
+Minim-mp also provides a few elementary macros and constants that are
+conspicuously absent from plain.mp; I hope their addition is uncontroversial.
+The constants are ⟦*pi⟧ (355/113), ⟦*fullsquare⟧, ⟦*unitcircle⟧ and the
+cmyk-colours ⟦*cyan⟧, ⟦*magenta⟧, ⟦*yellow⟧ and ⟦*key⟧. The macros are
+⟦*clockwise⟧, ⟦*xshifted⟧, ⟦*yshifted⟧, ⟦*hflip⟧ and ⟦*vflip⟧, where the flips
+are defined in such a way that ⟦p & hflip p⟧ gives the expected result.
\section Lua interface % 1
@@ -262,29 +317,6 @@ Each metapost instance is a table containing the following entries:
⟦env⟧&The lua environment for ⟦runscript⟧.\cr}
-\section PDF resource management % 1
-
-This package can add ⟦/Pattern⟧ and ⟦/ColorSpace⟧ entries to all page and xform
-resource dictionaries.
-Both refer to a single, global dictionary shared by all pages.
-Support for other keys may be added in the future.
-
-At the moment, this implementation only serves tiling pattern support;
-the mechanism will be enabled automatically at the first use of a tiling
-pattern (merely defining a pattern will not enable it) and is of little use for
-anything else.
-The relevant tables, should you want to expand on it yourself, are
-⟦M.colourspaces⟧ and ⟦M.patterns⟧; see the source file for additional
-instructions.
-
-Since pdf resource management must be done exactly once, this package may clash
-with other graphics packages doing the same.
-In particular, minim’s resource management will cause double (and thus invalid)
-entries in pages’ attribute dictionaries when used together with \red{tikz} or
-\red{pgf}.
-They can be used together, however, if you do not use minim’s tiling patterns.
-
-
\section Debugging % 1
You can enable (global) debugging by saying ⟦*debug_pdf⟧ to metapost or
@@ -321,9 +353,9 @@ processed; this information is still available inside the ⟦*finish_mpfigure⟧
callback that is executed just before the processed image is surrounded by
properly-dimensioned boxes.
-The ⟦*M.init_files⟧ table contains the list of metapost files that new instances
-are initialised with.
-The actual format will be loaded after the files in this table.
+The ⟦*M.init_code⟧ table contains the code used for initialing new instances.
+In it, the string ⟦INIT⟧ will be replaced with the value of the ⟦format⟧ option
+(normally ⟦plain.mp⟧).
\endmanual %
diff --git a/macros/luatex/generic/minim-mp/minim-mp.ini b/macros/luatex/generic/minim-mp/minim-mp.ini
index a257f6a18a..e3312a0cb9 100644
--- a/macros/luatex/generic/minim-mp/minim-mp.ini
+++ b/macros/luatex/generic/minim-mp/minim-mp.ini
@@ -7,6 +7,7 @@
\toksapp\everyjob{%
\message{This is the minim metapost processor.}\relax
+ \directlua {require('minim-mp').on_line = true}%
\newmetapostinstance[jobname="\jobname", mathmode="scaled"]\MP
\runmetapost\MP{input "\jobname";}%
\directlua {require('minim-mp').shipout(\the\MP)}%
diff --git a/macros/luatex/generic/minim-mp/minim-mp.lua b/macros/luatex/generic/minim-mp/minim-mp.lua
index 0f1851eba0..366313e60b 100644
--- a/macros/luatex/generic/minim-mp/minim-mp.lua
+++ b/macros/luatex/generic/minim-mp/minim-mp.lua
@@ -1,88 +1,13 @@
local alloc = require ('minim-alloc')
local cb = require('minim-callbacks')
+local pdfres = require('minim-pdfresources')
alloc.remember ('minim-mp')
local M = {}
-- 1 AUXILIARY FUNCTIONS
--- 2 pdf resource management
-
--- We add /ColorSpace and /Pattern entries to all page and xform resources.
--- Each key refers to a central (global) object mapping names to objects. This
--- central dictionary will be written to the pdf inside the finish_pdffile
--- callback.
---
--- In the future, /Shading and /ExtGState may also be added.
---
--- Central resource dictionaries and all used resources will be written to the
--- pdf inside the finish_pdf callback.
---
--- Since a resource dictionary can only contain one entry of each kind, this
--- package cannot coëxist with other packages doing their own resource
--- management. I am aware of only one other package doing that, however, which
--- is pgf. Luckily, pgf users are unlikely to be interested in metapost. Due to
--- this incompatibility, however, resource management must be enabled
--- explicitly.
-
--- keys are pdf names (starting with a slash)
-local patterns = { }; M.patterns = patterns
-local colourspaces = { }; M.colourspaces = colourspaces
-
-local global_resources, pattern_dict_objnum, colourspace_dict_objnum
-function M.enable_resource_management()
- if global_resources then return end
- -- central dictionary objects
- pattern_dict_objnum = pdf.reserveobj()
- colourspace_dict_objnum = pdf.reserveobj()
- global_resources = string.format('/Pattern %d 0 R /ColorSpace %d 0 R',
- pattern_dict_objnum, colourspace_dict_objnum)
- -- add to page and xform resources
- pdf.setpageresources((pdf.getpageresources() or '')..global_resources)
- pdf.setxformresources((pdf.getxformresources() or '')..global_resources)
-end
-
--- Saved patterns should have the following fields:
--- objnum the reserved object number for the pattern (optional)
--- used true if the pattern is in use (should be set automatically)
--- attr the pattern attributes
--- stream the pattern drawing statements
--- painttype the paint type of the pattern (1 or 2)
--- Saved colour spaces should have the following fields:
--- objnum the reserved object number for the colour space (optional)
--- used true if the pattern is in use (should be set automatically)
--- content the colour space contents (a pdf array)
-
-function M.write_resources()
- if not global_resources then return end
- -- patterns
- local used_patterns = { '<<' }
- for name, pat in pairs(patterns) do
- if pat.used then
- local objnum = pat.objnum or pdf.reserveobj()
- pdf.immediateobj(objnum, 'stream', pat.stream, pat.attr)
- table.insert(used_patterns, string.format('%s %d 0 R', name, objnum))
- end
- end
- table.insert(used_patterns, '>>')
- pdf.immediateobj(pattern_dict_objnum, table.concat(used_patterns, ' '))
- -- colour spaces
- local used_spaces = { '<<' }
- for name, space in pairs(colourspaces) do
- if space.used then
- local objnum = space.objnum or pdf.reserveobj()
- pdf.immediateobj(objnum, space.content)
- table.insert(used_spaces, string.format('%s %d 0 R', name, objnum))
- end
- end
- table.insert(used_spaces, '>>')
- pdf.immediateobj(colourspace_dict_objnum, table.concat(used_spaces, ' '))
-end
-
--- Write out resource objects at the end of the run
-cb.register('finish_pdffile', M.write_resources)
-
-- 2 state metatable
-- q Q store/restore graphics state
@@ -125,6 +50,7 @@ function A.save(append)
local st = append.state[#append.state] or { }
append.state[#append.state+1] =
{
+ linewidth = st.linewidth,
miterlimit = st.miterlimit,
linejoin = st.linejoin,
linecap = st.linecap,
@@ -159,6 +85,7 @@ local debugging = false
function M.enable_debugging()
debugging = true
pdf.setcompresslevel(0)
+ pdf.setobjcompresslevel(0)
end
local function print_prop(append, obj, prop)
@@ -270,7 +197,7 @@ local function curve_fmt(...)
end
function A.literal(append, fmt, ...)
- local lit = node.new(8,16)
+ local lit = node.new(8,16) -- pdf_literal
lit.data = fmt:format(...)
append:node(lit)
end
@@ -336,14 +263,14 @@ end
-- variables ‘stroke’ and ‘fill’ that record the last-used colour settings.
-- preload device colour pattern colour spaces
-colourspaces['/PsG'] = { content = '[ /Pattern /DeviceGray ]' }
-colourspaces['/PsRG'] = { content = '[ /Pattern /DeviceRGB ]' }
-colourspaces['/PsK'] = { content = '[ /Pattern /DeviceCMYK ]' }
+pdfres.add_resource('ColorSpace', 'PsG', { value = '[ /Pattern /DeviceGray ]' })
+pdfres.add_resource('ColorSpace', 'PsRG', { value = '[ /Pattern /DeviceRGB ]' })
+pdfres.add_resource('ColorSpace', 'PsK', { value = '[ /Pattern /DeviceCMYK ]' })
local colour_template = { '%.3f ', '%.3f %.3f ', '%.3f %.3f %.3f ', '%.3f %.3f %.3f %.3f ' }
local colour_stroke_operators = { 'G', nil, 'RG', 'K' }
local colour_fill_operators = { 'g', nil, 'rg', 'k' }
-local colour_pattern_spaces = { '/PsG', nil, '/PsRG', '/PsK' }
+local colour_pattern_spaces = { 'PsG', nil, 'PsRG', 'PsK' }
local function get_colour_params(cr)
return format_numbers(colour_template[#cr], table.unpack(cr))
@@ -353,16 +280,16 @@ local function get_stroke_colour(cr)
return get_colour_params(cr)..colour_stroke_operators[#cr]
end
-local function get_fill_colour(cr, pattern)
+local function get_fill_colour(append, cr)
local params = get_colour_params(cr)
- if pattern then
- local ptype, pname = table.unpack(pattern)
+ if append.pattern then
+ local ptype, pname = table.unpack(append.pattern)
if ptype == 2 then -- coloured pattern
local space = colour_pattern_spaces[#cr]
- colourspaces[space].used = true
- return string.format('%s cs %s%s scn', space, params, pname)
+ append:node(pdfres.use_resource_node('ColorSpace', space))
+ return string.format('/%s cs %s%s scn', space, params, alloc.pdf_name(pname))
elseif ptype == 1 then -- uncoloured pattern
- return string.format('/Pattern cs %s scn', pname)
+ return string.format('/Pattern cs %s scn', alloc.pdf_name(pname))
else -- should be unreachable
alloc.err('Unknown pattern paint type %s', ptype)
end
@@ -386,7 +313,7 @@ function A.colour(append, cr, otype)
end
-- fill colour (possibly a pattern)
if otype ~= 'outline' then
- local fill = get_fill_colour(cr, append.pattern)
+ local fill = get_fill_colour(append, cr)
append.pattern = nil -- patterns only apply to one object
if fill ~= append.fill then
append.fill = fill
@@ -432,7 +359,7 @@ function A.linestate (append, object)
end
elseif append.dashed then
append.dashed = false
- table.insert(res, string.format('[] 0 d'))
+ table.insert(res, '[] 0 d')
end
append:literal(table.concat(res, ' '))
end
@@ -505,16 +432,27 @@ end
-- h close the path
-- s close and draw the path (equivalent to h S)
-- f fill the path (implies h)
+-- f* fill the path, use even/odd rule
-- b close, fill and draw the path (equivalent to h B)
+-- b* close, fill and draw, use even/odd rule
-- n do nothing (used for clipping paths)
-local function get_path_operator (otype, open)
+local function get_path_operator(otype, open)
if otype == 'fill' then
return 'f'
elseif otype == 'outline' then
return (open and 'S') or 's'
elseif otype == 'both' then
return 'b'
+ elseif otype == 'nofill' then
+ return ''
+ elseif otype == 'eofill' then
+ return 'f*'
+ elseif otype == 'eofilldraw' then
+ return 'b*'
+ else
+ alloc.err('Unknown path type ‘%s’', otype)
+ return 'f'
end
end
@@ -557,7 +495,8 @@ local function split_specials(specials)
end
end
-local function parse_object (append, object)
+local function parse_object(append, object)
+ append.object_info = { }
append:printobj(object)
local processor = nil
for sp, instr in split_specials(object.prescript) do
@@ -616,29 +555,28 @@ end
-- 2 fill and outline
-function A.set_pen(append, object, otype, open)
+process.fill_or_outline = function(append, object, otype)
+ append:linestate(object)
+ local t, appendpath
if object.pen and object.pen.type == 'elliptical' then
-- metapost includes nonelliptical pens in the outline
- local t = mplib.pen_info(object)
- append:literal(pdfnum('w', t.width))
- if otype == 'fill' then otype = 'both' end
+ t = mplib.pen_info(object)
+ if t.width ~= append.linewidth then
+ append:literal(pdfnum('w', t.width))
+ append.linewidth = t.width
+ end
+ if otype == 'fill' then otype = 'both' end -- for in append:colour
local transformed = not ( t.sx == 1 and t.rx == 0
and t.ry == 0 and t.sy == 1
and t.tx == 0 and t.ty == 0 )
- return transformed and t, get_path_operator(otype, open), otype
- else
- return false, get_path_operator(otype, open), otype
+ t = transformed and t
end
-end
-
-process.fill_or_outline = function(append, object, otype)
+ append:colour(object.color, otype) -- otype is 'fill' 'outline' or 'both'
+ otype = append.object_info.otype or otype -- 'eofill' etc.
local open = object.path
and object.path[1].left_type
and object.path[#object.path].right_type
- local t, operator, otype = append:set_pen(object, otype, open)
- append:colour(object.color, otype)
- append:linestate(object)
- local appendpath
+ local operator = get_path_operator(otype, open)
if t then
local d = t.sx * t.sy - t.rx - t.ry
local concat = function(px, py)
@@ -671,6 +609,9 @@ end
-- 2 specials
+-- this will be pointed to the right table at the start of each run
+local current_instance = false
+
-- pure specials are already taken care of in parse_object (they only have
-- a ‘prescript’ field).
process.special = function(append, object) end
@@ -692,6 +633,10 @@ prescripts.latelua = function(append, str, object)
end
postscripts.latelua = prescripts.latelua
+prescripts.OTYPE = function(append, str, object)
+ append.object_info.otype = append.object_info.otype or str
+end
+
specials.BASELINE = function(append, str, object)
-- object is a ‘fill’ statement with only a single point in its path (and
-- will thus not have to be transformed).
@@ -700,15 +645,26 @@ end
-- 2 patterns
+-- Saved patterns have the following fields:
+-- attr the pattern attributes
+-- stream the pattern drawing statements
+-- painttype the paint type of the pattern (1 or 2)
+
+local function write_pattern_object(pat)
+ local objnum = pat.objnum or pdf.reserveobj()
+ pdf.obj(objnum, 'stream', pat.stream, pat.attr)
+ pdf.refobj(objnum)
+ return string.format('%d 0 R', objnum)
+end
+
prescripts.fillpattern = function(append, str, object)
- M.enable_resource_management()
- local name = '/MnmP'..tonumber(str)
- local pat = patterns[name]
+ local name = 'MnmP'..tonumber(str)
+ local pat = pdfres.get_resource('Pattern', name)
if not pat then
alloc.err('Unknown pattern %s', name)
else
append.pattern = { pat.painttype, name }
- pat.used = true
+ append:node(pdfres.use_resource_node('Pattern', name))
end
end
@@ -719,9 +675,18 @@ specials.definepattern = function(append, str, object)
matrix = { xx = xx, xy = xy, yx = yx, yy = yy, x = 0, y = 0 } }
end
+local function make_pattern_xform(head, bb)
+ -- regrettably, pdf.refobj does not work with xforms, so we must
+ -- write it to the pdf immediately, whether the pattern will be
+ -- used or not.
+ local xform = tex.saveboxresource(node.hpack(node.copy_list(head)),
+ '/Subtype/Form '..bb, nil, true, 4)
+ return string.format(' /Resources << /XObject << /PTempl %d 0 R >> >>', xform), '/PTempl Do'
+end
+
local function definepattern(head, user, bb)
local bb = bbox_fmt(table.unpack(bb))
- local pat, literals, resources = { }, { }
+ local pat, literals, resources = { write = write_pattern_object }, { }
-- pattern content
for n in node.traverse(head) do
-- try if we can construct the content stream ourselves; otherwise,
@@ -735,31 +700,27 @@ local function definepattern(head, user, bb)
elseif n.subtype == 31 then -- restore
table.insert(literals, 'Q')
else
- goto fail
+ resources, pat.stream = make_pattern_xform(head, bb)
+ goto continue
end
+ else
+ resources, pat.stream = make_pattern_xform(head, bb)
+ goto continue
end
pat.stream = table.concat(literals, '\n')
end
- ::fail:: do
- -- regrettably, pdf.refobj does not work with xforms, so we must
- -- write it to the pdf immediately, whether the pattern will be
- -- used or not.
- local xform = tex.saveboxresource(node.hpack(node.copy_list(head)),
- '/Subtype/Form '..bb, resources, true, 4)
- resources = string.format(' /Resources << /XObject << /PTempl %d 0 R >> >>', xform)
- pat.stream = '/PTempl Do'
- end
+ ::continue::
-- construct the pattern object
local i = user.pattern_info
local m = i.matrix
pat.painttype = tonumber(i.painttype)
pat.attr = table.concat({
- string.format(' /PatternType 1 /PaintType %d /TilingType %s /XStep %f /YStep %f\n',
+ string.format('/PatternType 1 /PaintType %d /TilingType %s /XStep %f /YStep %f\n',
i.painttype, i.tilingtype, i.xstep, i.ystep),
string.format('%s\n/Matrix [ %s %s %s %s %s %s ]', bb, m.xx, m.xy, m.yx, m.yy, m.x, m.y),
resources }, '')
-- remember the pattern
- patterns['/MnmP'..i.nr] = pat
+ pdfres.add_resource('Pattern', 'MnmP'..i.nr, pat)
end
cb.register('finish_mpfigure', function(img)
@@ -787,17 +748,16 @@ local function get_transform(rect)
return sx, rx, ry, sy, tx, ty
end
-local function make_surrounding(nd_id, head)
+local function make_surrounding_box(nd_id, head)
local nd = node.new(nd_id)
- nd.dir = 'TLT'
- nd.head = head
+ nd.dir, nd.head = 'TLT', head
return nd
end
-local function apply_translation(box, tx, ty)
- local horizontal = make_surrounding(0, box)
- local vertical = make_surrounding(1, horizontal)
- local outer = make_surrounding(0, vertical)
+local function wrap_picture(head, tx, ty)
+ local horizontal = make_surrounding_box(0, head)
+ local vertical = make_surrounding_box(1, horizontal)
+ local outer = make_surrounding_box(0, vertical)
vertical.shift = tex.sp('-'..ty..'bp')
horizontal.shift = tex.sp(''..tx..'bp')
return outer
@@ -805,10 +765,10 @@ end
local function apply_transform(rect, box)
local sx, rx, ry, sy, tx, ty = get_transform(rect)
- local transform = node.new(8,29)
+ local transform = node.new(8,29) -- pdf_setmatrix
transform.next, box.prev = box, transform
transform.data = string.format('%f %f %f %f', sx, rx, ry, sy)
- return apply_translation(transform, tx, ty)
+ return wrap_picture(transform, tx, ty)
end
function A.box(append, object, box)
@@ -827,7 +787,7 @@ end
specials.CHAR = function(append, data, object)
local char, font, xo, yo = table.unpack(data:explode(' '))
- local n = node.new(29)
+ local n = node.new(29) -- glyph
n.char, n.font, n.xoffset, n.yoffset =
tonumber(char), tonumber(font), tonumber(xo), tonumber(yo)
append:box(object, node.hpack(n))
@@ -847,7 +807,7 @@ M.instances = instances
-- 2 small instance helper functions
-local default_catcodes = alloc.new_catcodetable('minim:mp:catcodes')
+local default_catcodes = alloc.registernumber('minim:mp:catcodes')
-- parameters: wd, ht+dp, dp
local function make_transform(w, h, d)
@@ -855,21 +815,27 @@ local function make_transform(w, h, d)
w/65536, (h+d)/65536, d/65536)
end
-local function print_log (nr, res)
+local status_names = { [0] = 'good', 'warning', 'error', 'fatal' }
+local function print_status(st)
+ return string.format('status %d (%s)', st, status_names[st])
+end
+
+M.on_line = false
+local function print_log (nr, res, why)
local i = instances[nr]
- -- only write to term if exit status increases
+ -- only write to term if on_line or if exit status increases
local log, alog
- if res.status > i.status then
+ if M.on_line or res.status > i.status then
local nrlines, maxlines = 0, 16
alog = alloc.amsg
log = function(...)
- if nrlines == maxlines then
+ if M.on_line or nrlines < maxlines then
+ nrlines = nrlines + 1
+ alloc.msg(...)
+ else
alloc.log(...)
alloc.term('╧ [... see log file for full report ...]')
log, alog = alloc.log, alloc.alog
- else
- nrlines = nrlines + 1
- alloc.msg(...)
end
end
else
@@ -881,15 +847,11 @@ local function print_log (nr, res)
report[#report] = nil
end
-- write out the log
- if #report > 0 then
- log('┌ exit status %d', res.status)
- for _,line in ipairs(report) do
- log('│ '..line)
- end
- log('└')
- else
- log('[ no logs for this run; exit status %d ]', res.status)
+ log('┌ %smetapost instance %s (%d)', why or '', i.jobname, i.nr)
+ for _,line in ipairs(report) do
+ log('│ '..line)
end
+ log('└ %s', print_status(res.status))
-- generate error or warning if needed
if res.status > i.status then
if res.status == 3 then
@@ -897,7 +859,7 @@ local function print_log (nr, res)
elseif res.status == 2 then
alloc.err('Error in metapost code. Further errors will be ignored')
elseif res.status == 1 then
- alloc.msg('Metapost: code caused warning')
+ alloc.msg('Metapost code caused warning')
end
end
-- save the exit status for later comparison
@@ -915,7 +877,6 @@ end
-- 2 processing results
local function process_results(nr, res)
- print_log(nr, res)
local pictures = {}
if res.fig then
alloc.alog (' (%d figures)', #res.fig)
@@ -951,7 +912,7 @@ local function process_results(nr, res)
end
cb.call_callback('finish_mpfigure', pic)
if not pic.discard then
- pic.head = apply_translation(append.head, -llx, -bas)
+ pic.head = wrap_picture(append.head, -llx, -bas)
end
if debugging then
alloc.msg('┌ image %s, with %s objects, %s nodes',
@@ -987,8 +948,6 @@ local function default_env()
return env
end
-local current_instance = false
-
local function runscript(code)
local f, msg = load(code, current_instance.jobname, 't', current_instance.env)
if f then
@@ -1053,22 +1012,22 @@ local function maketext(text, mode)
end
end
-local infont_box = alloc.new_box('infont box')
-function M.infont(text, fnt)
- local fontid = tonumber(fnt) or font.id(fnt)
+local function getfontid(fnt)
+ return tonumber(fnt) or font.id(fnt)
+end
+
+local typeset_box = alloc.new_box('infont box')
+
+local function process_typeset(text, fnt, sep, fn)
tex.runtoks(function()
tex.sprint(default_catcodes, string.format(
- '\\setbox%d=\\hbox{\\setfontid%d\\relax', infont_box, fontid))
+ '\\setbox%d=\\hbox{\\setfontid%d\\relax', typeset_box, getfontid(fnt)))
tex.sprint(-2, text); tex.sprint(default_catcodes, '}')
end)
local res, x = { }, 0
- for n in node.traverse(tex.box[infont_box].list) do
+ for n in node.traverse(tex.box[typeset_box].list) do
if n.id == 29 then -- glyph
- table.insert(res, string.format(
- 'draw image ( fill unitsquare shifted (%fpt,0) withprescript "CHAR:%d %d %d %d";'
- ..'setbounds currentpicture to unitsquare transformed %s shifted (%fpt,0););',
- x/65536, n.char, n.font, n.xoffset, n.yoffset,
- make_transform(n.width, n.height, n.depth), x/65536))
+ fn(res, n, x)
x = x + n.width
elseif n.id == 12 then -- glue
x = x + n.width
@@ -1076,7 +1035,88 @@ function M.infont(text, fnt)
x = x + n.kern
end
end
- return table.concat(res, '')
+ return table.concat(res, sep)
+end
+
+function M.infont(text, fnt)
+ return process_typeset(text, fnt, '', function(res, n, x)
+ table.insert(res, string.format(
+ 'draw image ( fill unitsquare shifted (%fpt,0) withprescript "CHAR:%d %d %d %d";'
+ ..'setbounds currentpicture to unitsquare transformed %s shifted (%fpt,0););',
+ x/65536, n.char, n.font, n.xoffset, n.yoffset,
+ make_transform(n.width, n.height, n.depth), x/65536))
+ end)
+end
+
+
+-- 2 glyph contours
+
+function M.make_glyph(glyphname, fnt)
+ -- gather information
+ if not luaotfload then
+ alloc.err('Luaotfload required for glyph of operator')
+ return { }, 10
+ end
+ local fontid = getfontid(fnt)
+ local thefont = font.getfont(fontid)
+ local fontname = thefont.psname
+ local gid = luaotfload.aux.gid_of_name(fontid, glyphname)
+ if not gid then
+ alloc.err('Font %s has no glyph named %s', thefont.psname, glyphname)
+ return { }, 10
+ end
+ local segments = fonts.hashes.shapes[fontid].glyphs[gid].segments
+ if #segments == 0 then return { }, 10 end
+ local q = 1000 / (thefont.units_per_em or 1000)
+ -- retrieve the contours
+ local path, paths = { '(' }, { }
+ for _, s in ipairs(segments) do
+ local op = s[#s]
+ if op == 'm' then
+ if #path > 1 then
+ table.insert(path, '--cycle)')
+ table.insert(paths, table.concat(path, ''))
+ path = { '(' }
+ end
+ table.insert(path, string.format('(%f, %f)', q*s[1], q*s[2]))
+ elseif op == 'l' then
+ table.insert(path, string.format('--(%f, %f)', q*s[1], q*s[2]))
+ elseif op == 'c' then
+ table.insert(path, string.format('..controls (%f, %f) and (%f, %f) .. (%f, %f)',
+ q*s[1], q*s[2], q*s[3], q*s[4], q*s[5], q*s[6]))
+ end
+ end
+ table.insert(path, '--cycle)')
+ table.insert(paths, table.concat(path, ''))
+ return paths, thefont.size
+end
+
+function M.get_named_glyph(name, fnt)
+ local res, contours, size = {}, M.make_glyph(name, fnt)
+ for _, c in ipairs(contours) do
+ table.insert(res, string.format(
+ '%s scaled %f', c, size/65536000))
+ end
+ return table.concat(res, ', ')
+end
+
+local function get_glyphname(c_id)
+ return luaotfload.aux.name_of_slot(c_id)
+end
+
+function M.get_glyph(c_id, fnt)
+ return M.get_named_glyph(get_glyphname(c_id), fnt)
+end
+
+function M.get_contours(text, fnt)
+ return process_typeset(text, fnt, ', ', function(res, n, x)
+ local contours, size = M.make_glyph(get_glyphname(n.char), n.font)
+ for _, c in ipairs(contours) do
+ table.insert(res, string.format(
+ '%s scaled %f shifted (%fpt, %fpt)', c,
+ size/65536/1024, (x + n.xoffset)/65536, n.yoffset/65536))
+ end
+ end)
end
-- 2 opening, running and and closing instances
@@ -1122,27 +1162,21 @@ function M.run (nr, code)
return
end
current_instance = self
- alloc.log ('metapost: executing chunk in %s (%d)', self.jobname, nr)
- local res = process_results(nr, self.instance:execute(code))
- save_image_list(self, res)
+ local res = self.instance:execute(code)
+ print_log(nr, res)
+ local picts = process_results(nr, res)
+ save_image_list(self, picts)
end
-M.init_files = { 'minim.mp' }
+M.init_code = { 'let dump=endinput;', 'input INIT;', 'input minim.mp;' }
function M.open (t)
local nr = #instances + 1
t.jobname = t.jobname or ':metapost:'
- alloc.log ('metapost: creating instance %s (%d)', t.jobname, nr)
-- creating instance options
- local init = ""
- for _, f in ipairs(M.init_files) do
- init = string.format('%s input %s;', init, f)
- end
- init = string.format('%s input %s;', init, t.format or 'plain.mp')
+ local init = string.gsub(table.concat(M.init_code, ''), 'INIT', t.format or 'plain.mp')
local opts = apply_default_instance_opts(t)
local instance = mplib.new(opts)
- instance:execute(init)
- local continue
-- adding the instance
instances[nr] =
{ nr = nr
@@ -1154,15 +1188,15 @@ function M.open (t)
, boxes = { } -- allocated by maketext
, env = t.env or default_env()
}
+ print_log(nr, instance:execute(init), 'opening ')
return nr
end
function M.close (nr)
local i = instances[nr]
- alloc.log ('metapost: closing instance %s (%d) ', i.jobname, nr)
if i.instance then
local res = i.instance:finish()
- print_log(nr, res)
+ print_log(nr, res, 'closing ')
end
for _, nr in ipairs(i.boxes) do
-- remove allocated boxes
diff --git a/macros/luatex/generic/minim-mp/minim-mp.pdf b/macros/luatex/generic/minim-mp/minim-mp.pdf
index b511de3297..1011878d1e 100644
--- a/macros/luatex/generic/minim-mp/minim-mp.pdf
+++ b/macros/luatex/generic/minim-mp/minim-mp.pdf
Binary files differ
diff --git a/macros/luatex/generic/minim-mp/minim-mp.tex b/macros/luatex/generic/minim-mp/minim-mp.tex
index 8e39c7f227..ad84a4f19d 100644
--- a/macros/luatex/generic/minim-mp/minim-mp.tex
+++ b/macros/luatex/generic/minim-mp/minim-mp.tex
@@ -6,6 +6,7 @@
\catcode`\: = 11
\input minim-alloc
+\input minim-pdfresources
% a default catcode table
\newcatcodetable \minim:mp:catcodes
@@ -30,7 +31,7 @@
% \directmetapost [ options ] { code }
\protected\def\directmetapost{\withoptions[]\directmetapost:}
-\def\directmetapost:[#1]#2{%
+\long\def\directmetapost:[#1]#2{%
\begingroup
\newmetapostinstance[#1]\:mpinst:
\runmetapost\:mpinst:{#2}%
diff --git a/macros/luatex/generic/minim-mp/minim.mp b/macros/luatex/generic/minim-mp/minim.mp
index c78dde2a92..f3f03eb3d0 100644
--- a/macros/luatex/generic/minim-mp/minim.mp
+++ b/macros/luatex/generic/minim-mp/minim.mp
@@ -1,13 +1,19 @@
delimiters ();
+% redefine some constants to work with the new numerical engines
+numeric mm, cm, pt, pc, dd, cc;
+pc = 12 pt; cc = 12 dd; cm = 10 mm;
+803 pt = 800; 127 mm = 360; 1157 dd = 1238 pt;
+eps := 1/2048; infinity := 64*64-epsilon;
+
message "Loading the minim extension macros";
% interaction with tex
-def baseline expr o =
- fill if numeric o: (0,o) else o fi
+vardef baseline expr o =
+ fill if numeric o : (0,o) else: o fi
-- cycle withprescript "BASELINE:"; enddef;
-def boxresource expr nr = image(
+vardef boxresource expr nr = image(
fill unitsquare withprescript "BOXRESOURCE:" & decimal nr ;
setbounds currentpicture to unitsquare transformed runscript
("return { 'box_size', tex.getboxresourcedimensions(" & decimal nr & ") }");
@@ -17,6 +23,46 @@ primarydef t infont f = image( runscript(
"return require('minim-mp').infont("&ditto&t&ditto&", "
&if numeric f: decimal(f) else: ditto&f&ditto fi&")" ) ) enddef;
+% even-odd rule
+def nofill expr c = fill c withprescript "OTYPE:nofill" enddef;
+def eofill expr c = fill c withprescript "OTYPE:eofill" enddef;
+def eofilldraw expr c = filldraw c withprescript "OTYPE:eofilldraw" enddef;
+
+def multidraw (text paths) text opts = draw image(
+ for p = paths: ; nofill p opts endfor
+ withprescript "OTYPE:outline";) enddef;
+def multifill (text paths) text opts = draw image(
+ for p = paths: ; nofill p opts endfor
+ withprescript "OTYPE:fill";) enddef;
+def multifilldraw (text paths) text opts = draw image(
+ for p = paths: ; nofill p opts endfor
+ withprescript "OTYPE:filldraw";) enddef;
+def multieofill (text paths) text opts = draw image(
+ for p = paths: ; nofill p opts endfor
+ withprescript "OTYPE:eofill";) enddef;
+def multieofilldraw (text paths) text opts = draw image(
+ for p = paths: ; nofill p opts endfor
+ withprescript "OTYPE:eofilldraw";) enddef;
+
+vardef clipto text t =
+ clip currentpicture to bbox currentpicture
+ for c = t: -- c -- cycle endfor -- cycle enddef;
+vardef clipout text t =
+ clip currentpicture to
+ for c = t: c -- cycle -- endfor cycle enddef;
+
+vardef glyph expr c of f = image(for p =
+ runscript("return require('minim-mp').get_"
+ &if string c: "named_glyph("&ditto&c&ditto
+ else: "glyph("& decimal c fi &", "
+ &if numeric f: decimal(f) else: ditto&f&ditto fi
+ & ")" ) : ; nofill p endfor
+ withprescript "OTYPE:fill"; ) enddef;
+
+def contours expr t of f =
+ runscript("return require('minim-mp').get_contours("&ditto&t&ditto&", "
+ &if numeric f: decimal(f) else: ditto&f&ditto fi& ")" ) enddef;
+
% interaction with lua
vardef hexadecimal expr n =
% TODO: support other number systems
@@ -68,6 +114,31 @@ def endpattern (expr xstep, ystep) =
newinternal tilingtype; tilingtype:=1;
_patterns_._last_ := 0;
-% so that we can load plain.mp after this
-let dump = endinput ;
+% shorthands
+primarydef p xshifted x = p shifted (x,0) enddef;
+primarydef p yshifted y = p shifted (0,y) enddef;
+
+% reverse paths to allow „p & vflip p”
+def hflip primary p = if path p: reverse fi p xscaled -1 enddef;
+def vflip primary p = if path p: reverse fi p yscaled -1 enddef;
+
+% missing definitions
+path fullsquare, unitcircle ;
+fullsquare := unitsquare shifted - center unitsquare ;
+unitcircle := fullcircle shifted urcorner fullcircle ;
+
+% complement counterclockwise
+vardef clockwise primary c =
+ if turningnumber c > 0: reverse fi c enddef;
+
+% cmyk colours
+cmykcolor cyan, magenta, yellow, key;
+cyan = (1,0,0,0);
+magenta = (0,1,0,0);
+yellow = (0,0,1,0);
+key = (0,0,0,1);
+
+% constants
+pi := 355/113;
+
diff --git a/macros/luatex/generic/minim-pdf/README b/macros/luatex/generic/minim-pdf/README
index 1d1f02a913..d8f2b19c6e 100644
--- a/macros/luatex/generic/minim-pdf/README
+++ b/macros/luatex/generic/minim-pdf/README
@@ -1,4 +1,4 @@
-Version: 2021/1.0
+Version: 2022/1.1
SUMMARY
@@ -25,9 +25,32 @@ In order to obtain the typeset manual of this package, simply say:
luatex minim-pdf.doc
+HISTORY
+
+2022/1.1 (3/3/2022)
+
+ New features:
+
+ * Added support for structure element attributes.
+ * Added support for structure element attribute classes.
+ * Improved tagging of equations; added configuration.
+ * Made tagged artifacts more robust: they can now occur across page
+ breaks.
+ * The lua interface should now be more-or-less stable.
+
+ Minor changes:
+
+ * PDF strings will be encoded in a more clever (and readable) way.
+ * Structure element tags will have special characters encoded properly.
+
+2021/1.0 (1/6/2021)
+
+ This was the original release.
+
+
COPYING
-(c) 2021 Esger Renkema
+(c) 2022 Esger Renkema
These files may be distributed under the terms of the European Union Public
Licence (EUPL) version 1.2 or later. A copy can be obtained at:
diff --git a/macros/luatex/generic/minim-pdf/minim-languagecodes.lua b/macros/luatex/generic/minim-pdf/minim-languagecodes.lua
index df3e95a65e..6a8b6f3b0b 100644
--- a/macros/luatex/generic/minim-pdf/minim-languagecodes.lua
+++ b/macros/luatex/generic/minim-pdf/minim-languagecodes.lua
@@ -78,6 +78,7 @@ return {
latvian = 'lv',
lithuanian = 'lt',
liturgicallatin = 'la-x-liturgic',
+ macedonian = 'mk',
malayalam = 'ml',
marathi = 'mr',
medievalgreek = 'gkm',
@@ -94,8 +95,10 @@ return {
norwegian = 'nb',
nynorsk = 'nn',
occitan = 'oc',
+ oldgerman = 'de',
oriya = 'or',
pali = 'pi',
+ panjabi = 'pa',
patois = 'fr',
persian = 'fa',
piedmontese = 'pms',
@@ -111,6 +114,7 @@ return {
sahidic = 'cop-x-sahidic',
samaritan = 'smp',
sanskrit = 'sa',
+ schoolfinnish = 'fi',
serbian = 'sr-latn',
serbianc = 'sr-cyrl',
slovak = 'sk',
@@ -129,11 +133,11 @@ return {
turkish = 'tr',
turkmen = 'tk',
ugaritic = 'uga',
- uncoded = 'mis',
- undetermined = 'und',
ukenglish = 'en-UK',
UKenglish = 'en-UK',
ukrainian = 'uk',
+ uncoded = 'mis',
+ undetermined = 'und',
uppersorbian = 'hsb',
usenglish = 'en-US',
USenglish = 'en-US',
diff --git a/macros/luatex/generic/minim-pdf/minim-pdf.doc b/macros/luatex/generic/minim-pdf/minim-pdf.doc
index 2c06dd25b0..71e8cea89c 100644
--- a/macros/luatex/generic/minim-pdf/minim-pdf.doc
+++ b/macros/luatex/generic/minim-pdf/minim-pdf.doc
@@ -14,8 +14,8 @@ all other features of the package are described here.
\else \startmetadata
author {Esger Renkema}
title {minim-pdf}
- date {2021-06-01}
- version {2021/1.0}
+ date {2022-03-03}
+ version {2022/1.1}
keywords {LuaTeX; Plain TeX; PDF/A; Tagged PDF; accessibility; a11y;
hypertext; bookmarks; document outline; associated files}
stopmetadata
@@ -47,8 +47,9 @@ generated name.
\section Bookmarks % 1
-Bookmarks can be added with ⟦*\outline [open] [dest {name}] {title}⟧.
-Add ⟦open⟧ to have the bookmark appear initially open and
+Bookmarks can be added with ⟦*\outline [open|closed] [dest {name}] {title}⟧.
+Add ⟦open⟧ or ⟦closed⟧ to have the bookmark appear initially open or
+closed (default), and
say ⟦dest {name}⟧ for having it refer to a specific named destination
(otherwise, a new one will be created where the ⟦\outline⟧ command appears).
@@ -129,11 +130,10 @@ With the minim-xmp package, a useful setting is
\section Lua module % 1
The interface of the lua module (available via
-⟦local M = require('minim-pdf')⟧) is not stable yet, and may change.
-One function of interest, however, is
-⟦M.pdf_string(...)⟧, wich converts a lua string to a pdf string. The
-surrounding ⟦<>⟧ or ⟦()⟧ characters are included in the return value.
-
+⟦local M = require('minim-pdf')⟧) should be stable by now.
+Though it contains lua equivalents for most tex commands described here, using
+them directly is not very ergonomical and not recommended.
+Please consult the source if you do want to use them anyway.
% 
@@ -160,7 +160,7 @@ be seen by tex’s stomach in the \emph{logical} order.
Furthermore, while the macros in this package are sophisticated enough that
tagging can be done without any manual intervantion, it is quite possible and
-rather easy to generate the wrong document structore, or even cause syntax
+rather easy to generate the wrong document structure, or even cause syntax
errors in the resulting pdf code.
You should always check the result in an external application.
@@ -169,21 +169,17 @@ This is the full list of limitations, pitfalls and shortcomings:
\item1. Document content must be seen by tex in its logical order (although you
can mark out-of-order content explicitly if you know what you are doing; see
below).
-\item2. Artifacts cannot be split across pages. A pagebreak inmidst an artifact
-will cause incorrect pdf without error or warning.
-\item3. The contents of ⟦\localleftbox⟧ and ⟦\localrightbox⟧ must be marked
+\item2. The contents of ⟦\localleftbox⟧ and ⟦\localrightbox⟧ must be marked
manually, probably as artifact.
-\item4. You must mark page header, page footer and footnote rule yourself; no
+\item3. You must mark page header, page footer and footnote rule yourself; no
default is set.
-\item5. There currently is no way of marking xforms or other pdf objects as
+\item4. There currently is no way of marking xforms or other pdf objects as
content items of themselves.
-\item6. The content of xforms (i.e. pdf objects created by ⟦\useboxresource⟧)
+\item5. The content of xforms (i.e. pdf objects created by ⟦\useboxresource⟧)
should not contain tagging commands.
-\item7. Likewise, you should be careful with box reuse: it might work, but you
+\item6. Likewise, you should be careful with box reuse: it might work, but you
should check.
-\item8. The use of structure element attributes is currently not supported
-except in a limited number of cases.
-\item9. This package currently only supports pdf~1.7 tagging and is not yet
+\item7. This package currently only supports pdf~1.7 tagging and is not yet
ready for use with pdf~2.0.
\stoplist
@@ -234,7 +230,7 @@ structure element instead.
The begining and ending of a content item can be forced with
⟦*\startcontentitem⟧ and ⟦*\stopcontentitem⟧, while ⟦*\ensurecontentitem⟧ will
only open a new content item if you are currently outside any.
-If you need some part to be a single content item, that can use
+If you need some part to be a single content item, you can use
⟦*\startsinglecontentitem ... \stopsinglecontentitem⟧.
This will disable all SE and MCI tagging inside.
@@ -249,8 +245,6 @@ Artifacts can be marked in two ways: with ⟦*\markartifact {type} {...}⟧ or w
The ⟦type⟧ is written to the pdf attribute dictionary directly, so that if you
need a subtype, you can write e.g.
⟦\startartifact {Pagination /Subtype/Header} etc⟧.
-Do make sure your artifact does not contain a page break, as this will result
-in invalid output.
Inside artifacts, other structure content markers will be ignored. Furthermore,
this package makes sure artifacts are never part of marked content items,
@@ -281,11 +275,11 @@ perfect nor complete. You should always check the results in an external
application.
Particular care should be taken when ‘skipping’ structure levels: the sequence
chapter – subsection – section will result in the section beneath the subsection.
-If you are in doubt about an element being closed already, you can use
+If you are in doubt whether an element has been closed already, you can use
⟦*\ensurestopelement {Tag}⟧ instead of ⟦\stopelement⟧
to prevent an error being raised.
-All these helpful features can also be disabled by setting
+All these helpful features can be disabled by setting
⟦*\strictstructuretagging⟧ to a positive value. Then, every structure element
will have to be closed by an explicit closing tag, as in xml.
In this case, ⟦\stopelement⟧ and ⟦\ensurestopelement⟧ will be equivalent.
@@ -293,6 +287,8 @@ In this case, ⟦\stopelement⟧ and ⟦\ensurestopelement⟧ will be equivalent
By default, ⟦P⟧ structure elements are inserted automatically at the start of
every paragraph. The tag can be changed with ⟦*\nextpartag {Tag}⟧; leaving the
argument empty will prevent marking the next paragraph.
+Keep in mind that the reassignment is local: if a paragraph marked with
+⟦\nextpartag⟧ starts inside a group, it will not reset.
Auto-marking paragraphs can be (locally) disabled or enabled by saying
⟦*\markparagraphsfalse⟧ or ⟦*\markparagraphstrue⟧.
@@ -326,20 +322,28 @@ in more complicated situations you should therefore use
⟦*\savecurrentelementto\name ... \continueelementfrom\name⟧ which restores the
current SE from a named identifier ⟦\name⟧.
-
\section Structure element options % 1
-The ⟦\startcontentitem⟧ command allows a few options that are not mentioned
-above: its full syntax is ⟦*\startcontentitem <options> {Tag}⟧.
+The ⟦\startelement⟧ command allows a few options that are not mentioned
+above: its full syntax is ⟦*\startelement <options> {Tag}⟧.
The three most useful options are ⟦alt⟧ for setting an alt-text (the ⟦/Alt⟧
entry in the structure element dicionary), ⟦actual⟧ for a text replacement
(⟦/ActualText⟧) and ⟦lang⟧ for the language (⟦/Lang⟧; see the next section).
The alternative and actual texts can also be given after the fact with
-⟦*\setalttext{...}⟧ and ⟦*\setactualtext{...}⟧. These apply to the current
+⟦*\setalttext{...}⟧ and ⟦*\setactualtext{...}⟧; these apply to the current
structure element.
-Setting structure element attributes is not supported at this moment, except
-the placement attributes ⟦block⟧ and ⟦inline⟧, which can be given as options.
+Structure element attributes can be given with
+⟦attr <owner> <key> <value>⟧, e.g. ⟦attr Layout Placement /Inline⟧.
+Note that for the ⟦owner⟧ and ⟦key⟧ the initial slash must be omitted; the
+⟦value⟧ on the other hand will be written to the pdf verbatim.
+Any number of attributes can be added.
+
+Finally, structure element classes can be given with the
+⟦class <classname>⟧ keyword, which can be repeated.
+Classes can be defined with
+⟦*\newattributeclass classname <attributes>⟧ where ⟦<attributes>⟧ can be any
+number of ⟦attr⟧ statements as above.
\section Languages % 1
@@ -358,7 +362,7 @@ separate codes to dialects.
There is a small set of default language code associations, which can be found
in the file ⟦minim-languagecodes.lua⟧.
It covers most languages defined by the hyph-utf8 package, as well as (due to
-their ubiquitous use) many ancient languages.
+their ubiquitous use) some ancient languages.
An actual language change introduced by ⟦\uselanguage⟧ will not otherwise be
acted upon by this package. Therefore, you will probably want to add
@@ -381,7 +385,7 @@ This package ensures the existence of the ⟦nohyph⟧, ⟦nolang⟧, ⟦uncoded
⟦undetermined⟧ dummy languages, all without hyphenation.
-\section Helper macros
+\section Helper macros % 1
For marking up an entry in a table of contents, you can use the macro
⟦*\marktocentry {dest} {lbl} {title} {filler} {pageno}⟧, which should insert all
@@ -410,14 +414,18 @@ are used for lay-out and should not be marked as such.
After the latter command, auto-tagging can be switched off and on with
⟦*\stopformulatagging⟧ and ⟦*\startformulatagging⟧.
-Both alt and actualtext of the ⟦Formula⟧ structure element will be set to the
-(unexpanded) source code of the equation, surrounded by the appropriate number
-of dollar signs.
-Furthermore, if ⟦\pdfaconformancelevel⟧ equals three, the source of the formula
-will be attached in an embedded file with the ⟦/AFRelation⟧ set to ⟦Source⟧.
+The source of the equation can be associated with the ⟦Formula⟧ structure
+element in various ways, which can be configured with ⟦*\includeformulasources
+{option}⟧, where the ⟦option⟧ must be one of ⟦none⟧, ⟦actualtext⟧, ⟦attachment⟧
+or ⟦both⟧.
+The ⟦actualtext⟧ option will use the unexpanded source code of the equation,
+surrounded by the appropriate number of dollar signs.
+The ⟦attachment⟧ option will only work if ⟦\pdfaconformancelevel⟧ equals three:
+then the source of the formula will be attached in an embedded file with the
+⟦/AFRelation⟧ set to ⟦Source⟧.
The name of this file can be changed by redefining ⟦*\formulafilename⟧ inside
the equation.
-
+The default value is ⟦both⟧.
% 
diff --git a/macros/luatex/generic/minim-pdf/minim-pdf.lua b/macros/luatex/generic/minim-pdf/minim-pdf.lua
index ffe845061c..96725523d2 100644
--- a/macros/luatex/generic/minim-pdf/minim-pdf.lua
+++ b/macros/luatex/generic/minim-pdf/minim-pdf.lua
@@ -2,6 +2,7 @@
local M = { }
local alloc = require('minim-alloc')
local cb = require('minim-callbacks')
+alloc.remember('minim-hooks')
alloc.remember('minim-pdf')
-- 1 helper functions
@@ -18,9 +19,27 @@ local function add_to_names(...)
pdf.setnames((pdf.getnames() or '') .. string.format(...) .. ' ')
end
+local pdf_name = alloc.pdf_name
+local pdf_string = alloc.pdf_string
+local options_scanner = alloc.options_scanner
+
+-- has this table just one element?
+local function singleton(t)
+ local one = false
+ for _, _ in pairs(t) do
+ if one then
+ return false
+ else
+ one = true
+ end
+ end
+ return one
+end
+
-- in-depth node list traversal
-- returns current and parent node
--- only dives into hbox and vbox nodes
+-- only dives into hbox, vbox and ins nodes
+-- returns node and enclosing box
local function full_traverse(head)
return function(stack, last)
local next = last.next
@@ -36,103 +55,8 @@ local function full_traverse(head)
end, { { } }, { next = head }
end
--- re-encode to utf-16 and surround by <>
-local function pdf_hex_string(text)
- local str = { [1] = '<feff' }
- for i in text:utfvalues() do
- if i < 0xFFFF then
- insert_formatted(str, '%04x', i)
- else
- i = i - 0x10000
- m = math.floor(i/0x400) + 0xD800
- n = ( i % 0x400 ) + 0xDC00
- insert_formatted(str, '%04x%04x' ,m, n)
- end
- end
- table.insert(str, '>')
- return table.concat(str,'')
-end
-
--- try and produce a () string first, then fall back to <>
-function M.pdf_string(text)
- local str = { '(' }
- for i in text:utfvalues() do
- if i > 0x7E then
- return pdf_hex_string(text)
- elseif i < 0x20 then
- insert_formatted(str, '\\%03o', i)
- elseif i == 0x28 or i == 0x29 or i == 0x5c then
- insert_formatted(str, '\\%c', i)
- else
- insert_formatted(str, '%c', i)
- end
- end
- table.insert(str, ')')
- return table.concat(str,'')
- end
-
--- make available as \pdfstring{...}
-alloc.luadef('pdfstring', function() M.pdf_string(token.scan_string()) end)
-
--- try and produce a date of the format (D:YYYYMMDD)
-function M.pdf_date(text)
- local y, m, d = string.match(text, '^([12][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)$')
- if not y then d, m, y = string.match(text, '^([0-9][0-9]?)-([0-9][0-9]?)-([12][0-9][0-9][0-9])$') end
- if y then
- return string.format('(D:%4d%02d%02d)', y, m, d)
- else
- return string.format('(D:%s)', text)
- end
-end
-
-function M.options_scanner()
- return { scanners = { },
- add = function(this, name, scanner)
- this.scanners[name] = scanner
- return this
- end,
- keyword = function(this, name)
- return this:add(name, function() return true end)
- end,
- int = function(this, name)
- return this:add(name, token.scan_int)
- end,
- glue = function(this, name)
- return this:add(name, token.scan_glue)
- end,
- dimen = function(this, name)
- return this:add(name, token.scan_dimen)
- end,
- string = function(this, name)
- return this:add(name, token.scan_string)
- end,
- argument = function(this, name)
- return this:add(name, token.scan_argument)
- end,
- word = function(this, name)
- return this:add(name, token.scan_word)
- end,
- list = function(this, name)
- return this:add(name, token.scan_list)
- end,
- scan = function(this, defaults)
- local res = defaults or { }
- repeat
- local matched = false
- for name, scanner in pairs(this.scanners) do
- if token.scan_keyword(name) then
- matched, this.scanners[name] = true, nil
- res[name] = scanner()
- end
- end
- until not matched
- return res
- end
- }
-end
-
local function pdf_err(n, msg)
- local m = node.new(8,16)
+ local m = node.new(8,16) -- pdf_literal
m.mode, m.token = 2, '%% Warning: '..msg
node.insert_after(n, n, m)
end
@@ -158,10 +82,10 @@ local structure = { {
local parent_tree = { } -- list of list of structure elements
-- Our four helper attributes
-local current_struct = alloc.new_attribute('tagging:current:se')
-local current_order = alloc.new_attribute('tagging:element:order')
-local current_status = alloc.new_attribute('tagging:current:status')
-local current_lang = alloc.new_attribute('tagging:current:language')
+local current_struct = alloc.registernumber('tagging:current:se')
+local current_order = alloc.registernumber('tagging:element:order')
+local current_status = alloc.registernumber('tagging:current:status')
+local current_lang = alloc.registernumber('tagging:current:language')
local function current_structure_element()
return structure[tex.attribute[current_struct]]
@@ -242,7 +166,7 @@ local structure_types = alloc.saved_table('structure types', {
Note = { type = 'inline' },
Reference = { type = 'inline' },
BibEntry = { type = 'inline' },
- Code = { type = 'inline' },
+ Code = { type = 'inline', attributes = { ['CSS-2.00'] = { ['white-space'] = '(pre)' } } },
Link = { type = 'inline' }, -- contains link objects
Annot = { type = 'inline' }, -- contains other annotations
-- ruby/warichu
@@ -318,7 +242,6 @@ alloc.luadef('struct:addalias', function()
M.add_structure_alias(stype, alias, settings)
end, 'protected')
-
-- 1 writing the document structure
local function stable_sort_on_order_field(unsorted)
@@ -373,7 +296,7 @@ local function make_rolemap()
local aliases = { }
for k, v in pairs(structure_types) do
if v.aliasof and v.inuse and v.aliasof ~= k then
- insert_formatted(aliases, '/%s/%s', k, v.aliasof)
+ insert_formatted(aliases, '%s%s', pdf_name(k), pdf_name(v.aliasof))
end
end
if #aliases > 0 then
@@ -382,6 +305,33 @@ local function make_rolemap()
return ''
end
+local function make_attributes(res, t)
+ -- is there just one attribute?
+ local list = not singleton(t)
+ if list then table.insert(res, '[') end
+ for ao, ac in pairs(t) do
+ insert_formatted(res, '<< /O %s', pdf_name(ao))
+ for k,v in pairs(ac) do
+ insert_formatted(res, '%s %s', pdf_name(k), v)
+ end
+ table.insert(res, '>>')
+ end
+ if list then table.insert(res, ']') end
+end
+
+local attribute_classes = alloc.saved_table('attribute classes')
+local function make_classmap()
+ local classes = { }
+ for c, as in pairs(attribute_classes) do
+ insert_formatted(classes, '\n%s', pdf_name(c))
+ make_attributes(classes, as)
+ end
+ if #classes > 0 then
+ return '\n/ClassMap << ' .. table.concat(classes, ' ') .. ' >>'
+ end
+ return ''
+end
+
local function write_structure()
if #structure == 1 then return end
-- reserve object numbers, prepare for writing
@@ -395,22 +345,29 @@ local function write_structure()
add_to_catalog('/StructTreeRoot %s 0 R', root_obj)
-- write the structure tree root
pdf.immediateobj(root_obj, string.format(
- '<< /Type/StructTreeRoot /K %d 0 R /ParentTree %d 0 R%s >>',
- structure[1].objnum, parent_tree_obj, make_rolemap()))
+ '<< /Type/StructTreeRoot /K %d 0 R /ParentTree %d 0 R%s%s >>',
+ structure[1].objnum, parent_tree_obj, make_rolemap(), make_classmap()))
-- write structure elements
for _, se in ipairs(structure) do
if not se.hidden then
local res = { '<<' }
- insert_formatted(res, '/Type/StructElem /S/%s /P %d 0 R', se.struct, se.parent.objnum)
+ insert_formatted(res, '/Type/StructElem /S%s /P %d 0 R', pdf_name(se.struct), se.parent.objnum)
if se.lang and se.lang ~= se.parent.lang then insert_formatted(res, '/Lang (%s)', se.lang) end
- if se.alt then insert_formatted(res, '/Alt %s', M.pdf_string(se.alt)) end
- if se.actual then insert_formatted(res, '/ActualText %s', M.pdf_string(se.actual)) end
+ if se.alt then insert_formatted(res, '/Alt %s', pdf_string(se.alt)) end
+ if se.actual then insert_formatted(res, '/ActualText %s', pdf_string(se.actual)) end
if #se.children > 0 then insert_formatted(res, '\n/K %s', format_K_array(se)) end
if se.mainpage then insert_formatted(res, '/Pg %d 0 R', se.mainpage) end
+ if se.class then
+ table.insert(res, '/C')
+ if #se.class > 1 then table.insert(res, '[') end
+ for _, c in ipairs(se.class) do
+ insert_formatted(res, '%s', pdf_name(c))
+ end
+ if #se.class > 1 then table.insert(res, ']') end
+ end
if se.attributes then
- table.insert(res, '/A <<')
- for k,v in pairs(se.attributes) do insert_formatted(res, '/%s %s', k, v) end
- table.insert(res, '>>')
+ table.insert(res, '/A')
+ make_attributes(res, se.attributes)
end
if se.files then
table.insert(res, '/AF [')
@@ -487,11 +444,10 @@ end, 'protected')
-- \uselanguage patch; provide default document language
-- and associate names with numbers
-alloc.luadef('minim:apply:language:code', function()
- local name = token.scan_string()
+cb.register('uselanguage', function(name)
local nr = language_codes[name] or alloc.err('No language code known for ‘%s’', name) and 1
if not structure[1].lang then M.set_document_language(language_codes[nr]) end
- tex.sprint(nr)
+ tex.attribute['tagging:current:language'] = nr
end)
local function write_language()
@@ -536,24 +492,20 @@ end, 'protected')
function M.open_structure_node(n)
local info = structure_types[n.struct]
if not info then
- alloc.err('Unknown structure type %s replaced by NonStruct', n.struct)
+ alloc.err('Unknown structure type %s replaced with NonStruct', n.struct)
n.struct, info = 'NonStruct', structure_types.NonStruct
end
info.inuse = true
if info.attributes then
- n.attributes = n.attributes or { }
- for k,v in pairs(info.attributes) do
- n.attributes[k] = n.attributes[k] or v
+ n.attributes = n.attr or { }
+ for k1,v1 in pairs(info.attributes) do
+ n.attributes[k1] = n.attributes[k1] or { }
+ for k2, v2 in pairs(v1) do
+ n.attributes[k1][k2] = n.attributes[k1][k2] or v2
+ end
end
- end
- if n.block then
- n.type = 'block'
- n.attributes = n.attributes or { }
- n.attributes.Placement = '/Block'
- elseif n.inline then
- n.type = 'inline'
- n.attributes = n.attributes or { }
- n.attributes.Placement = '/Inline'
+ else
+ n.attributes = n.attr
end
n.index = #structure + 1
n.children = { }
@@ -573,13 +525,13 @@ function M.open_structure_node(n)
end
alloc.luadef('tagging:startelement', function()
- local s = M.options_scanner()
+ local s = options_scanner()
:string('type') -- 'section', 'group', 'block' etc.
:argument('alt')
:argument('actual')
:string('lang')
- :keyword('block')
- :keyword('inline')
+ :subtable('attr')
+ :string('class', true)
:scan()
s.struct = token.scan_string()
M.open_structure_node(s)
@@ -593,6 +545,11 @@ alloc.luadef('tagging:actual', function()
current_structure_element().actual = token.scan_string()
end)
+alloc.luadef('newattributeclass', function()
+ local s = options_scanner():subtable('attr')
+ attribute_classes[token.scan_string()] = s:scan().attr
+end, 'protected')
+
-- 1 marking content items
@@ -613,7 +570,7 @@ local function clear_page_tagging_parameters()
_open_mci_node_ = function (se_num, order)
pageobj = pageobj or pdf.getpageref(status.total_pages + 1)
local se = structure[se_num]
- pdf.print(string.format('/%s <</MCID %d>> BDC ', se.struct, #mcid_list))
+ pdf.print(string.format('%s <</MCID %d>> BDC ', pdf_name(se.struct), #mcid_list))
table.insert(se.children, { mcid = #mcid_list, order = order, pageobj = pageobj })
table.insert(mcid_list, se)
-- unhide hidden parents (done here to preserve the correct order)
@@ -631,17 +588,13 @@ local function new_open_mci_node(se, order)
return n
end
-local function new_open_art_node(atype)
+local function pdf_literal(token)
local n = node.new(8,16) -- pdf_literal
- n.mode, n.token = 1, string.format('/Artifact << /Type/%s >> BDC', atype)
+ n.mode, n.token = 1, token
return n
end
-local function new_emc_node()
- local n = node.new(8,16) -- pdf_literal
- n.mode, n.token = 1, 'EMC'
- return n
-end
+local open_artifacts = { }
cb.register('finish_pdfpage', function(shippingout)
if shippingout then
@@ -655,17 +608,17 @@ cb.register('finish_pdfpage', function(shippingout)
end
end)
--- 1 content item boundaries and linking
+-- 1 content item boundaries and linking (in pre-shipout)
function M.mark_content_items(box)
- local se, order, open
+ local se, order, art, open
local start_node, end_node, parent_node
local pageobj = pdf.getpageref(status.total_pages + 1)
- -- inserting mci markers
+ -- helper functions for inserting mci markers
local insert_tags = function(end_parent)
if not open then return end
parent_node.list = node.insert_before(parent_node.list, start_node, open)
- node.insert_after(end_parent.list, end_node, new_emc_node())
+ node.insert_after(end_parent.list, end_node, pdf_literal('EMC'))
start_node, end_node, parent_node, open = nil, nil, nil, nil
end
local start_content = function(n, b)
@@ -676,18 +629,31 @@ function M.mark_content_items(box)
for n, b in full_traverse(box) do
local marker = n.id == 8 and n.subtype == 8
and n.user_id == marker_whatsit and n.value
- if marker and marker.what == 'art_start' then
+ local stat = n[current_status]
-- first we start with marking artifacts
+ if marker and marker.what == 'art_start' then
insert_tags(b);
start_content(n, b)
- open = new_open_art_node(marker.it)
+ local a = string.format('/Artifact << /Type/%s >> BDC', marker.it)
+ open_artifacts[stat], open, art = a, pdf_literal(a), stat
elseif marker and marker.what == 'art_stop' then
end_node = n
insert_tags(b);
- elseif n[current_status] then
- -- inside artifact, do nothing
- elseif n.id == 8 and n.subtype == 19 then -- pdf_start_link
+ open_artifacts[art], art = nil, nil
+ elseif stat and stat >10 and stat ~=art then -- broken artifact
+ insert_tags(b);
+ start_content(n, b)
+ local a = open_artifacts[stat]
+ if not a then
+ alloc.err('Encountered tail of unknown artifact (see pdf)')
+ pdf_err(n, 'unknown artifact (this should not be possible)')
+ a = '/Artifact << /Type/Unknown >> BDC'
+ end
+ open, art = pdf_literal(a), stat
+ elseif stat then -- inside artifact or tagging disabled
+ end_node = n
-- then attach links to Link elements
+ elseif n.id == 8 and n.subtype == 19 then -- pdf_start_link
local _se, _order = n[current_struct], n[current_order]
local link = structure[_se]
if link.struct == 'Link' then
@@ -698,16 +664,16 @@ function M.mark_content_items(box)
alloc.err('Link found outside Link structure element (see pdf)')
pdf_err(n, 'unmarked link')
end
+ -- handle explicit start and stop nodes
elseif marker and marker.what == 'mci_start' then
- -- explicit start and stop nodes
insert_tags(b);
start_content(n, b)
open = new_open_mci_node(se, order)
elseif marker and marker.what == 'mci_stop' then
end_node = end_node and n; insert_tags(b)
+ -- finally, see if we need to intervene between content nodes
elseif n.id == 2 or n.id == 29 -- rule, glyph or content marker
or marker and marker.what == 'content' then
- -- now see if we need to intervene between content nodes
local _se, _order = n[current_struct], n[current_order]
if n.id == 2 and (n.width == 0 or n.height == 0 and n.depth == 0) then
-- ignore invisible rules
@@ -720,8 +686,7 @@ function M.mark_content_items(box)
insert_tags(b);
start_content(n, b)
open = new_open_mci_node(se, order)
- else
- -- nothing changed: continue current mci
+ else -- nothing changed: continue current mci
end_node = n
end
elseif n.id == 12 and n.subtype > 2 and n.subtype < 8 then
@@ -730,10 +695,6 @@ function M.mark_content_items(box)
end
end
-- close the last mci
- if start_node and start_node.user_id and start_node.value
- and start_node.value.what == 'art_start' then
- alloc.err('Page %d ends with a broken artifact', status.total_pages+1)
- end
insert_tags(box)
end
@@ -786,7 +747,7 @@ local function write_bookmarks()
-- write bookmark objects
for i=2, #bookmarks do
local bm, res = bookmarks[i], { }
- insert_formatted(res, '<< /Title %s\n/Parent %s 0 R /Dest (%s)', M.pdf_string(bm.title),
+ insert_formatted(res, '<< /Title %s\n/Parent %s 0 R /Dest (%s)', pdf_string(bm.title),
bm.parent and bm.parent.outline_obj or bookmarks[1].outline_obj, bm.dest)
if bm.next then insert_formatted(res, '/Next %s 0 R', bm.next.outline_obj) end
if bm.prev then insert_formatted(res, '/Prev %s 0 R', bm.prev.outline_obj) end
@@ -827,9 +788,8 @@ function M.add_bookmark(bm)
end
alloc.luadef('outline', function()
- local s = M.options_scanner()
- :keyword('open')
- :keyword('closed') -- default; ignored
+ local s = options_scanner()
+ :keyword('open', 'closed')
:string('dest')
:scan()
s.title = token.scan_string()
@@ -866,8 +826,8 @@ function M.embed_file(t)
end
-- embed the file
local attr = { '/Type/EmbeddedFile' }
- if t.mimetype then insert_formatted(attr, '/Subtype/%s', string.gsub(t.mimetype, '/', '#2F')) end
- if t.moddate then insert_formatted(attr, '/Params << /ModDate %s >>', M.pdf_date(t.moddate)) end
+ if t.mimetype then insert_formatted(attr, '/Subtype%s', pdf_name(t.mimetype)) end
+ if t.moddate then insert_formatted(attr, '/Params << /ModDate %s >>', alloc.pdf_date(t.moddate)) end
local ef = pdf.obj {
immediate = true,
compresslevel = t.uncompressed and 0 or nil,
@@ -878,7 +838,7 @@ function M.embed_file(t)
-- write the filespec
local res = { '<< /Type/Filespec' }
insert_formatted(res, '/F %s /UF %s /EF << /F %d 0 R /UF %d 0 R >>', t.name, t.name, ef, ef)
- if t.desc then insert_formatted(res, '/Desc %s', M.pdf_string(t.desc)) end
+ if t.desc then insert_formatted(res, '/Desc %s', pdf_string(t.desc)) end
if t.relation then insert_formatted(res, '/AFRelationship /%s', t.relation) end
table.insert(res, '>>')
local fs = pdf.immediateobj(table.concat(res, ' '))
@@ -887,7 +847,7 @@ function M.embed_file(t)
end
alloc.luadef('embedfile', function()
- local t = M.options_scanner()
+ local t = options_scanner()
:string('desc')
:string('file')
:string('string')
@@ -901,7 +861,7 @@ alloc.luadef('embedfile', function()
if not t.name then
t.name = t.file or aloc.err('No name specified for embedded file stream')
end
- t.name = M.pdf_string(t.name or '(unnamed)')
+ t.name = pdf_string(t.name or '(unnamed)')
local fs, ef = M.embed_file(t, t.global)
-- where to attach?
if t.global then
@@ -1036,7 +996,7 @@ local function write_pagelabels()
end
local res = { '/PageLabels << /Nums [' }
for _, l in ipairs(pagelabels) do
- local s, p = l.s and '/S/'..l.s, l.p and ' /P '..M.pdf_string(l.p)
+ local s, p = l.s and '/S/'..l.s, l.p and ' /P '..pdf_string(l.p)
table.insert(res, string.format('%d << /St %d %s%s >>', l.start, l.st, s or '', p or ''))
end
table.insert(res, ']')
@@ -1083,7 +1043,7 @@ function M.add_default_rgb_output_intent(t)
N = 3, path = 'sRGB.icc' }
end
-function M.add_default_cmyk_output_intents(t)
+function M.add_default_cmyk_output_intent(t)
t = t or {}
M.add_output_intent {
subtype = t.subtype or 'GTS_PDFA1',
diff --git a/macros/luatex/generic/minim-pdf/minim-pdf.pdf b/macros/luatex/generic/minim-pdf/minim-pdf.pdf
index b460bdf4ed..414e577186 100644
--- a/macros/luatex/generic/minim-pdf/minim-pdf.pdf
+++ b/macros/luatex/generic/minim-pdf/minim-pdf.pdf
Binary files differ
diff --git a/macros/luatex/generic/minim-pdf/minim-pdf.tex b/macros/luatex/generic/minim-pdf/minim-pdf.tex
index f8075ae6e4..630c374d41 100644
--- a/macros/luatex/generic/minim-pdf/minim-pdf.tex
+++ b/macros/luatex/generic/minim-pdf/minim-pdf.tex
@@ -5,6 +5,9 @@
\chardef\minimpdfloaded = \catcode`\:
\catcode`\: = 11
+\input minim-alloc
+\input minim-hooks
+
% Abbreviations used throughout this document:
% se structure element
% mci marked content item
@@ -19,9 +22,6 @@
% 1 the attributes
-\input minim-alloc
-\input minim-hooks
-
% By three attributes do we determine the document structure.
%
% One for marking the current structure element:
@@ -37,7 +37,8 @@
%
% One for marking the status:
% - assignments are generally local
-% - if set, disables tagging and content marking
+% - if set, disables tagging and content marking in pre_shipout
+% - values >10 indicate artifacts
\newattribute \tagging:current:status \tagging:current:status = \unset
%
% A fourth attribute keeps track of the current language
@@ -53,7 +54,7 @@
% disables marking structure elements
\newif\iftagging:enabled \tagging:enabledtrue
\protected\def\starttagging{\tagging:enabledtrue
- \ifnum1=\tagging:current:status
+ \ifnum0<\tagging:current:status
\tagging:current:status\unset\fi}
\protected\def\stoptagging{\tagging:enabledfalse
\ifnum\unset=\tagging:current:status
@@ -62,9 +63,12 @@
% \markartifact {Layout} {...}
% \startartifact {Pagination /Subtype/Header} ... \stopartifact
\long\def\markartifact#1#2{\startartifact{#1}#2\stopartifact}
-\protected\def\startartifact{\begingroup\stoptagging
+\protected\def\startartifact{\begingroup\tagging:enabledfalse
+ \tagging:current:status=\tagging:current:artifact
+ \global\advance\tagging:current:artifact1\relax
\tagging:mci:incr\tagging:art:markstart}
\protected\def\stopartifact{\tagging:art:markstop\tagging:mci:incr\endgroup}
+\newcount\tagging:current:artifact \tagging:current:artifact = 11
% \startcontentitem ... \stopcontentitem
\protected\def\startcontentitem{\iftagging:enabled\tagging:mci:incr\tagging:mci:markstart\fi}
@@ -223,20 +227,36 @@
\def\tagging:startdisplay\fi\fi\fi#1$${\tagging:makeformula{#1}{$$}}
\def\tagging:makeformula#1#2{\fi\fi\fi
\global\advance\tagging:formulanr1\relax
- \startelement\iftagging:indisplay block\else inline\fi{Formula}%
- \setalttext{\tagging:formulasource{#1}}%
- \setactualtext{\tagging:formulasource{#1}}%
- \ifnum3=\pdfaconformancelevel
- \embedfile mimetype text/x-tex
- relation Source desc {Equation source}
- name {\formulafilename.tex}
- string {\tagging:formulasource{#1}}\fi
+ \startelement attr Layout Placement \iftagging:indisplay/Block\else/Inline
+ % some html converters ignore Placement attributes
+ attr CSS-2.00 display (inline)\fi{Formula}%
+ \formulasource:set{#1}%
\scantextokens{#1}#2}
\def\tagging:formulasource#1{%
$\iftagging:indisplay$\fi
\unexpanded{#1}%
$\iftagging:indisplay$\fi}
+% \includeformulasources {none|actualtext|attachment|both}
+\def\includeformulasources#1{%
+ \expandafter\let
+ \expandafter\formulasource:set
+ \csname formulasource:#1\endcsname}
+\def\formulasource:none#1{}
+\def\formulasource:actualtext#1{%
+ \setactualtext{\tagging:formulasource{#1}}}
+\def\formulasource:attachment#1{%
+ \ifnum3=\pdfaconformancelevel
+ \embedfile mimetype text/x-tex
+ relation Source desc {Equation source}
+ name {\formulafilename.tex}
+ string {\tagging:formulasource{#1}}\fi}
+\def\formulasource:both#1{%
+ \formulasource:actualtext{#1}%
+ \formulasource:attachment{#1}}
+\includeformulasources{both}
+
+
% 1 hyperlinks
% provided by the lua module:
@@ -265,20 +285,6 @@
% provided by the lua module:
% \setdocumentlanguage {name or code}
% \setlanguagecode {name} {code}
-% \minim:apply:language:code{name} → index
-
-% patch in language codes to \uselanguage
-\ifcsname uselanguage@hook\endcsname
- \expandafter\let
- \expandafter\minim:uselanguagehook
- \lastnamedcs \fi
-\expandafter\edef\csname uselanguage@hook\endcsname#1{%
- % tagging support
- \noexpand\tagging:current:language
- \noexpand\minim:apply:language:code{#1}%
- % previous definitions
- \ifdefined\minim:uselanguagehook
- \noexpand\minim:uselanguagehook{#1}\fi}
% \newnamedlanguage {name} {lhm} {rhm}
\def\newnamedlanguage#1#2#3{%
diff --git a/macros/luatex/generic/minim-xmp/README b/macros/luatex/generic/minim-xmp/README
index 0383085ee2..46d9d3cc6e 100644
--- a/macros/luatex/generic/minim-xmp/README
+++ b/macros/luatex/generic/minim-xmp/README
@@ -1,4 +1,4 @@
-Version: 2021/1.0
+Version: 2022/1.1
SUMMARY
@@ -19,9 +19,22 @@ In order to obtain the typeset manual of this package, simply say:
luatex minim-xmp.doc
+HISTORY
+
+2022/1.1 (3/3/2022)
+
+ New features:
+
+ * Writing metadata can now be disabled globally.
+
+2021/1.0 (1/6/2021)
+
+ This was the original release.
+
+
COPYING
-(c) 2021 Esger Renkema
+(c) 2022 Esger Renkema
These files may be distributed under the terms of the European Union Public
Licence (EUPL) version 1.2 or later. A copy can be obtained at:
diff --git a/macros/luatex/generic/minim-xmp/minim-xmp.doc b/macros/luatex/generic/minim-xmp/minim-xmp.doc
index 01d2084f6c..57fe527d2c 100644
--- a/macros/luatex/generic/minim-xmp/minim-xmp.doc
+++ b/macros/luatex/generic/minim-xmp/minim-xmp.doc
@@ -8,8 +8,8 @@
\else \startmetadata
author {Esger Renkema}
title {minim-xmp}
- date {2021-06-01}
- version {2021/1.0}
+ date {2022-03-03}
+ version {2022/1.1}
keywords {LuaTeX; Plain TeX; XMP; metadata; PDF/A;}
stopmetadata
\maketitle \fi
@@ -156,6 +156,68 @@ after which the generated XMP code will be
</colours:Favourite>
</rdf:Description>⟧
+If use of the pdf/a format is detected (i.e. a ⟦pdfaid⟧ entry is present in the
+metadata), the following pdf/a extension schema will also be generated:
+
+\font\seventt {Latin Modern Mono:script=latn;+smcp;} at 7pt
+\begingroup\rightskip=-6cm\baselineskip=9pt
+⟦∥let∥tentt∥seventt∥seventt<rdf:Description rdf:about=""
+ xmlns:pdfaExtension="http://www.aiim.org/pdfa/ns/extension/"
+ xmlns:pdfaSchema="http://www.aiim.org/pdfa/ns/schema#"
+ xmlns:pdfaProperty="http://www.aiim.org/pdfa/ns/property#"
+ xmlns:pdfaType="http://www.aiim.org/pdfa/ns/type#"
+ xmlns:pdfaField="http://www.aiim.org/pdfa/ns/field#" >
+ <pdfaExtension:schemas>
+ <rdf:Bag>
+ <rdf:li rdf:parseType="Resource">
+ <pdfaSchema:schema>Example namespace</pdfaSchema:schema>
+ <pdfaSchema:namespaceURI>http://example.com/minim/colours/</pdfaSchema:namespaceURI>
+ <pdfaSchema:prefix>colours</pdfaSchema:prefix>
+ <pdfaSchema:property>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <pdfaProperty:name>Favourite</pdfaProperty:name>
+ <pdfaProperty:valueType>Colour</pdfaProperty:valueType>
+ <pdfaProperty:category>external</pdfaProperty:category>
+ <pdfaProperty:description>The author’s favourite colour</pdfaProperty:description>
+ </rdf:li>
+ </rdf:Seq>
+ </pdfaSchema:property>
+ <pdfaSchema:valueType>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <pdfaType:type>Colour</pdfaType:type>
+ <pdfaType:namespaceURI>http://example.com/minim/colours/</pdfaType:namespaceURI>
+ <pdfaType:prefix>c</pdfaType:prefix>
+ <pdfaType:description>RGB Colour</pdfaType:description>
+ <pdfaType:field>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <pdfaField:name>B</pdfaField:name>
+ <pdfaField:valueType>Integer</pdfaField:valueType>
+ <pdfaField:description>Blue component</pdfaField:description>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <pdfaField:name>G</pdfaField:name>
+ <pdfaField:valueType>Integer</pdfaField:valueType>
+ <pdfaField:description>Green component</pdfaField:description>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <pdfaField:name>R</pdfaField:name>
+ <pdfaField:valueType>Integer</pdfaField:valueType>
+ <pdfaField:description>Red component</pdfaField:description>
+ </rdf:li>
+ </rdf:Seq>
+ </pdfaType:field>
+ </rdf:li>
+ </rdf:Seq>
+ </pdfaSchema:valueType>
+ </rdf:li>
+ </rdf:Bag>
+ </pdfaExtension:schemas>
+</rdf:Description>⟧
+\par\endgroup
+
You probably will not need defining your own value types,
so in most cases you should omit the fifth argument to ⟦add_namespace⟧.
If you do define a new value type, you can specify its prefix if it differs
@@ -182,6 +244,8 @@ All metadata will be written to the PDF file uncompressed.
The ⟦*\metadatamodification⟧ setting controls whether XMP packets will be
marked as read-only (value~0; default) or writeable (value~1).
Writeable XMP packets will be padded with about 2\thinspace kB of whitespace.
+You can prohibit writing metadata altogether
+by specifying ⟦*\writedocumentmetadata = 0⟧.
If the document-level metadata contains values in the ⟦pdfaid⟧ namespace,
metadata extension schemas will be appended to the document-level metadata
diff --git a/macros/luatex/generic/minim-xmp/minim-xmp.lua b/macros/luatex/generic/minim-xmp/minim-xmp.lua
index ba01344ccd..95275aef35 100644
--- a/macros/luatex/generic/minim-xmp/minim-xmp.lua
+++ b/macros/luatex/generic/minim-xmp/minim-xmp.lua
@@ -2,6 +2,7 @@
local M = { }
local alloc = require('minim-alloc')
alloc.remember('minim-xmp')
+local cb = require('minim-callbacks')
local function sorted_pairs(t)
local keys, i = { }, 0
@@ -506,11 +507,13 @@ M.aliases = {
version = { 'xmpMM:VersionID' },
}
-callback.register('finish_pdffile', function()
+cb.register('finish_pdffile', function()
+ if tex.count['writedocumentmetadata'] == 0 then return end
if #XMP > 1 then
alloc.err('Not all metadata has been written out.')
XMP = { [1] = XMP[1] }
- elseif #XMP > 0 then
+ end
+ if #XMP > 0 then
local metadata_obj = M.write_metadata()
local catalog = pdf.getcatalog() or ''
pdf.setcatalog(catalog..string.format('/Metadata %s 0 R', metadata_obj))
diff --git a/macros/luatex/generic/minim-xmp/minim-xmp.pdf b/macros/luatex/generic/minim-xmp/minim-xmp.pdf
index fdf048a857..11c86a9d67 100644
--- a/macros/luatex/generic/minim-xmp/minim-xmp.pdf
+++ b/macros/luatex/generic/minim-xmp/minim-xmp.pdf
Binary files differ
diff --git a/macros/luatex/generic/minim-xmp/minim-xmp.tex b/macros/luatex/generic/minim-xmp/minim-xmp.tex
index 2ec4adc895..2548ad857b 100644
--- a/macros/luatex/generic/minim-xmp/minim-xmp.tex
+++ b/macros/luatex/generic/minim-xmp/minim-xmp.tex
@@ -19,6 +19,10 @@
\newcount \metadataseparator
\metadataseparator = `\;
+% \writedocumentmetadata
+\newcount \writedocumentmetadata
+\writedocumentmetadata = 1
+
% Defined from the lua side:
%
% \getmetadata ns:key
diff --git a/macros/luatex/generic/minim/README b/macros/luatex/generic/minim/README
index 4a16b4e801..31c34b28bf 100644
--- a/macros/luatex/generic/minim/README
+++ b/macros/luatex/generic/minim/README
@@ -1,4 +1,4 @@
-Version: 2021/1.0
+Version: 2022/1.1
SUMMARY
@@ -29,9 +29,33 @@ For the sake of completeness, this manual also includes the documentation of
the packages mentioned above.
+HISTORY
+
+2022/1.1 (3/3/2022)
+
+ Major changes:
+
+ * Updated the allocation mechanism, distinguishing the new_<register>()
+ allocators from the new registernumber() function.
+ * Included a new (pgf-compatible) pdf resource manager.
+
+ Minor changes:
+
+ * Updated the manual to reflect the latest versions of the other minims.
+ * Included a few helper functions moved in from minim-pdf.
+ * Fixed a bug where the primitive callback.register() could not remove
+ list callbacks (the module’s M.register() still cannot).
+ * Added an M.deregister() function for callbacks.
+ * Added a uselanguage callback.
+
+2021/1.0 (1/6/2021)
+
+ This was the original release.
+
+
COPYING
-(c) 2021 Esger Renkema
+(c) 2022 Esger Renkema, Michal Vlasák
These files may be distributed under the terms of the European Union Public
Licence (EUPL) version 1.2 or later. A copy can be obtained at:
diff --git a/macros/luatex/generic/minim/minim-alloc.doc b/macros/luatex/generic/minim/minim-alloc.doc
index fa08988bf4..edf268c81d 100644
--- a/macros/luatex/generic/minim/minim-alloc.doc
+++ b/macros/luatex/generic/minim/minim-alloc.doc
@@ -1,6 +1,8 @@
\input minim-doc.sty
+\chapter Programming macros
+
This chapter describes the programming helper modules on which all the above
modules depend. It mainly concerns register allocation, callback management and
format file inclusion.
@@ -78,15 +80,8 @@ name, the number of that register will be returned. You will need this when you
want to allow your lua code to be included in a format file; it has nothing to
do with the tex-side ⟦\countdef⟧ and the like.
-For the new allocation macros listed above and (as a special case) for
-⟦\newbox⟧,
-after saying ⟦\newwhatsit\name⟧, the call ⟦M.new_whatsit('name')⟧ will return
-the number of ⟦\name⟧. For the other (older) allocation macros, this is not the
-case. After all, because of the ⟦\countdef⟧ etc. included in ⟦\newcount⟧ etc.
-you can already use ⟦tex.count['name']⟧ etc. for retrieving tex-side
-allocations from lua. The exceptions to this are ⟦\newbox⟧, which is why it is
-included with the new macros, and ⟦\newattribute⟧, for which you can use both
-methods.
+If you want to access from lua a register defined in tex, the function
+⟦*M.registernumber('name')⟧ will give you the index of register ⟦\name⟧.
Besides ⟦\newluachunkname\name⟧, you can also use
⟦*\setluachunkname \name {actual name}⟧
@@ -102,21 +97,24 @@ take no parameters.
As noted at the beginning of this chapter, the callback functions are only
available after you say ⟦local C = require('minim-callbacks')⟧.
-This module will override the primitive callback functions with its own
-⟦*C.register⟧, ⟦*C.find⟧ and ⟦*C.list⟧; the original primitive functions can be
-found in the ⟦*C.primitives⟧ table.
-
The simple function of this module is allowing multiple callbacks to co-exist.
Different callbacks call for different implementations, and some callbacks can
-only contain a single function.
-Any callbacks that are already assigned before loading this module will be
-preserved; this includes the ltluatex callback mechanism if it has already been
-installed.
+only contain a single function. Its interface matches the primitive interface,
+with ⟦*C.register(callback, fn)⟧, ⟦*C.find(callback)⟧ and ⟦*C.list()⟧ taking
+the same arguments. In addition to these, ⟦*C.deregister(fn)⟧ will allow you to
+remove a callback. This is necessary when you want to remove a callback from
+a list or from the bottom of a stack. The ⟦fn⟧ variable should point to the
+same object.
-You can create your own callbacks with ⟦*C.new_callback(name, type)⟧. The ⟦type⟧
-should be one of the types mentioned below or ⟦'single'⟧ for callbacks that
-allow only one function. If the ⟦name⟧ is that of a primitive callback, new
-registrations will target your new callback.
+Any callbacks that are already assigned before loading this module will be
+preserved and the primitive callback interface is still available, though
+callbacks registered through the latter will actually use the new functions.
+Ltluatex may be loaded either before or after this module.
+
+You can create your own callbacks with ⟦*C.new_callback(name, type)⟧. The
+⟦type⟧ should be one of the types mentioned below or ⟦'single'⟧ for callbacks
+that allow only one function. If the ⟦name⟧ is that of a primitive callback,
+new registrations will target your new callback.
You can call the new callback with ⟦*C.call_callback(name, ...)⟧, adding any
number of parameters.
@@ -131,7 +129,6 @@ Callbacks of this type are
⟦vpack_filter⟧,
⟦pre_output_filter⟧ and
⟦mlist_to_mlist⟧.
-There is no way of unregistering callbacks of this type.
Similarly, for the ⟦*data⟧ callbacks
⟦process_input_buffer⟧,
@@ -153,6 +150,7 @@ will be called. These are
Register ⟦nil⟧ at the callback to pop a function off the stack.
Finally, for the ⟦*simple⟧ callbacks
+⟦uselanguage⟧,
⟦contribute_filter⟧,
⟦pre_dump⟧,
⟦wrapup_run⟧,
@@ -164,21 +162,50 @@ Finally, for the ⟦*simple⟧ callbacks
⟦process_rule⟧.
all registered functions are called in order with the same arguments.
-The new ⟦*mlist_to_mlist⟧ callback is called before ⟦mlist_to_hlist⟧ and should
-not convert noads to nodes.
+Two callbacks are new:
+the new ⟦*mlist_to_mlist⟧ callback is called before ⟦mlist_to_hlist⟧ and should
+not convert noads to nodes, while the ⟦*uselanguage⟧ callback is called from
+⟦\uselanguage⟧.
If you create a new callback with a number for a name, that callback will
replace the ⟦*process_rule⟧ callback when its number matches the index property
of the rule.
+\section Programming helpers
+
+Optional keyword arguments to tex macros can be defined with help of
+⟦*M.options_scanner()⟧. An example from the definition of minim-pdf’s
+⟦\outline⟧:
+
+⟦ local s = M.options_scanner()
+ :keyword('open', 'closed')
+ :string('dest')
+ :scan()
+ s.title = token.scan_string()
+ M.add_bookmark(s)⟧
+
+Here, the ⟦keyword⟧ function adds two opposite keywords: if one is present, its
+value will be set to ⟦true⟧ and the other’s to ⟦false⟧ (the second keyword is
+optional). The ⟦string⟧ function stores the result of ⟦token.scan_string⟧ under
+its key. Of the same form you have ⟦int⟧, ⟦glue⟧, ⟦dimen⟧, ⟦argument⟧, ⟦word⟧
+and ⟦list⟧. All these take an optional second argument: if ⟦true⟧ then the
+keyword can be repeated and its values will be stored as a list.
+
+The ⟦scan⟧ function, finally, scans all keywords, which may appear in any
+order. You can give it a table with default values. In the example given above,
+the argument ⟦s⟧ to ⟦M.add_bookmark⟧ will consist of a table with at most the
+following entries: ⟦open⟧, ⟦closed⟧, ⟦dest⟧ and ⟦title⟧, though entries whose
+keywords do not occur will not be present.
+
+This function is particularly useful when used together with
+⟦*M.luadef('csname', function, ...)⟧, which defines primitive-like tex macros
+from lua. There, ⟦function⟧ can be any function (it will be assigned a lua
+function register) and at the place of the dots you may append ⟦'protected'⟧
+and/or ⟦'global'⟧.
-\section Miscellaneous functions
-This section describes functions and macros that are internal to this package,
-but might be of general usefulness.
+\section Miscellaneous functions
-For instance, you might find the function ⟦*M.table_to_text(table)⟧ useful when
-debugging lua code.
The small functions
⟦*M.msg(...)⟧, ⟦*M.log(...)⟧ and ⟦*M.err(...)⟧
include a call to ⟦M.string.format⟧;
@@ -186,14 +213,24 @@ additionally,
⟦*M.amsg(...)⟧ and ⟦*M.alog(...)⟧
do not start a new line.
-Very useful is ⟦*M.luadef('csname', function, ...)⟧ for defining primitive-like
-tex macros from lua: ⟦function⟧ can be any function (it will be assigned a lua
-function register) and at the place of the dots you may append ⟦'protected'⟧
-and/or ⟦'global'⟧.
-
Both ⟦*M.unset⟧ and ⟦*\unset⟧ contain the value ⟦-0x7FFFFFFF⟧ that can be used
for clearing attributes.
+When writing data to pdf literals, ⟦*M.pdf_string(...)⟧,
+⟦*M.pdf_name(...)⟧ and ⟦*M.pdf_date(...)⟧ may be useful: they produce strings
+that can be written to the pdf directly. Surrounding ⟦<>⟧ or ⟦()⟧ characters or
+a leading ⟦/⟧ will be included in the return value. The ⟦M.pdf_date⟧ function
+expects a value of the form ⟦yyyy[-mm[-dd]]⟧ and returns a date of the form
+⟦(D:yyyymmdd)⟧.
+The function ⟦M.pdf_string⟧ is also available to tex through the macro
+⟦*\pdfstring⟧.
+
+Finally the function ⟦*M.table_to_text(table)⟧ may be useful when debugging lua
+code: it dumps a table as a (lua-readable) string. Cyclic references will spin
+in into an eternal loop, however.
+
+\section Miscellaneous helper macros
+
On the tex side, ⟦*\voidbox⟧, ⟦*\ignore⟧, ⟦*\spacechar⟧, ⟦*\unbrace⟧,
⟦*\firstoftwo⟧ and ⟦*\secondoftwo⟧ should be self-explanatory and
uncontroversial additions. For looking ahead, you can use
diff --git a/macros/luatex/generic/minim/minim-alloc.lua b/macros/luatex/generic/minim/minim-alloc.lua
index c99ca2c73d..8f6a69ed0d 100644
--- a/macros/luatex/generic/minim/minim-alloc.lua
+++ b/macros/luatex/generic/minim/minim-alloc.lua
@@ -27,6 +27,131 @@ function M.err (...)
tex.error(string.format(...))
end
+-- 1 pdf helpers
+
+local function insert_formatted(t, ...)
+ table.insert(t, string.format(...))
+end
+
+local function hexify(c)
+ return string.format('#%02x', c:byte())
+end
+function M.pdf_name(n)
+ return '/'..n
+ :gsub('[][(){}<>#%%/\\]', hexify)
+ :gsub('%G', hexify)
+end
+
+-- re-encode to utf-16
+local function pdf_hex_string(text)
+ local str = { [1] = '<feff' }
+ for i in text:utfvalues() do
+ if i <= 0xffff then
+ insert_formatted(str, '%04x', i)
+ else
+ i = i - 0x10000
+ m = math.floor(i/0x400) + 0xd800
+ n = ( i % 0x400 ) + 0xdc00
+ insert_formatted(str, '%04x%04x', m, n)
+ end
+ end
+ table.insert(str, '>')
+ return table.concat(str,'')
+end
+local function octify(c)
+ return string.format('\\%03o', c:byte())
+end
+function M.pdf_string(text)
+ -- do note that \ddd is decimal in lua, octal in pdf
+ if text:match('[^%g\009\010\13 ]') then
+ return pdf_hex_string(text)
+ else
+ return string.format('(%s)', text
+ :gsub('[()\\]','\\%0')
+ :gsub('%c', octify))
+ end
+end
+
+-- try and produce a date of the format (D:YYYYMMDD)
+function M.pdf_date(text)
+ local y, m, d = string.match(text, '^([12][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)$')
+ if not y then d, m, y = string.match(text, '^([0-9][0-9]?)-([0-9][0-9]?)-([12][0-9][0-9][0-9])$') end
+ if y then
+ return string.format('(D:%4d%02d%02d)', y, m, d)
+ else
+ return string.format('(D:%s)', text)
+ end
+end
+
+-- 1 scanning helpers
+
+local function make_scanner(fn)
+ return function(this, name, multiple)
+ this.scanners[name] = multiple and function()
+ this.res[name] = this.res[name] or { }
+ table.insert(this.res[name], fn())
+ end or function()
+ this.scanners[name] = nil
+ this.res[name] = fn()
+ end
+ return this
+ end
+end
+
+function M.options_scanner()
+ return { scanners = { }, res = { },
+ int = make_scanner(token.scan_int),
+ glue = make_scanner(token.scan_glue),
+ dimen = make_scanner(token.scan_dimen),
+ string = make_scanner(token.scan_string),
+ argument = make_scanner(token.scan_argument),
+ word = make_scanner(token.scan_word),
+ list = make_scanner(token.scan_list),
+ keyword = function(this, name, opposite)
+ this.scanners[name] = function()
+ this.res[name] = true
+ if opposite then this.res[opposite] = false end
+ end
+ if opposite then
+ this.scanners[opposite] = function()
+ this.res[name] = false
+ this.res[opposite] = true
+ end
+ end
+ return this
+ end,
+ table = function(this, name)
+ this.scanners[name] = function()
+ this.res[name] = this.res[name] or { }
+ this.res[name][token.scan_string()] = token.scan_string()
+ end
+ return this
+ end,
+ subtable = function(this, name)
+ this.scanners[name] = function()
+ this.res[name] = this.res[name] or { }
+ local sub = token.scan_string();
+ this.res[name][sub] = this.res[name][sub] or { }
+ this.res[name][sub][token.scan_string()] = token.scan_string()
+ end
+ return this
+ end,
+ scan = function(this, defaults)
+ this.res = defaults or this.res
+ repeat
+ local matched = false
+ for name, scanner in pairs(this.scanners) do
+ if token.scan_keyword(name) then
+ matched = true
+ scanner()
+ end
+ end
+ until not matched
+ return this.res
+ end
+ }
+end
+
-- 1 saving modules and tables
local tables = package.loaded['minim-saved-tables']
@@ -70,7 +195,7 @@ function M.table_to_text (tbl)
return '{ ' .. table.concat (r,', ') .. ' }'
end
-require('minim-callbacks')
+local cb = require('minim-callbacks')
M.remember('minim-callbacks')
M.remember('minim-alloc')
@@ -79,11 +204,23 @@ M.remember('minim-alloc')
-- like \unset
M.unset = -0x7FFFFFFF
-local allocations = M.saved_table ('minim:allocations')
+-- works for both \chardef and the likes of \countdef
+function M.registernumber(csname)
+ if token.is_defined(csname) then
+ return token.create(csname).index
+ else
+ return -- would return 0 otherwise
+ end
+end
+
+-- we need remember lua-made allocations in the format file, since otherwise,
+-- a different register will be reserved when the lua code is seen again in the
+-- actual run.
+local allocations = M.saved_table('minim lua-side allocations')
-local function make_alloc_new (fname, globcount)
+local function make_alloc_new(fname, globcount)
allocations[fname] = allocations[fname] or { }
- M['new_'..fname] = function (id)
+ M['new_'..fname] = function(id)
local nr
if id and allocations[fname][id] then
nr = allocations[fname][id]
@@ -108,7 +245,7 @@ make_alloc_new ('userrule' , 'e@alloc@rule@count' )
-- We need different allocation functions for the older registers, because
-- etex’s global allocation macros are off-by-one w.r.t. all other.
--
-local function make_alloc_old (fname, globcount, loccount)
+local function make_alloc_old(fname, globcount)
allocations[fname] = allocations[fname] or { }
M['new_'..fname] = function (id)
local nr
@@ -122,21 +259,16 @@ local function make_alloc_old (fname, globcount, loccount)
end
return nr
end
- M['local_'..fname] = function ()
- local nr = tex.count[loccount] - 1
- tex.setcount(loccount, nr)
- return nr
- end
end
-- existing allocation counters
-make_alloc_old ('count', 260, 270 )
-make_alloc_old ('dimen', 261, 271 )
-make_alloc_old ('skip', 262, 272 )
-make_alloc_old ('muskip', 263, 273 )
-make_alloc_old ('box', 264, 274 )
-make_alloc_old ('toks', 265, 275 )
-make_alloc_old ('marks', 266, 276 )
+make_alloc_old ('count', 260 )
+make_alloc_old ('dimen', 261 )
+make_alloc_old ('skip', 262 )
+make_alloc_old ('muskip', 263 )
+make_alloc_old ('box', 264 )
+make_alloc_old ('toks', 265 )
+make_alloc_old ('marks', 266 )
function M.luadef (csname, fn, ...)
local nr = M.new_function(csname)
@@ -144,8 +276,19 @@ function M.luadef (csname, fn, ...)
token.set_lua(csname, nr, ...)
end
-M.luadef ('minim:rememberalloc', function()
- allocations[token.scan_string()][token.scan_string()] = tex.count['allocationnumber']
+-- the current file
+M.luadef('minim:currentfile', function()
+ tex.sprint((status.filename:gsub('^.*/', '')))
+end)
+
+-- make pdf_string() available as \pdfstring{...}
+M.luadef('pdfstring', function() M.pdf_string(token.scan_string()) end)
+
+-- uselanguage hook callback
+cb.new_callback('uselanguage', 'simple')
+M.luadef('minim:uselanguagecallback', function()
+ local langname = token.scan_string()
+ cb.call_callback('uselanguage', langname)
end)
-- 1 dumping information to the format file
@@ -188,7 +331,7 @@ local function dump_saved_tables()
lua.bytecode[saved_tables_bytecode] = load(saved_tables)
end
-callback.register ('pre_dump', dump_saved_tables)
+cb.register ('pre_dump', dump_saved_tables)
--
diff --git a/macros/luatex/generic/minim/minim-alloc.tex b/macros/luatex/generic/minim/minim-alloc.tex
index 66f08c9045..8752c2e336 100644
--- a/macros/luatex/generic/minim/minim-alloc.tex
+++ b/macros/luatex/generic/minim/minim-alloc.tex
@@ -62,58 +62,48 @@
% 1 ltluatex compatibility
+% \ProvidesFile identifies most problematic files
+\ifdefined \ProvidesFile
+ \let\minim:providesfile=\ProvidesFile\else
+ \def\minim:providesfile#1#2[#3]{%
+ \wlog{Loading file #1 version #3.}}\fi
+\def\ProvidesFile#1{\begincsname minim:intercept:#1\endcsname
+ \minim:providesfile{#1}}
+
+
% repair ltluatex, which, without apparent reason, resets all allocation
% counters, even if they already exist
-\def\minim:ltltx:file{ltluatex.tex}
-\let\ProvidesFile:saved=\ProvidesFile
-\def\ProvidesFile#1#2[#3]{%
- \ifdefined\ProvidesFile:saved \ProvidesFile:saved{#1}#2[#3]\fi
- \def\minim:ltltx:arg{#1}%
- \ifx\minim:ltltx:file\minim:ltltx:arg
- \let\ProvidesFile=\ProvidesFile:saved
- \let\endinput:saved=\endinput
- \protected\edef\endinput{%
- \minim:ltltx:fix{e@alloc@attribute@count}%
- \minim:ltltx:fix{e@alloc@whatsit@count}%
- \minim:ltltx:fix{e@alloc@bytecode@count}%
- \minim:ltltx:fix{e@alloc@luafunction@count}%
- \minim:ltltx:fix{e@alloc@luachunk@count}%
- \minim:ltltx:fix{e@alloc@ccodetable@count}%
- % also patch in remembering allocations to lua
- \alloc:patch \noexpand\attribute
- \alloc:patch \noexpand\whatsit
- \alloc:patch \noexpand\luabytecode
- \alloc:patch \noexpand\luachunkname
- \alloc:patch \noexpand\catcodetable
- \alloc:patch \noexpand\userrule
- % restore register allocation functions
- \directlua{ local C = require('minim-callbacks')
- callback.register, callback.find, callback.list
- = C.register, C.find, C.list }%
- \let\noexpand\endinput=\noexpand\endinput:saved
- \noexpand\endinput}\fi}
+\expandafter\def\csname minim:intercept:ltluatex.tex\endcsname
+ {\wlog{minim: applying ltluatex patches.}%
+ \edef\endinput{\let\noexpand\endinput=\noexpand\minim:endinput
+ \minim:ltltx:fix{e@alloc@attribute@count}%
+ \minim:ltltx:fix{e@alloc@whatsit@count}%
+ \minim:ltltx:fix{e@alloc@bytecode@count}%
+ \minim:ltltx:fix{e@alloc@luafunction@count}%
+ \minim:ltltx:fix{e@alloc@luachunk@count}%
+ \minim:ltltx:fix{e@alloc@ccodetable@count}%
+ % restore register allocation functions
+ \noexpand\directlua{ callback.register =
+ require('minim-callbacks').primitiveregister }%
+ \noexpand\endinput}}
+\let\minim:endinput = \endinput
\def\minim:ltltx:fix#1{%
\ifnum0<\the\csname#1\endcsname
\wlog{Restoring \csname#1\endcsname to previous value \the\csname#1\endcsname}%
\expandafter\noexpand\csname#1\endcsname =\the\csname#1\endcsname\relax\fi}
-\protected\def\alloc:patch#1{%
- \expandafter\expandafter\expandafter\let
- \expandafter\expandafter\csname\csstring#1:ltluatex:new\endcsname
- \csname new\csstring#1\endcsname
- \expandafter\edef\csname new\csstring#1\endcsname##1{%
- \noexpand\minim:rememberalloc{\csstring#1}{\noexpand\csstring##1}%
- \expandafter\noexpand\csname\csstring#1:ltluatex:new\endcsname{##1}}}
% 1 allocation
% use global allocation (see etex.src)
-\let\newcount = \globcount
-\let\newdimen = \globdimen
-\let\newskip = \globskip
-\let\newmuskip = \globmuskip
-\let\newbox = \globbox
-\let\newtoks = \globtoks
-\let\newmarks = \globmarks
+\ifdefined \globcount
+ \let\newcount = \globcount
+ \let\newdimen = \globdimen
+ \let\newskip = \globskip
+ \let\newmuskip = \globmuskip
+ \let\newbox = \globbox
+ \let\newtoks = \globtoks
+ \let\newmarks = \globmarks
+\fi
% new allocation macros
@@ -121,8 +111,7 @@
\unless\ifcsname#3\endcsname
\expandafter\newcount \csname#3\endcsname
\csname#3\endcsname 0\fi
- \ifcsname new\csstring#1\endcsname
- \alloc:patch#1\else
+ \unless\ifcsname new\csstring#1\endcsname
\expandafter\edef\csname new\csstring#1\endcsname{%
\noexpand\minim:alloc\noexpand#1\noexpand#2%
\expandafter\noexpand\csname#3\endcsname}\fi}
@@ -131,9 +120,7 @@
\global\advance#31%
\allocationnumber#3%
\global#2#4\allocationnumber
- \wlog{\string#4=\string#1\the\allocationnumber}%
- % minim:rememberalloc will be defined from lua side
- \minim:rememberalloc{\csstring#1}{\csstring#4}}
+ \wlog{\string#4=\string#1\the\allocationnumber}}
% all names and counters below are identical to those from ltluatex
% note: we cannot use \newluafunction, or ltluatex will not load
@@ -147,7 +134,10 @@
% initialise new catcode tables
\def\catcode:chardef#1#2{\chardef#1#2\initcatcodetable#2}
-\csname e@alloc@ccodetable@count\endcsname = 4 % because ltluatex allocates 4...
+% ltluatex initialises the catcode tables 1–4, so we make sure not to claim
+% those ourselves:
+\ifnum\csname e@alloc@ccodetable@count\endcsname = 0
+ \csname e@alloc@ccodetable@count\endcsname = 4 \fi
% set initial chunk name value
\def\chardef:chunk#1#2{\chardef#1#2\directlua{lua.name[\the#2]='\csstring#1'}}
@@ -156,17 +146,22 @@
\protected\def\setluachunkname#1#2{\newluachunkname#1%
\directlua{lua.name[\the#1]='\luaescapestring{#2}'}}
-% patch in remembering box allocations
-\def\minim:boxchardef#1{%
- \minim:rememberalloc{box}{\csstring#1}%
- \mathchardef#1}
-\edef\newbox{%
- \expandafter\noexpand\csname et@xglob\endcsname
- 4\box\noexpand\minim:boxchardef}
-
% undefine our helper functions
\let\alloc:makenew=\undefined
+% patch in our callback to \uselanguage
+% \minim:uselanguagecallback is defined from Lua
+\ifcsname uselanguage@hook\endcsname
+ \expandafter\let
+ \expandafter\minim:uselanguagehook
+ \lastnamedcs \fi
+\expandafter\edef\csname uselanguage@hook\endcsname#1{%
+ % our uselanguage callback
+ \noexpand\minim:uselanguagecallback{#1}%
+ % previous definitions
+ \ifdefined\minim:uselanguagehook
+ \noexpand\minim:uselanguagehook{#1}\fi}
+
% 1 format file compatibility
% all other work is done at the lua end
diff --git a/macros/luatex/generic/minim/minim-callbacks.lua b/macros/luatex/generic/minim/minim-callbacks.lua
index 3ac075dc01..af3db59e24 100644
--- a/macros/luatex/generic/minim/minim-callbacks.lua
+++ b/macros/luatex/generic/minim/minim-callbacks.lua
@@ -1,41 +1,51 @@
local M = {}
-local function log(msg, ...)
+local function log(...) end
+local function alog(...) end
+local function do_log(msg, ...)
texio.write_nl('log', string.format(msg, ...))
end
-- 1 capturing the callback mechanism
--- if ltluatex is loaded, we must get callback.register back
-if luatexbase ~= nil then
- local luatex_base = luatexbase
- luatexbase.uninstall ()
- luatexbase = luatex_base
-end
-
local primitives = { }
M.primitives = primitives
primitives.register = callback.register
primitives.find = callback.find
primitives.list = callback.list
-local own_callbacks = {}
-local callback_lists = {}
+-- use the ltluatex functions if needed
+local primitive_register = primitives.register
+if luatexbase then
+ primitive_register = function(cb, f)
+ if f == nil then
+ luatexbase.remove_from_callback(cb, 'minim callback')
+ elseif f == false then
+ luatexbase.disable_callback(cb)
+ else
+ luatexbase.add_to_callback(cb, f, 'minim callback')
+ end
+ end
+end
+
+
+local own_callbacks = {}
+local callback_lists = {}
local callback_stacks = {}
-- 1 finding callbacks
-function M.find (name)
- local f = own_callbacks[name]
+function M.find(cb)
+ local f = own_callbacks[cb]
if f == nil then
- return primitives.find(name)
+ return primitives.find(cb)
else
return f
end
end
-function M.list (name)
+function M.list()
local t = {}
for n,f in pairs(callback_lists) do
if f then
@@ -44,14 +54,16 @@ function M.list (name)
t[n] = false
end
end
- for n,f in pairs(own_callbacks) do
+ -- no stack callbacks, since the active callback is in one of the two below
+ for n,f in pairs(primitives.list()) do
if f then
t[n] = t[n] or true
else
t[n] = t[n] or false
end
end
- for n,f in pairs(primitives.list()) do
+ -- this might obscure primitive callbacks (this is intended)
+ for n,f in pairs(own_callbacks) do
if f then
t[n] = t[n] or true
else
@@ -63,42 +75,73 @@ end
-- 1 registering callbacks
-local function register_simple (cb,f)
+local function register_simple(cb,f)
-- prefer user-defined callbacks over built-in
- local x = own_callbacks[cb]
- if x == nil then
- return primitives.register (cb, f)
+ local own = own_callbacks[cb]
+ log ('callback %s: %s (%s)', f == nil and 'removed' or f and 'set' or 'disabled',
+ cb, own == nil and 'primitive' or 'user-defined')
+ if own == nil then -- may be set to ‘false’
+ return primitive_register(cb, f)
else
- -- default to false because nil would delete the callback itself
- own_callbacks[cb] = f or false
+ own_callbacks[cb] = f or false -- ‘nil’ would delete the callback
return -1
end
end
-- will be redefined later
-local function announce_callback(cb, f) end
-function M.register (cb, f)
- announce_callback(cb, f)
+function M.register(cb, f)
local list = callback_lists[cb]
+ if list then
+ if f == nil then
+ return tex.error('Use ‘deregister’ for removing list callbacks')
+ else
+ list[#list+1] = f
+ log('callback set: %s (#%d on list)', cb, #list)
+ return -2
+ end
+ end
local stack = callback_stacks[cb]
if stack then
if f == nil then -- pop
local p = stack[#stack]
stack[#stack] = nil
- return register_simple (cb,p)
+ return register_simple(cb,p)
else -- push
- stack[#stack+1] = M.find (cb)
- return register_simple (cb,f)
+ stack[#stack+1] = M.find(cb)
+ return register_simple(cb,f)
end
- elseif list ~= nil then
- list[#list+1] = f
- return -2
- else
- return register_simple (cb,f)
end
+ return register_simple(cb, f)
end
+function M.deregister(cb, f)
+ local list = callback_lists[cb]
+ if list then
+ for i,g in ipairs(list) do
+ if f == g then
+ log('callback removed: %s (#%d on list)', cb, i)
+ table.remove(list, i)
+ return true, -2
+ end
+ end
+ return false
+ end
+ local stack = callback_stacks[cb]
+ if stack then
+ for i,g in ipairs(stack) do
+ if f == g then
+ log('callback removed: %s (#%d on stack)', cb, i)
+ table.remove(stack, i)
+ return true, -3
+ end
+ end
+ -- no return: fall through to next
+ end
+ if f == M.find(cb) then
+ return true, register_simple(cb, nil)
+ end
+end
-- 1 lists of callback functions
@@ -169,22 +212,40 @@ function M.call_callback (name, ...)
end
end
+-- 1 replace the primitive registering
+
+-- TODO: preserve return values
+local primitively_registered = { }
+function M.primitiveregister(cb, f)
+ local rv = false
+ if f == nil then
+ f = primitively_registered[cb]
+ if f == nil then
+ rv = M.register(cb)
+ else
+ _, rv = M.deregister(cb, f)
+ end
+ else
+ rv = M.register(cb, f)
+ end
+ alog(' through primitive interface')
+ primitively_registered[cb] = f
+ return rv
+end
+
+
-- 1 initialisation
-- save all registered callbacks
-local saved = {}
-for n,s in pairs(primitives.list()) do
- if s then
- log('save callback: %s', n)
- saved[n] = callback.find(n)
+if not luatexbase then
+ for n,s in pairs(primitives.list()) do
+ if s then
+ do_log('save callback: %s', n)
+ primitively_registered[n] = primitives.find(n)
+ end
end
end
--- replace the primitive registering
-callback.register = M.register
-callback.find = M.find
-callback.list = M.list
-
-- string processing callbacks
register_list ('process_input_buffer', call_list_data)
register_list ('process_output_buffer', call_list_data)
@@ -202,7 +263,7 @@ register_list ('pre_output_filter', call_list_node)
M.new_callback ('mlist_to_mlist', 'node')
M.new_callback ('mlist_to_hlist', 'stack')
M.register ('mlist_to_hlist', node.mlist_to_hlist )
-primitives.register ('mlist_to_hlist', function (head, ...)
+primitive_register ('mlist_to_hlist', function (head, ...)
local newhead = M.call_callback ('mlist_to_mlist', head, ...)
if newhead ~= true then
head = newhead or head
@@ -232,7 +293,7 @@ stack_callback ('build_page_insert')
-- process_rule
M.new_callback ('process_rule', 'simple')
-primitives.register ('process_rule', function (rule, ...)
+primitive_register ('process_rule', function (rule, ...)
local p = own_callbacks[rule.index]
if p then
p (rule, ...)
@@ -242,23 +303,23 @@ primitives.register ('process_rule', function (rule, ...)
end)
-- restore all registered callbacks
-for n,f in pairs(saved) do
- log('restore callback: %s', n)
- M.register (n,f)
+for n,f in pairs(primitively_registered) do
+ do_log('restore callback: %s', n)
+ M.primitiveregister (n,f)
end
saved = nil
+--
-local function announce_callback(cb, f)
- if f then
- log('callback added: %s', cb)
- else
- log('callback removed: %s', cb)
- end
-end
-
+-- replace primitive callbacks
+callback.find = M.find
+callback.list = M.list
+callback.register = M.primitiveregister
---
+log = do_log
+local function alog(msg, ...)
+ texio.write('log', string.format(msg, ...))
+end
return M
diff --git a/macros/luatex/generic/minim/minim-doc.sty b/macros/luatex/generic/minim/minim-doc.sty
index 1d3c2d4cea..93e770153b 100644
--- a/macros/luatex/generic/minim/minim-doc.sty
+++ b/macros/luatex/generic/minim/minim-doc.sty
@@ -6,6 +6,7 @@
\expandafter\endinput\fi
\input minim
+%\decompressedpdf
\pdfalevel 3a
\overfullrule = 0pt
@@ -15,7 +16,6 @@
\pdfvariable horigin 0pt
\pdfvariable vorigin 0pt
\frenchspacing
-\raggedbottom
\uselanguage{ukenglish}
\hyphenation {
@@ -38,27 +38,27 @@
% 1 fonts
\input luaotfload.sty
-\font\tenrm {Latin Modern Roman:script=latn;protrusion=default} at 10pt
-\font\tenbf {Latin Modern Roman/B:script=latn} at 10pt
-\font\tenit {Latin Modern Roman/I:script=latn} at 10pt
-\font\tentt {Latin Modern Mono:script=latn;+smcp} at 10pt
-\font\title {Latin Modern Roman/B:script=latn} at 12pt
-\font\Title {Latin Modern Roman/B:script=latn} at 16pt
-
-\font\tenmath {Latin Modern Math:mode=base;script=math;ssty=0} at 10pt
-\font\tenmaths {Latin Modern Math:mode=base;script=math;ssty=1} at 7pt
-\font\tenmathss {Latin Modern Math:mode=base;script=math;ssty=2} at 5pt
-\textfont 0 = \tenmath
-\scriptfont 0 = \tenmaths
-\scriptscriptfont 0 = \tenmathss
-
-\font\altmath {Tex Gyre Pagella Math:mode=base;script=math;ssty=0} at 10pt
-\font\altmaths {Tex Gyre Pagella Math:mode=base;script=math;ssty=1} at 7pt
-\font\altmathss {Tex Gyre Pagella Math:mode=base;script=math;ssty=2} at 5pt
+\font\tenrm {Latin Modern Roman:script=latn;protrusion=default;} at 10pt
+\font\tenbf {Latin Modern Roman/B:script=latn;} at 10pt
+\font\tenit {Latin Modern Roman/I:script=latn;} at 10pt
+\font\tentt {Latin Modern Mono:script=latn;+smcp;} at 10pt
+\font\title {Latin Modern Roman/B:script=latn;} at 12pt
+\font\Title {Latin Modern Roman/B:script=latn;} at 16pt
+
+\font\altmath {Tex Gyre Pagella Math:mode=base;script=math;ssty=0;} at 10pt
+\font\altmaths {Tex Gyre Pagella Math:mode=base;script=math;ssty=1;} at 7pt
+\font\altmathss {Tex Gyre Pagella Math:mode=base;script=math;ssty=2;} at 5pt
\textfont 1 = \altmath
\scriptfont 1 = \altmaths
\scriptscriptfont 1 = \altmathss
+\font\tenmath {Latin Modern Math:mode=base;script=math;ssty=0;} at 10pt
+\font\tenmaths {Latin Modern Math:mode=base;script=math;ssty=1;} at 7pt
+\font\tenmathss {Latin Modern Math:mode=base;script=math;ssty=2;} at 5pt
+\textfont 0 = \tenmath
+\scriptfont 0 = \tenmaths
+\scriptscriptfont 0 = \tenmathss
+
\expandglyphsinfont \tenrm 40 25 5
\protrudechars=2 \adjustspacing=2
\tenrm
@@ -67,21 +67,31 @@
% 1 code typesetting
-\def\red#1{\quitvmode\pdfextension
- literal{0.75 0 0 rg}{#1}\pdfextension literal{0 g}}
+\chardef\thecolourstack = \pdffeedback colorstackinit page {0 g 0 G}
+\def\pushcolour#1{\pdfextension colorstack \thecolourstack push {#1}}
+\def\popcolour{\pdfextension colorstack \thecolourstack pop\relax}
+\def\red#1{\pushcolour{0.75 0 0 rg}{#1}\popcolour}
\def\emph#1{{\tenit #1\/}}
+\newattributeclass Code
+ attr Layout Placement /Block
+ attr CSS-2.00 display (block)
+
\def\breakablespace{\penalty0~}
\catcode`\⟦=\active
\def⟦{\quitvmode\begingroup\catcode`\∥=0\relax
\markparagraphsfalse
\def\do##1{\catcode`##1=12}\dospecials
- \catcode`\ =\active
- \letcharcode`\ =\breakablespace\obeylines
- \parskip0pt\tentt
+ \catcode`\%=\active \letcharcode`\%=\verbatimcomment
+ \catcode`\ =\active \letcharcode`\ =\breakablespace
+ \def\par{\ifhmode\tentt\endgraf\else\vskip\baselineskip\fi}%
+ \everypar{\stopelement{Code}%
+ \startelement class Code {Code}}%
+ \parskip0pt\tentt \obeylines
\nextif*{\verbatim\ignore}{\expandafter\ignore\verbatim}}
\def\verbatim#1⟧{\red{\markelement{Code}{#1}}\endgroup}
+\def\verbatimcomment{\tenit\Uchar`\%}
% 1 the minim symbol
@@ -109,7 +119,6 @@ endfig;}
\setbox\notehead=\hbox{\markartifact{Layout}{\box\notehead}}
\closemetapostinstance \mnmMP
-%
% 1 document structure
% page artifacts
@@ -134,9 +143,9 @@ endfig;}
\ensurestopelement{Section}%
\startelement{Chapter}%
\outline open {#1}%
- \nextpartag{H}\red{\Title#1\hfill\copy\notehead}%
\addtotoc{\chapter{#1}{\lastdestinationname}}%
- \bigskip}
+ \nextpartag{H}\quitvmode
+ \red{\Title#1\hfill\copy\notehead}\bigskip\nobreak}
% \section Title \par
\addstructuretype Sect Section
@@ -144,8 +153,8 @@ endfig;}
\bigskip\penalty-50\relax
\startelement{Section}%
\outline closed {#1}%
- \nextpartag{H}\quitvmode
\addtotoc{\section{#1}{\lastdestinationname}}%
+ \nextpartag{H}\quitvmode
\red{\title#1}%
\par\nobreak}
@@ -200,7 +209,6 @@ obtained at
{\hyperlink url {https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12}%
https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\endlink}$$\startformulatagging}
-
% for identifying which file we are typesetting
\edef\thejobname{\expandafter\scantextokens\expandafter{\jobname}}
\newif \ifchapter
diff --git a/macros/luatex/generic/minim/minim-hooks.lua b/macros/luatex/generic/minim/minim-hooks.lua
index c399547c9e..f11ce27875 100644
--- a/macros/luatex/generic/minim/minim-hooks.lua
+++ b/macros/luatex/generic/minim/minim-hooks.lua
@@ -1,13 +1,11 @@
--- Adds a callback just before a box is shipped out, opposite to
--- 'finish_pdfpage'.
-
-local alloc = require('minim-alloc')
local cb = require ('minim-callbacks')
-alloc.remember('minim-hooks')
local M = { }
+-- Add a callback just before a box is shipped out, opposite to
+-- 'finish_pdfpage'.
+
cb.new_callback('pre_shipout', 'simple')
M.primitive_shipout = tex.shipout
@@ -16,15 +14,5 @@ function tex.shipout(nr)
M.primitive_shipout(nr)
end
-local shipout_box = alloc.new_box('minim:shipout:box')
-
-alloc.luadef('minim:shipout', function()
- tex.box[shipout_box] = token.scan_list()
- cb.call_callback('pre_shipout', shipout_box)
- -- we must let tex do the rest, because some other package may have
- -- redefined \shipout before us.
- tex.sprint(token.create('minim:shipout:do'))
-end, 'protected')
-
return M
diff --git a/macros/luatex/generic/minim/minim-hooks.tex b/macros/luatex/generic/minim/minim-hooks.tex
index b3b8092654..deef66fc9a 100644
--- a/macros/luatex/generic/minim/minim-hooks.tex
+++ b/macros/luatex/generic/minim/minim-hooks.tex
@@ -21,13 +21,17 @@
\chardef\minimhooksloaded = \catcode`\:
\catcode`\: = 11
-\input minim-alloc
+\directlua{ require('minim-hooks') }
% 1 the pre_shipout callback
\newbox\minim:shipout:box \let\minim:shipout:orig = \shipout
\def\minim:shipout:do{\minim:shipout:orig\box\minim:shipout:box}
-\directlua{require('minim-hooks')} \let\shipout\minim:shipout
+\protected\def\minim:shipout:new{\directlua{
+ tex.box[\the\minim:shipout:box] = token.scan_list()
+ require('minim-callbacks').call_callback('pre_shipout', \the\minim:shipout:box)
+ token.put_next(token.create('minim:shipout:do'))}}
+\let\shipout = \minim:shipout:new
% 1 invisibly adding to \everypar
diff --git a/macros/luatex/generic/minim/minim-lmodern.tex b/macros/luatex/generic/minim/minim-lmodern.tex
index 61bc0054e9..e420dd2a1c 100644
--- a/macros/luatex/generic/minim/minim-lmodern.tex
+++ b/macros/luatex/generic/minim/minim-lmodern.tex
@@ -11,15 +11,15 @@
\def\preloadfont#1#2#3{\def#1{\initfontloader\font#1{#2}at#3#1}}
\def\initfontloader{\input luaotfload.sty \let\initfontloader=\relax}
-\preloadfont \tenrm {Latin Modern Roman:script=latn;+liga;+kern;+dlig}{10pt}
-\preloadfont \tenit {Latin Modern Roman/I:script=latn;+liga;+kern;+dlig}{10pt}
-\preloadfont \tenbf {Latin Modern Roman/B:script=latn;+liga;+kern;+dlig}{10pt}
-\preloadfont \tensl {Latin Modern Roman Slanted:script=latn;+liga;+kern;+dlig}{10pt}
-\preloadfont \tentt {Latin Modern Mono:script=latn;+liga;+kern;+dlig}{10pt}
-
-\preloadfont\tenmath {Latin Modern Math:mode=base;script=math;ssty=0}{10pt}
-\preloadfont\tenmaths {Latin Modern Math:mode=base;script=math;ssty=1}{7pt}
-\preloadfont\tenmathss {Latin Modern Math:mode=base;script=math;ssty=2}{5pt}
+\preloadfont \tenrm {Latin Modern Roman:script=latn;+liga;+kern;+dlig;}{10pt}
+\preloadfont \tenit {Latin Modern Roman/I:script=latn;+liga;+kern;+dlig;}{10pt}
+\preloadfont \tenbf {Latin Modern Roman/B:script=latn;+liga;+kern;+dlig;}{10pt}
+\preloadfont \tensl {Latin Modern Roman Slanted:script=latn;+liga;+kern;+dlig;}{10pt}
+\preloadfont \tentt {Latin Modern Mono:script=latn;+liga;+kern;+dlig;}{10pt}
+
+\preloadfont\tenmath {Latin Modern Math:mode=base;script=math;ssty=0;}{10pt}
+\preloadfont\tenmaths {Latin Modern Math:mode=base;script=math;ssty=1;}{7pt}
+\preloadfont\tenmathss {Latin Modern Math:mode=base;script=math;ssty=2;}{5pt}
\toksapp\everyjob{\tenmath\tenmaths\tenmathss\tenrm
\textfont0=\tenmath\scriptfont0=\tenmaths\scriptscriptfont0=\tenmathss}
diff --git a/macros/luatex/generic/minim/minim-pdfresources.lua b/macros/luatex/generic/minim/minim-pdfresources.lua
new file mode 100644
index 0000000000..bc09aeaf40
--- /dev/null
+++ b/macros/luatex/generic/minim/minim-pdfresources.lua
@@ -0,0 +1,154 @@
+
+local M = { }
+
+local alloc = require 'minim-alloc'
+local cb = require 'minim-callbacks'
+
+-- the standard table design
+local function init_resources()
+ return {
+ ExtGState = { },
+ ColorSpace = { },
+ Pattern = { },
+ Shading = { },
+ }
+end
+
+-- the module will use optex’s functions if present
+M.self_destruct = pdf.add_page_resource or false
+
+-- resource_data is a table that can contain any data. only the following keys
+-- are used by this module:
+--
+-- _entry_ internal value; do not use
+-- value value in the resource dictionary
+-- write() called for writing the resource to the pdf; returns value
+--
+-- of the last two, only one needs be present; if the value is missing it will
+-- be set at first use to the result of write().
+--
+local resource_data = init_resources() -- name ↦ { [write = ... | value = ...], ... }
+--
+function M.add_resource(kind, name, resource)
+ resource_data[kind][name] = resource
+end
+function M.get_resource(kind, name)
+ return resource_data[kind][name]
+end
+function M.use_resource(kind, name)
+ local res = resource_data[kind][name]
+ if not res then
+ return alloc.err('Unknown %s resource: %s', kind, name)
+ end
+ res.value = res.value or res:write()
+ if not res._entry_ then -- first-use
+ res._entry_ = string.format('%s %s', alloc.pdf_name(name), res.value)
+ if M.self_destruct then
+ M.self_destruct(kind, name, res.value)
+ end
+ end
+ return res._entry_
+end
+
+-- global resources are mainly for pgf compatibility: contains adds entries to
+-- the resource dictionaries that will be added for every page.
+--
+local global_resources = init_resources() -- name ↦ '/Key <value>'
+--
+function M.add_global_resource(kind, name, value)
+ local r = global_resources[kind]
+ if M.self_destruct then
+ M.self_destruct(kind, name, value)
+ elseif name == nil then -- used for pgf compatibility
+ if value ~= '' then
+ r[''] = r[''] and string.format('%s %s', global_resources[kind][''], value) or value
+ end
+ else
+ r[name] = string.format('%s %s', alloc.pdf_name(name), value)
+ end
+end
+
+-- we can now provide optex’s interface
+if not M.self_destruct then
+ pdf.add_page_resource = M.add_global_resource
+end
+
+-- for nonglobal resources, every use must be markes with a late_lua node. from
+-- those, the M.use_resouce() function will be called automatically.
+--
+local page_resources = init_resources() -- name ↦ '/Key <value>'
+--
+function _with_pdf_resource_(kind, name) -- global, for use in latelua
+ page_resources[kind][name] = M.use_resource(kind, name)
+end
+function M.use_resource_node(kind, name)
+ local n = node.new('whatsit', 'late_lua')
+ n.data = string.format('_with_pdf_resource_("%s", "%s")', kind, name)
+ return n
+end
+
+-- construction and caching of resource dictionaries.
+--
+local previous_dicts = init_resources() -- pdf dict ↦ objnum
+--
+local function make_resource_entry(kind)
+ local arr = { }
+ for _, entry in pairs(page_resources[kind]) do table.insert(arr, entry) end
+ for _, entry in pairs(global_resources[kind]) do table.insert(arr, entry) end
+ if #arr == 0 then return false end
+ table.sort(arr)
+ arr[0] = '<<'; table.insert(arr, '>>')
+ local dict = table.concat(arr, ' ', 0)
+ local objnum = previous_dicts[kind][dict]
+ if not objnum then
+ objnum = pdf.obj(dict)
+ pdf.refobj(objnum)
+ previous_dicts[kind][dict] = objnum
+ end
+ return string.format('/%s %d 0 R', kind, objnum)
+end
+
+local removal_regex = {
+ ExtGState = ' */ExtGState *%d+ +0 *R',
+ ColorSpace = ' */ColorSpace *%d+ +0 *R',
+ Pattern = ' */Pattern *%d+ +0 *R',
+ Shading = ' */Shading *%d+ +0 *R' }
+
+local function update_page_resources(shippingout)
+ if M.self_destruct then return end
+ local resources = shippingout and pdf.getpageresources() or pdf.getxformresources() or ''
+ for kind, used in pairs(page_resources) do
+ resources = string.gsub(resources, removal_regex[kind], '')
+ local entry = make_resource_entry(kind)
+ if entry then
+ resources = resources == '' and entry or string.format('%s %s', resources, entry)
+ end
+ end
+ -- update page resources
+ if shippingout then
+ pdf.setpageresources(resources)
+ else
+ pdf.setxformresources(resources)
+ end
+ page_resources = init_resources()
+end
+
+cb.register('finish_pdfpage', update_page_resources)
+
+-- for pgf compatibility, reroute the pgf resource registration functions to
+-- our global resource pool.
+--
+alloc.luadef('minim:pgf:fix:luaside', function()
+ alloc.luadef('pgf@sys@addpdfresource@extgs@plain', function()
+ M.add_global_resource('ExtGState', nil, token.scan_string())
+ end)
+ alloc.luadef('pgf@sys@addpdfresource@patterns@plain', function()
+ M.add_global_resource('Pattern', nil, token.scan_string())
+ end)
+ alloc.luadef('pgf@sys@addpdfresource@colorspaces@plain', function()
+ M.add_global_resource('ColorSpace', nil, token.scan_string())
+ end)
+end)
+
+return M
+
diff --git a/macros/luatex/generic/minim/minim-pdfresources.tex b/macros/luatex/generic/minim/minim-pdfresources.tex
new file mode 100644
index 0000000000..6b8dc29577
--- /dev/null
+++ b/macros/luatex/generic/minim/minim-pdfresources.tex
@@ -0,0 +1,51 @@
+
+\ifdefined \minimpdfresourcesloaded
+ \message{(skipped)}
+ \expandafter\endinput\fi
+\chardef\minimpdfresourcesloaded=\catcode`\:
+\catcode`\:=11
+
+% at the moment, this file only deals with pgf compatibility. if you do not use
+% pgf, you only need the lua module.
+
+\directlua{ require 'minim-pdfresources' }
+
+% 1 pgf compatibility
+
+% this ballet inserts our fix directly at the end of pgfsys-luatex.def
+\expandafter\def\csname minim:intercept:pgfsys-luatex.def\endcsname
+ {\wlog{minim: applying pgf patches...}\newtoks\minim:pgf:fix:toks
+ \minim:pgf:fix:toks\csname pgfutil@everybye\endcsname
+ \let\endinput=\minim:pgf:fix:endinput}
+\def\minim:pgf:fix:endinput{%
+ \begincsname minim:pgf:fix:\minim:currentfile\endcsname
+ \minim:endinput}
+\expandafter\def\csname minim:pgf:fix:pgfsys-luatex.def\endcsname{%
+ \csname pgfutil@everybye\endcsname\minim:pgf:fix:toks \minim:pgf:fix:common
+ \let\endinput=\minim:endinput \wlog{minim: done applying pgf patches}}
+
+\def\minim:pgf:fix:common{\directlua{%
+ local pdfres = require 'minim-pdfresources'
+ pdfres.add_global_resource('ExtGState', nil,
+ '\luaescapestring{\csname pgf@sys@pgf@resource@list@extgs\endcsname}')
+ pdfres.add_global_resource('Pattern', nil,
+ '\luaescapestring{\csname pgf@sys@pgf@resource@list@patterns\endcsname}')
+ pdfres.add_global_resource('ColorSpace', nil,
+ '\luaescapestring{\csname pgf@sys@pgf@resource@list@colorspaces\endcsname}')}
+ \expandafter\let\csname pgf@sys@pdf@possible@resources\endcsname = \empty
+ \minim:pgf:fix:luaside \pdfvariable pageresources{}}
+
+% if pgf has already been loaded, copy the already-defined resources
+\ifcsname pgf@sys@pdf@extgs@objnum\endcsname \minim:pgf:fix:common
+ % three empty registers will be written at the end. having three unused
+ % empty objects in the pdf is not ideal, but will not lead to problems.
+ \expandafter\let\csname pgf@sys@pgf@resource@list@extgs\endcsname = \empty
+ \expandafter\let\csname pgf@sys@pgf@resource@list@patterns\endcsname = \empty
+ \expandafter\let\csname pgf@sys@pgf@resource@list@colorspaces\endcsname = \empty
+\fi
+
+% 
+
+\catcode`\:=\minimpdfresourcesloaded
+\endinput
+
diff --git a/macros/luatex/generic/minim/minim-plain.tex b/macros/luatex/generic/minim/minim-plain.tex
index 85fd802b8b..1fc0178ed8 100644
--- a/macros/luatex/generic/minim/minim-plain.tex
+++ b/macros/luatex/generic/minim/minim-plain.tex
@@ -490,8 +490,6 @@
\def\leavevmode{\unhbox\voidb@x} % begins a paragraph, if necessary
\def\_{\leavevmode \kern.06em \vbox{\hrule width.3em}}
-\def\AA{\leavevmode\setbox0\hbox{!}\dimen@\ht0\advance\dimen@-1ex%
- \rlap{\raise.67\dimen@\hbox{\char'27}}A}
\def\mathhexbox#1#2#3{\leavevmode
\hbox{$\m@th \mathchar"#1#2#3$}}
@@ -512,18 +510,6 @@
\def\dots{\relax\ifmmode\ldots\else$\m@th\ldots\,$\fi}
\def\TeX{T\kern-.1667em\lower.5ex\hbox{E}\kern-.125emX}
-\def\`#1{{\accent18 #1}}
-\def\'#1{{\accent19 #1}}
-\def\v#1{{\accent20 #1}} \let\^^_=\v
-\def\u#1{{\accent21 #1}} \let\^^S=\u
-\def\=#1{{\accent22 #1}}
-\def\^#1{{\accent94 #1}} \let\^^D=\^
-\def\.#1{{\accent95 #1}}
-\def\H#1{{\accent"7D #1}}
-\def\~#1{{\accent"7E #1}}
-\def\"#1{{\accent"7F #1}}
-\def\t#1{{\edef\next{\the\font}\the\textfont1\accent"7F\next#1}}
-
\def\hrulefill{\leaders\hrule\hfill}
\def\dotfill{\cleaders\hbox{$\m@th \mkern1.5mu.\mkern1.5mu$}\hfill}
\def\rightarrowfill{$\m@th\smash-\mkern-7mu%
diff --git a/macros/luatex/generic/minim/minim.doc b/macros/luatex/generic/minim/minim.doc
index d16250a0fe..a0ad8f2d4a 100644
--- a/macros/luatex/generic/minim/minim.doc
+++ b/macros/luatex/generic/minim/minim.doc
@@ -4,8 +4,8 @@
\startmetadata
author {Esger Renkema}
title {minim}
- date {2021-06-01}
- version {2021/1.0}
+ date {2022-03-03}
+ version {2022/1.1}
keywords {LuaTeX; Plain TeX; MetaPost; PDF/A; Tagged PDF; accessibility; a11y;
Unicode mathematics; XMP; metadata; hypertext; bookmarks}
stopmetadata
@@ -62,12 +62,7 @@ Please get in touch if you find this not the case.
Particular care has been taken to be compatible with \red{ltluatex}. All
overlapping functions should produce the same results and ltluatex can be
loaded either before or after minim.
-
-One point of incompatibility exists between \red{tikz/pgf} and the pattern
-functionality of minim-mp, due to conflicting implementations of pdf resource
-management.
-If you do not use filling patterns, however, the two packages can be used
-together.
+Earlier incompatibilities with \red{pgf} have been resolved.
\licencesection
diff --git a/macros/luatex/generic/minim/minim.pdf b/macros/luatex/generic/minim/minim.pdf
index 715525bcf9..1596eb65d4 100644
--- a/macros/luatex/generic/minim/minim.pdf
+++ b/macros/luatex/generic/minim/minim.pdf
Binary files differ
diff --git a/macros/luatex/generic/penlight/README.md b/macros/luatex/generic/penlight/README.md
index 818fb7d4ea..ca66c41b74 100644
--- a/macros/luatex/generic/penlight/README.md
+++ b/macros/luatex/generic/penlight/README.md
@@ -1,11 +1,11 @@
# penlight -- Lua libraries for use in LuaLaTeX
-This LuaLaTeX package provides a thin-wrapper to use the [penlight](https://github.com/lunarmodules/Penlight) Lua libraries with LuaLaTeX.
+This LuaLaTeX package provides a wrapper to use the [penlight](https://github.com/lunarmodules/Penlight) Lua libraries with LuaLaTeX, with some extra functionality added.
# License
-Copyright (C) 2021 Kale Ewasiuk
+Copyright (C) 2021-2022 Kale Ewasiuk
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/macros/luatex/generic/penlight/penlight.pdf b/macros/luatex/generic/penlight/penlight.pdf
index a8e166a1ae..33f3457df2 100644
--- a/macros/luatex/generic/penlight/penlight.pdf
+++ b/macros/luatex/generic/penlight/penlight.pdf
Binary files differ
diff --git a/macros/luatex/generic/penlight/penlight.sty b/macros/luatex/generic/penlight/penlight.sty
index b9f5a9490a..936cb6dce7 100644
--- a/macros/luatex/generic/penlight/penlight.sty
+++ b/macros/luatex/generic/penlight/penlight.sty
@@ -1,6 +1,6 @@
% Kale Ewasiuk (kalekje@gmail.com)
-% 2022-02-27
-% Copyright (C) 2021 Kale Ewasiuk
+% 2022-03-03
+% Copyright (C) 2021-2022 Kale Ewasiuk
%
% Permission is hereby granted, free of charge, to any person obtaining a copy
% of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,7 @@
% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
% OR OTHER DEALINGS IN THE SOFTWARE.
-\ProvidesPackage{penlight}[2022-02-27]
+\ProvidesPackage{penlight}[2022-03-03]
\RequirePackage{luacode}
@@ -32,17 +32,23 @@
}}
\DeclareOption{penlight}{\luadirect{
penlight = require('penlight')
- __PENLIGHT__ = 'penlight'
+ __PENLIGHT__ = 'penlight'
}}
\DeclareOption{stringx}{\luadirect{_G[__PENLIGHT__].stringx.import()}}
\DeclareOption{format}{\luadirect{_G[__PENLIGHT__].stringx.format_operator()}}
\DeclareOption{func}{\luadirect{_G[__PENLIGHT__].utils.import(__PENLIGHT__..'.func')}}
-\DeclareOption{extras}{\luadirect{require('penlightextras')}}
-\DeclareOption{extrasnoglobals}{
+\DeclareOption{extras}{\luadirect{require'penlightextras'}}
+\DeclareOption{extrasnoglobals}{\luadirect{
__PL_NO_GLOBALS__ = true
- \luadirect{require('penlightextras')
- }}
+ require'penlightextras'
+}}
\ProcessOptions*\relax
+
+\luadirect{
+if __PENLIGHT__ == nil then
+ tex.print('\\PackageError{penlight}{penlight or pl option must be passed to penlight as the first option}{}')
+end
+}
diff --git a/macros/luatex/generic/penlight/penlight.tex b/macros/luatex/generic/penlight/penlight.tex
index 176dc4e557..2096c10b68 100644
--- a/macros/luatex/generic/penlight/penlight.tex
+++ b/macros/luatex/generic/penlight/penlight.tex
@@ -1,6 +1,6 @@
% Kale Ewasiuk (kalekje@gmail.com)
-% 2022-02-27
-% Copyright (C) 2021 Kale Ewasiuk
+% 2022-03-03
+% Copyright (C) 2021-2022 Kale Ewasiuk
%
% Permission is hereby granted, free of charge, to any person obtaining a copy
% of this software and associated documentation files (the "Software"), to deal
diff --git a/macros/luatex/generic/penlight/penlightextras.lua b/macros/luatex/generic/penlight/penlightextras.lua
index 0cdec03763..192c86c923 100644
--- a/macros/luatex/generic/penlight/penlightextras.lua
+++ b/macros/luatex/generic/penlight/penlightextras.lua
@@ -1,8 +1,31 @@
+--% Kale Ewasiuk (kalekje@gmail.com)
+--% 2022-03-03
+--% Copyright (C) 2021-2022 Kale Ewasiuk
+--%
+--% Permission is hereby granted, free of charge, to any person obtaining a copy
+--% of this software and associated documentation files (the "Software"), to deal
+--% in the Software without restriction, including without limitation the rights
+--% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+--% copies of the Software, and to permit persons to whom the Software is
+--% furnished to do so, subject to the following conditions:
+--%
+--% The above copyright notice and this permission notice shall be included in
+--% all copies or substantial portions of the Software.
+--%
+--% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+--% ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+--% TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+--% PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+--% SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+--% ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+--% ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+--% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+--% OR OTHER DEALINGS IN THE SOFTWARE.
__SKIP_TEX__ = __SKIP_TEX__ or false --if declared true before here, it will use regular print functions
-- (for troubleshooting with texlua instead of actual use in lua latex)
-
__PL_NO_GLOBALS__ = __PL_NO_GLOBALS__ or false
+__PL_EXTRAS__ = 1
-- requires penlight
local pl = _G['penlight'] or _G['pl'] -- penlight for this namespace is pl
@@ -10,8 +33,8 @@ local pl = _G['penlight'] or _G['pl'] -- penlight for this namespace is pl
-- some bonus string operations, % text operator, and functional programming
pl.stringx.import()
-pl.text.format_operator()
-pl.utils.import('pl.func') -- allow placeholder expressions _1 +1 etc.
+pl.stringx.format_operator()
+pl.utils.import'pl.func' -- allow placeholder expressions _1 +1 etc.
pl.COMP = require'pl.comprehension'.new() -- for comprehensions
@@ -561,15 +584,48 @@ end
+-- https://tex.stackexchange.com/questions/38150/in-lualatex-how-do-i-pass-the-content-of-an-environment-to-lua-verbatim
+pl.tex.recordedbuf = ""
+function pl.tex.readbuf(buf)
+ i,j = string.find(buf, '\\end{%w+}')
+ if i==nil then -- if not ending an environment
+ pl.tex.recordedbuf = pl.tex.recordedbuf .. buf .. "\n"
+ return ""
+ else
+ return nil
+ end
+end
+
+function pl.tex.startrecording()
+ pl.tex.recordedbuf = ""
+ luatexbase.add_to_callback('process_input_buffer', pl.tex.readbuf, 'readbuf')
+end
+
+function pl.tex.stoprecording()
+ luatexbase.remove_from_callback('process_input_buffer', 'readbuf')
+ pl.tex.recordedbuf = pl.tex.recordedbuf:gsub("\\end{%w+}\n","")
+end
+
+
+
+
if not __PL_NO_GLOBALS__ then
+ __PL_EXTRAS__ = 2
-- iterators
kpairs = pl.utils.kpairs
npairs = pl.utils.npairs
--enum = utils.enum
for k,v in pairs(pl.tablex) do -- extend the table table to contain tablex functions
- _G['table'][k] = v
+ if k == 'sort' then
+ table.sortk = v
+ elseif k == 'move' then
+ table.xmove = v
+ else
+ _G['table'][k] = v
+ end
end
+ table.join = table.concat -- alias
hasval = pl.hasval
COMP = pl.COMP
@@ -589,6 +645,12 @@ if not __PL_NO_GLOBALS__ then
_G[k] = v
end
+end
+
+
+
+
+
--_xTrue = pl.tex._xTrue
--_xFalse = pl.tex._xFalse
--_xNoValue = pl.tex._xNoValue
@@ -619,11 +681,6 @@ if not __PL_NO_GLOBALS__ then
--add_bkt_cnt = pl.tex.add_bkt_cnt
--close_bkt_cnt = pl.tex.close_bkt_cnt
-end
-
-
-
-
-- graveyard
diff --git a/macros/luatex/latex/yamlvars/yamlvars.lua b/macros/luatex/latex/yamlvars/yamlvars.lua
index 1f95a50f25..f32627a21a 100644
--- a/macros/luatex/latex/yamlvars/yamlvars.lua
+++ b/macros/luatex/latex/yamlvars/yamlvars.lua
@@ -1,5 +1,5 @@
--% Kale Ewasiuk (kalekje@gmail.com)
---% 2022-02-25
+--% 2022-03-03
--% Copyright (C) 2021-2022 Kale Ewasiuk
--%
--% Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -46,9 +46,15 @@
--OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
--SOFTWARE.
+YAMLvars = {} -- self table
+YAMLvars.yaml = require'markdown-tinyyaml' -- note: YAMLvars.sty will have checked existence of this already
+
+local pl = _G['penlight'] or _G['pl'] -- penlight for this namespace is pl
+if (__PL_EXTRAS__ == nil) or (__PENLIGHT__ == nil) then
+ tex.sprint('\\PackageError{yamlvars}{penlight package with extras (or extrasnoglobals) option must be loaded before this package}{}')
+end
-YAMLvars = {} -- self table
YAMLvars.xfm = {}
YAMLvars.prc = {}
YAMLvars.dec = {} -- table of declare function
@@ -70,13 +76,12 @@ YAMLvars.tabmidrule = 'hline'
YAMLvars.debug = false
-YAMLvars.yaml = require'markdown-tinyyaml' -- note: YAMLvars.sty will have checked existence of this already
-local pl = _G['penlight'] or _G['pl'] -- penlight for this namespace is pl
+
function YAMLvars.debugtalk(s, ss)
if YAMLvars.debug then
- help_wrt(s, ss)
+ pl.tex.help_wrt(s, ss)
end
end
@@ -130,7 +135,7 @@ function YAMLvars.xfm.arrsortlastnameAZ(var, val)
end
-- todo need distinction beyyween table and penlight list ???
function YAMLvars.xfm.list2nl(var, val)
- return pl.tablex.join(val,'\\\\ ')
+ return pl.List(val):join('\\\\ ')
end
--val = pl.array2d.map_slice1(_1..'\\\\', val, 1,-2)
@@ -150,7 +155,7 @@ end
function YAMLvars.xfm.markdown(var, val)
--return '\\begin{markdown} '..val..'\n \\end{markdown}'
- help_wrt(val, md)
+ pl.tex.help_wrt(val, md)
return [[begin markdown ..val..
par end markdown]]
@@ -194,7 +199,7 @@ end
function YAMLvars.prc.toggle(t, v) -- requires penlight extras
local s = ''
- if hasval(v) then
+ if pl.hasval(v) then
s = '\\global\\toggletrue{'..t..'}'
else
s = '\\global\\togglefalse{'..t..'}'
@@ -358,15 +363,15 @@ local function eval_expr(func, var, val)
if c == 0 then
return _YV_invalid_expression
else
- --help_wrt(s, var)
- --help_wrt(val, var)
+ --pl.tex.help_wrt(s, var)
+ --pl.tex.help_wrt(val, var)
YAMLvars.valTemp = val
YAMLvars.varTemp = var
- --help_wrt(s, var)
+ --pl.tex.help_wrt(s, var)
s, c = s:gsub('\2', '') -- strip \2 that might have appeared if / was applied
s = sub_lua_var(' '..s, 'x', 'YAMLvars.valTemp')
s = sub_lua_var(s, 'v', 'YAMLvars.varTemp')
- --help_wrt(s, var)
+ --pl.tex.help_wrt(s, var)
local f, err = pcall(loadstring(s))
if not f then
tex.print('\\PackageError{YAMLvars}{xfm with "= or /" error on var "'..var..'"}{}') --
@@ -431,27 +436,6 @@ end
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
--- https://tex.stackexchange.com/questions/38150/in-lualatex-how-do-i-pass-the-content-of-an-environment-to-lua-verbatim
-recordedbuf = ""
-function readbuf(buf)
- i,j = string.find(buf, '\\end{%w+}')
- if i==nil then -- if not ending an environment
- recordedbuf = recordedbuf .. buf .. "\n"
- return ""
- else
- return nil
- end
-end
-
-function startrecording()
- recordedbuf = ""
- luatexbase.add_to_callback('process_input_buffer', readbuf, 'readbuf')
-end
-
-function stoprecording()
- luatexbase.remove_from_callback('process_input_buffer', 'readbuf')
- recordedbuf = recordedbuf:gsub("\\end{%w+}\n","")
-end
@@ -475,7 +459,7 @@ function YAMLvars.getYAMLcli()
end
end
end
- --help_wrt(t)
+ --pl.tex.help_wrt(t)
return t
end
@@ -489,7 +473,7 @@ return YAMLvars
-- y = clean_tex_spaces(y)
--end
--local function clean_tex_spaces(s)
--- help_wrt(s)
+-- pl.tex.help_wrt(s)
-- if s:sub(1,2) == '%s' then
-- s, _ = s:gsub('%s+','',1)
-- end
diff --git a/macros/luatex/latex/yamlvars/yamlvars.pdf b/macros/luatex/latex/yamlvars/yamlvars.pdf
index bdb6b811da..864a0842d4 100644
--- a/macros/luatex/latex/yamlvars/yamlvars.pdf
+++ b/macros/luatex/latex/yamlvars/yamlvars.pdf
Binary files differ
diff --git a/macros/luatex/latex/yamlvars/yamlvars.sty b/macros/luatex/latex/yamlvars/yamlvars.sty
index 8e295988fb..1c4b8fcf32 100644
--- a/macros/luatex/latex/yamlvars/yamlvars.sty
+++ b/macros/luatex/latex/yamlvars/yamlvars.sty
@@ -1,5 +1,5 @@
% Kale Ewasiuk (kalekje@gmail.com)
-% 2022-02-25
+% 2022-03-03
% Copyright (C) 2021-2022 Kale Ewasiuk
%
% Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -25,14 +25,14 @@
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{YAMLvars}[2022-02-25]
+\ProvidesPackage{YAMLvars}[2022-03-03]
\IfFileExists{markdown-tinyyaml.lua}{}{\PackageError{YAMLvars}{This package requires installation of the 'markdown' package, please install it and try again}{}}
\RequirePackage{luacode}
\RequirePackage{xspace}
\RequirePackage{etoolbox}
-\RequirePackage[pl,extras]{penlight}
+\RequirePackage{penlight} % no option passed here, but extras must be used, error will be thrown if not
\luadirect{YAMLvars = require('YAMLvars')}
@@ -53,6 +53,9 @@
\luadirect{YAMLvars.debug = true}
}
+\newcommand{\AllowUndeclaredYV}{\luadirect{YAMLvars.allowUndeclared = true}}
+\newcommand{\ForbidUndeclaredYV}{\luadirect{YAMLvars.allowUndeclared = false}}
+
\DeclareOption*{\PackageWarning{YAMLvars}{Unknown option: '\CurrentOption'}{}}
\ProcessOptions\relax
@@ -61,15 +64,13 @@
\newcommand{\parseYAMLvarsFile}[1]{\luadirect{YAMLvars.parseYAMLvarsFile(\luastring{#1})}}
-\newenvironment{declareYAMLvars}{\luadirect{startrecording()}}{\luadirect{stoprecording()}
-\luadirect{YAMLvars.declareYAMLvarsStr(recordedbuf)}
+\newenvironment{declareYAMLvars}{\luadirect{pl.tex.startrecording()}}{\luadirect{pl.tex.stoprecording()}
+ \luadirect{YAMLvars.declareYAMLvarsStr(pl.tex.recordedbuf)}
}
-\newenvironment{parseYAMLvars}{\luadirect{startrecording()}}{\luadirect{stoprecording()}
-\luadirect{YAMLvars.parseYAMLvarsStr(recordedbuf)}
+\newenvironment{parseYAMLvars}{\luadirect{pl.tex.startrecording()}}{\luadirect{pl.tex.stoprecording()}
+ \luadirect{YAMLvars.parseYAMLvarsStr(pl.tex.recordedbuf)}
}
\newcommand{\resetYAMLvarsspec}{\luadirect{YAMLvars.varspec = {}}}
-\newcommand{\AllowUndeclaredYV}{\luadirect{YAMLvars.allowUndeclared = true}}
-\newcommand{\ForbidUndeclaredYV}{\luadirect{YAMLvars.allowUndeclared = false}}
diff --git a/macros/luatex/latex/yamlvars/yamlvars.tex b/macros/luatex/latex/yamlvars/yamlvars.tex
index a61df03024..1c412c2f6d 100644
--- a/macros/luatex/latex/yamlvars/yamlvars.tex
+++ b/macros/luatex/latex/yamlvars/yamlvars.tex
@@ -1,5 +1,5 @@
% Kale Ewasiuk (kalekje@gmail.com)
-% 2022-02-25
+% 2022-03-03
% Copyright (C) 2021-2022 Kale Ewasiuk
%
% Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -53,7 +53,7 @@
\date{\today}
-
+\usepackage[pl,extrasnoglobals]{penlight}
\usepackage[overwritedefs]{YAMLvars}
\title{YAMLvars}
\subtitle{a YAML variable parser for LuaLaTeX}
diff --git a/macros/xetex/latex/ucharclasses/README b/macros/xetex/latex/ucharclasses/README
index c943253ffd..e29112c489 100644
--- a/macros/xetex/latex/ucharclasses/README
+++ b/macros/xetex/latex/ucharclasses/README
@@ -8,7 +8,7 @@
ucharclasses package for XeLaTex
--------------------------------------
- Michiel Kamermans, v2.4, February 2021
+ Michiel Kamermans, v2.5, March 2022
The brief
---------
@@ -58,11 +58,12 @@ So what is it?
Unicode Compatibility
---------------------
- Current compatibility is Unicode 13.0
+ Current compatibility is Unicode 14.0
Changelog
---------
+ v2.5: Unicode 14 support
v2.4: Unicode 11, 12, and 13 support
v2.3: Unicode 10 support
v2.2: Unicode 8.0 and LaTeX2e support
@@ -73,7 +74,7 @@ Changelog
Contributors
------------
- v2.4: Werner Lemberg
+ v2.4-2.5: Werner Lemberg
v2.1-2.3: Qing Lee, Werner Lemberg
v2.0: Enrico Gregorio
v1.0: Mike "Pomax" Kamermans
diff --git a/macros/xetex/latex/ucharclasses/ucharclasses.pdf b/macros/xetex/latex/ucharclasses/ucharclasses.pdf
index 01054f2957..76518d2702 100644
--- a/macros/xetex/latex/ucharclasses/ucharclasses.pdf
+++ b/macros/xetex/latex/ucharclasses/ucharclasses.pdf
Binary files differ
diff --git a/macros/xetex/latex/ucharclasses/ucharclasses.sty b/macros/xetex/latex/ucharclasses/ucharclasses.sty
index 11da6a9ed2..59a2daf356 100644
--- a/macros/xetex/latex/ucharclasses/ucharclasses.sty
+++ b/macros/xetex/latex/ucharclasses/ucharclasses.sty
@@ -8,12 +8,13 @@
% Current compatibility should be Unicode 13.0
%
% Credits:
-% v2.4: Werner Lemberg
+% v2.4-2.5: Werner Lemberg
% v2.1-2.3: Qing Lee, Werner Lemberg
% v2.0: Enrico Gregorio
% v1.0: Mike "Pomax" Kamermans
%
% Significant updates:
+% v2.5: Unicode 14 support
% v2.4: Unicode 13 support
% v2.3: Unicode 10 support
% v2.2: Unicode 8.0 and LaTeX2e support
@@ -25,7 +26,7 @@
%
% ----------------------------------------------------------------------------
-\ProvidesPackage{ucharclasses}[2021/02/16 v2.4.0 Unicode block character classes for XeLaTeX]
+\ProvidesPackage{ucharclasses}[2022/03/01 v2.5.0 Unicode block character classes for XeLaTeX]
\newif\if@ucharclassverbose
\DeclareOption{verbose}{\@ucharclassverbosetrue}
@@ -296,36 +297,29 @@
\do{LatinExtendedE}{"0AB30}{"0AB6F}
\do{LinearA}{"010600}{"01077F}
\do{Mahajani}{"011150}{"01117F}
- \do{Manichaean}{"010AC0}{"010AFF}
+% Manichaean (see below)
\do{MendeKikakui}{"01E800}{"01E8DF}
\do{Modi}{"011600}{"01165F}
\do{Mro}{"016A40}{"016A6F}
\do{MyanmarExtendedB}{"0A9E0}{"0A9FF}
- \do{Nabataean}{"010880}{"0108AF}
+% Nabataean (see below)
% OldNorthArabian (see below)
- \do{OldPermic}{"010350}{"01037F}
+% OldPermic (see below)
\do{OrnamentalDingbats}{"01F650}{"01F67F}
\do{PahawhHmong}{"016B00}{"016B8F}
- \do{Palmyrene}{"010860}{"01087F}
+% Palmyrene (see below)
\do{PauCinHau}{"011AC0}{"011AFF}
- \do{PsalterPahlavi}{"010B80}{"010BAF}
+% PsalterPahlavi (see below)
% ShorthandFormatControls (see below)
\do{Siddham}{"011580}{"0115FF}
\do{SinhalaArchaicNumbers}{"0111E0}{"0111FF}
\do{SupplementalArrowsC}{"01F800}{"01F8FF}
\do{Tirhuta}{"011480}{"0114DF}
\do{WarangCiti}{"0118A0}{"0118FF}
-% Unicode 8.0 additions
-% Ahom (see below)
-% AnatolianHieroglyphs (see below)
+% Unicode 8.0 additions needed for classes
\do{CherokeeSupplement}{"0AB70}{"0ABBF}
\do{CJKUnifiedIdeographsExtensionE}{"02B820}{"02CEAF}
-% EarlyDynasticCuneiform (see below)
-% Hatran (see below)
-% Multani (see below)
- \do{OldHungarian}{"010C80}{"010CFF}
\do{SupplementalSymbolsAndPictographs}{"01F900}{"01F9FF}
-% SuttonSignWriting (see below)
% Unicode 9.0 additions needed for classes
\do{CyrillicExtendedC}{"01C80}{"01C8F}
\do{GlagoliticSupplement}{"01E000}{"01E02F}
@@ -342,6 +336,13 @@
\do{SymbolsAndPictographsExtendedA}{"01FA70}{"01FAFF}
% Unicode 13.0 additions needed for classes
\do{CJKUnifiedIdeographsExtensionG}{"030000}{"03134F}
+% Unicode 14.0 additions needed for classes
+ \do{ArabicExtendedB}{"0870}{"089F}
+ \do{EthiopicExtendedB}{"01E7E0}{"01E7FF}
+ \do{KanaExtendedB}{"01AFF0}{"01AFFF}
+ \do{LatinExtendedF}{"010780}{"0107BF}
+ \do{LatinExtendedG}{"01DF00}{"01DFFF}
+ \do{UnifiedCanadianAboriginalSyllabicsExtendedA}{"011AB0}{"011ABF}
%
\ifdefined\XeTeXinterwordspaceshaping
% Unicode 5.1 block definitions
@@ -355,14 +356,20 @@
\do{OldTurkic}{"010C00}{"010C4F}
% Unicode 7.0 additions
\do{Duployan}{"01BC00}{"01BC9F}
+ \do{Manichaean}{"010AC0}{"010AFF}
+ \do{Nabataean}{"010880}{"0108AF}
\do{OldNorthArabian}{"010A80}{"010A9F}
+ \do{OldPermic}{"010350}{"01037F}
+ \do{Palmyrene}{"010860}{"01087F}
+ \do{PsalterPahlavi}{"010B80}{"010BAF}
\do{ShorthandFormatControls}{"01BCA0}{"01BCAF}
% Unicode 8.0 additions
- \do{Ahom}{"011700}{"01173F}
+ \do{Ahom}{"011700}{"01174F}
\do{AnatolianHieroglyphs}{"014400}{"01467F}
\do{EarlyDynasticCuneiform}{"012480}{"01254F}
\do{Hatran}{"0108E0}{"0108FF}
\do{Multani}{"011280}{"0112AF}
+ \do{OldHungarian}{"010C80}{"010CFF}
\do{SuttonSignWriting}{"01D800}{"01DAAF}
% Unicode 9.0 additions
\do{Adlam}{"01E900}{"01E95F}
@@ -402,8 +409,15 @@
\do{KhitanSmallScript}{"018B00}{"018CFF}
\do{LisuSupplement}{"011FB0}{"011FBF}
\do{SymbolsForLegacyComputing}{"01FB00}{"01FBFF}
- \do{TangutSupplement}{"018D00}{"018D8F}
+ \do{TangutSupplement}{"018D00}{"018D7F}
\do{Yezidi}{"010E80}{"010EBF}
+% Unicode 14.0 additions
+ \do{CyproMinoan}{"012F90}{"012FFF}
+ \do{OldUighur}{"010F70}{"010FAF}
+ \do{Tangsa}{"016A70}{"016ACF}
+ \do{Toto}{"01E290}{"01E2BF}
+ \do{Vithkuqi}{"010570}{"0105BF}
+ \do{ZnamennyMusicalNotation}{"01CF00}{"01CFCF}
\fi
}
@@ -461,6 +475,7 @@
\def\ArabicsClasses{
\do{Arabic}
\do{ArabicExtendedA}
+ \do{ArabicExtendedB}
\do{ArabicPresentationFormsA}
\do{ArabicPresentationFormsB}
\do{ArabicSupplement}
@@ -469,6 +484,7 @@
\def\CanadianSyllabicsClasses{
\do{UnifiedCanadianAboriginalSyllabics}
\do{UnifiedCanadianAboriginalSyllabicsExtended}
+ \do{UnifiedCanadianAboriginalSyllabicsExtendedA}
}
\def\CherokeeFullClasses{
@@ -532,6 +548,7 @@
\do{IdeographicSymbolsAndPunctuation}
\do{KanaSupplement}
\do{KanaExtendedA}
+ \do{KanaExtendedB}
\do{Kanbun}
\do{KangxiRadicals}
\do{Katakana}
@@ -570,6 +587,7 @@
\do{Ethiopic}
\do{EthiopicExtended}
\do{EthiopicExtendedA}
+ \do{EthiopicExtendedB}
\do{EthiopicSupplement}
}
@@ -615,6 +633,8 @@
\do{LatinExtendedC}
\do{LatinExtendedD}
\do{LatinExtendedE}
+ \do{LatinExtendedF}
+ \do{LatinExtendedG}
\do{LatinSupplement}
}
@@ -766,7 +786,7 @@
\do{MahjongTiles}
\do{Malayalam}
\do{Mandaic}
- \do{Manichaean}
+% Manichaean (see below)
\do{MeeteiMayek}
\do{MeeteiMayekExtensions}
\do{MendeKikakui}
@@ -776,15 +796,15 @@
\do{Modi}
\do{Mro}
\do{MusicalSymbols}
- \do{Nabataean}
+% Nabataean (see below)
\do{NewTaiLue}
\do{NKo}
\do{Ogham}
\do{OlChiki}
- \do{OldHungarian}
+% OldHungarian (see below)
% OldItalic (see below)
% OldNorthArabian (see below)
- \do{OldPermic}
+% OldPermic (see below)
\do{OldPersian}
% OldSouthArabian (see below)
% OldTurkic (see below)
@@ -792,14 +812,14 @@
\do{Oriya}
\do{Osmanya}
\do{PahawhHmong}
- \do{Palmyrene}
+% Palmyrene (see below)
\do{PauCinHau}
\do{PhagsPa}
% PhaistosDisc (see below)
\do{Phoenician}
\do{PlayingCards}
\do{PrivateUseArea}
- \do{PsalterPahlavi}
+% PsalterPahlavi (see below)
\do{Rejang}
\do{RumiNumeralSymbols}
\do{Runic}
@@ -847,6 +867,7 @@
\do{Carian}
\do{ChessSymbols}
\do{Chorasmian}
+ \do{CyproMinoan}
\do{DivesAkuru}
\do{Dogra}
\do{Duployan}
@@ -859,23 +880,30 @@
\do{LisuSupplement}
\do{KhitanSmallScript}
\do{Makasar}
+ \do{Manichaean}
\do{Marchen}
\do{MasaramGondi}
\do{MayanNumerals}
\do{Medefaidrin}
\do{Multani}
+ \do{Nabataean}
\do{Nandinagari}
\do{Newa}
\do{Nushu}
\do{NyiakengPuachueHmong}
+ \do{OldHungarian}
\do{OldItalic}
\do{OldNorthArabian}
+ \do{OldPermic}
\do{OldSogdian}
\do{OldSouthArabian}
\do{OldTurkic}
+ \do{OldUighur}
\do{Osage}
\do{OttomanSiyaqNumbers}
+ \do{Palmyrene}
\do{PhaistosDisc}
+ \do{PsalterPahlavi}
\do{ShorthandFormatControls}
\do{Sogdian}
\do{Soyombo}
@@ -884,12 +912,16 @@
\do{SuttonSignWriting}
\do{SymbolsForLegacyComputing}
\do{TamilSupplement}
+ \do{Tangsa}
\do{Tangut}
\do{TangutComponents}
\do{TangutSupplement}
+ \do{Toto}
+ \do{Vithkuqi}
\do{Wancho}
\do{Yezidi}
\do{ZanabazarSquare}
+ \do{ZnamennyMusicalNotation}
\fi
}
diff --git a/macros/xetex/latex/ucharclasses/ucharclasses.tex b/macros/xetex/latex/ucharclasses/ucharclasses.tex
index bbe96acd71..aaa7bc912b 100644
--- a/macros/xetex/latex/ucharclasses/ucharclasses.tex
+++ b/macros/xetex/latex/ucharclasses/ucharclasses.tex
@@ -381,7 +381,7 @@
\section{Package options and Unicode blocks}
- The following Unicode blocks are available for use in transition rules (corresponding to Unicode version 10.0), as well as for use as package options when you want ucharclasses to only load those classes that you know are used in your document.
+ The following Unicode blocks are available for use in transition rules (corresponding to Unicode version 14.0), as well as for use as package options when you want ucharclasses to only load those classes that you know are used in your document.
Starting with XeTeX version 0.99994 (available in TeXLive 2016), the number of \textbackslash XeTeXcharclass registers was extended from 256 to 4096; some not so important blocks are thus provided only for this and newer versions; in the list below, those blocks are put into parentheses.
@@ -398,6 +398,7 @@
\item AncientSymbols
\item Arabic
\item ArabicExtendedA
+ \item ArabicExtendedB
\item ArabicMathematicalAlphabeticSymbols
\item ArabicPresentationFormsA
\item ArabicPresentationFormsB
@@ -459,6 +460,7 @@
\item CuneiformNumbersAndPunctuation
\item CurrencySymbols
\item CypriotSyllabary
+ \item (CyproMinoan)
\item Cyrillic
\item CyrillicExtendedA
\item CyrillicExtendedB
@@ -485,6 +487,7 @@
\item Ethiopic
\item EthiopicExtended
\item EthiopicExtendedA
+ \item EthiopicExtendedB
\item EthiopicSupplement
\item GeneralPunctuation
\item GeometricShapes
@@ -522,6 +525,7 @@
\item Javanese
\item Kaithi
\item KanaExtendedA
+ \item KanaExtendedB
\item KanaSupplement
\item Kanbun
\item KangxiRadicals
@@ -542,6 +546,8 @@
\item LatinExtendedC
\item LatinExtendedD
\item LatinExtendedE
+ \item LatinExtendedF
+ \item LatinExtendedG
\item LatinSupplement
\item Lepcha
\item LetterlikeSymbols
@@ -558,7 +564,7 @@
\item (Makasar)
\item Malayalam
\item Mandaic
- \item Manichaean
+ \item (Manichaean)
\item (Marchen)
\item (MasaramGondi)
\item MathematicalAlphanumericSymbols
@@ -587,7 +593,7 @@
\item Myanmar
\item MyanmarExtendedA
\item MyanmarExtendedB
- \item Nabataean
+ \item (Nabataean)
\item (Nandinagari)
\item (Newa)
\item NewTaiLue
@@ -597,14 +603,15 @@
\item (Nushu)
\item Ogham
\item OlChiki
- \item OldHungarian
+ \item (OldHungarian)
\item (OldItalic)
\item (OldNorthArabian)
- \item OldPermic
+ \item (OldPermic)
\item OldPersian
\item (OldSogdian)
\item (OldSouthArabian)
\item (OldTurkic)
+ \item (OldUighur)
\item OpticalCharacterRecognition
\item Oriya
\item OrnamentalDingbats
@@ -612,7 +619,7 @@
\item Osmanya
\item (OttomanSiyaqNumbers)
\item PahawhHmong
- \item Palmyrene
+ \item (Palmyrene)
\item PauCinHau
\item PhagsPa
\item (PhaistosDisc)
@@ -621,7 +628,7 @@
\item PhoneticExtensionsSupplement
\item PlayingCards
\item PrivateUseArea
- \item PsalterPahlavi
+ \item (PsalterPahlavi)
\item Rejang
\item RumiNumeralSymbols
\item Runic
@@ -666,6 +673,7 @@
\item Takri
\item Tamil
\item (TamilSupplement)
+ \item (Tangsa)
\item (Tangut)
\item (TangutComponents)
\item (TangutSupplement)
@@ -675,13 +683,16 @@
\item Tibetan
\item Tifinagh
\item Tirhuta
+ \item (Toto)
\item TransportAndMapSymbols
\item Ugaritic
\item UnifiedCanadianAboriginalSyllabics
\item UnifiedCanadianAboriginalSyllabicsExtended
+ \item UnifiedCanadianAboriginalSyllabicsExtendedA
\item Vai
\item VedicExtensions
\item VerticalForms
+ \item (Vithkuqi)
\item (Wancho)
\item WarangCiti
\item (Yezidi)
@@ -689,6 +700,7 @@
\item YiSyllables
\item YijingHexagramSymbols
\item (ZanabazarSquare)
+ \item (ZnamennyMusicalNotation)
\end{itemlist}
\end{multicols*}