summaryrefslogtreecommitdiff
path: root/macros/luatex/generic/minim
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/luatex/generic/minim
parent6b9ed20cb01cb52c7aaf2a48202f5d8aa588ff79 (diff)
CTAN sync 202203040301
Diffstat (limited to 'macros/luatex/generic/minim')
-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
14 files changed, 691 insertions, 245 deletions
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