summaryrefslogtreecommitdiff
path: root/macros/optex/pkg/minim.opm
blob: 79298552d115d04500c73a82c34ff102081d783c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
% This is used by OpTeX packages minim-mp, minim-pdf, see http://petr.olsak.net/optex
% minim.opm, Michal Vlasák  <lahcim8@gmail.com>, 2022 
% see also https://github.com/vlasakm/optex-minim

\_def\_optexminim_version{0.1}
\_codedecl \optexminim_loaded  {Minim compatibility for \OpTeX/ (v\_optexminim_version)}

   \_doc
   When we want to use minim with \OpTeX/, we need to accomodate for their
   differences. Particularly in allocations. Because of Esger Renkema's
   graciousness, minim has been modified in ways that make it easier to
   integrate with \OpTeX/. So even when the two formats normally disagree on a
   lot of core things (allocations, callbacks) they can end up working together.

   \OpTeX/ defines most allocation macros in `alloc.opm` and some Lua
   allocation functions in `optex.lua`. Minim \"packages" are not standalone,
   they all depend on core routines defined in `minim-alloc.tex` and
   `minim-alloc.lua` respectively. Minim as a format preloads a stripped
   version of `etex.src` so the Lua code makes some assumptions about that
   (i.e. expects local allocators).

   Both \OpTeX/ and minim want to make it possible to register more functions
   for a single callback, by chaining their calls and `callback.register()`ing
   only a proxy function. While minim stays close to the `callback` interface
   from \LuaTeX/, \OpTeX/ is a subset of the \LaTeX/ `luatexbase` interface.
   But minim now can work on top of ltluatex by using its functions instead of
   `callback.register()`, so we don't have to do anything to support it in
   \OpTeX/!

   Firstly, because we only change what is defined by others, we actually need
   a dummy macro for `\_codedecl`, to prevent loading this file more than once.
   \_cod

\_catcode`\@=11
% dummy macro to signalize that we are loaded
\_let\optexminim_loaded=\empty

   \_doc
   In general, there are four allocator types expected by minim:

   \begitems
   * Knuth allocators from `plain.tex` (like `\newcount`). These are already
   defined by \OpTeX/. Although minim itself sets the old `\allocationnumber`
   counter, which is not even defined in \OpTeX/.

   * Global allocators from `etex.src` (like `\globcount`). These are not
   defined by \OpTeX/, since they no longer make sense (\LuaTeX/ doesn't use
   sparse arrays for registers). Minim defines them to be the classic Knuth
   allocators if it doesn't find them on the TeX side, but expects them from
   the Lua side.

   * Local allocators from `etex.src` (like `\loccount`). Concept of local
   allocators is completely missing in \OpTeX/. The semantics of local
   allocation in Lua is weird too, so we try to avoid these, since minim also
   doesn't define their Lua variants.

   * \LuaTeX/ allocators from `ltluatex.tex` (like `\newattribute`). Subset of
   these is in \OpTeX/ (only atributes, which are also allocatable in Lua, and
   catcode tables). But minim tries to be compatible with \LaTeX/ and patches
   its routines if it detects them.
   \enditems

   For defining \TeX/ commands implemented in Lua, \OpTeX/ has
   `define_lua_command`, which actually does the allocation and definition at
   the same time, and allows to do so only from Lua end.

   Historically (in my opinion unfortunately) \LaTeX/ made the allocations of
   these functions available from \TeX/ end, and the \"lua define" operation is
   thus a two step process which involves synchronization with \TeX/.

   `minim-alloc` actually defines a `luadef` function which is like
   `define_lua_command`, but is backed by the minim allocator. To make this
   work, we just need to set the \LaTeX/ register to the index of last
   allocated function, since it allocates at counter plus one. Then minim will
   start where \OpTeX/ stopped, and we will later define `define_lua_command`
   to be just minim's `luadef`.

   We tell the number of allocated function by going through the table of
   actually used functions. This is not that robust, because while
   `define_lua_command` allocates sequentially, the provided functions may be
   `nil`, which breaks the code below.
   \_cod

\_newcount\allocationnumber

% for synchronisation of allocated Lua functions
\_ea\_newcount\_csname e@alloc@luafunction@count\_endcsname

\directlua{
    local function_table = lua.get_functions_table()
    % minim allocates at count + 1 for "new" allocators, so this works
    tex.setcount("global", "e@alloc@luafunction@count", \csstring\#function_table)
}

   \_doc
   We also get PDF resources out of the way now. Minim is ready to use \OpTeX's
   PDF resource management, but also has compatibility layer for PGF, which is
   not needed in \OpTeX/. We prevent loading the problematic \TeX/ file.
   \_cod

\_let\minimpdfresourcesloaded=\_empty

   \_doc
   The preparations are over. We load `minim-alloc.tex`.
   \_cod

\input minim-alloc

   \_doc
   Both \LaTeX/ and the minim inspired catcode table allocators initialize the
   catcode tables with `\initcatcodetable` (i.e. ini\TeX/ catcodes). \OpTeX/
   merely allocates the registers. \LuaTeX/ doesn't allow to activate
   unitialized catcode table, therefore activation with either
   `\initcatcodetable` or `\savecatcodetable` is necessary before use. To
   ensure compatibility with foreign macros, we also issue `\initcatcodetable`
   on allocation in the public version of `\newcatcodetable`.
   \_cod

\_def\newcatcodetable#1{\_newcatcodetable#1\_initcatcodetable#1}

   \_doc
   By now, the Knuthian allocators are dealt with. \eTeX/ global and local
   allocators are undefined, but the global ones are expected in minim's Lua
   code with their hardcoded counter register numbers. This is unacceptable,
   since in this range (`\count260` to `\count266`) \OpTeX/ has already made
   allocations. Thus we need to replace these Lua functions with similar
   definitions. For some, \OpTeX/ also has a different idea whether the counter
   represent the last or next allocated register number, so we correct that as
   well.

   We also don't forget to actually set `define_lua_command` to be minim's
   `luadef`.
   \_cod

\directlua{
    local minimalloc = require("minim-alloc")

    define_lua_command = minimalloc.luadef

    % these are allocators already defined in OpTeX that we need to repair
    local toreplace = {
        "count",
        "dimen",
        "skip",
        "muskip",
        "box",
        "toks",
        "marks",
        "attribute",
        "catcodetable",
    }

    for _, alloc in ipairs(toreplace) do
        local cache = {}
        local countername = string.format("_\_pcent salloc", alloc)
        minimalloc["new_"..alloc] = function(id)
            local n = cache[id]
            if not n then
                n = tex.getcount(countername) + 1
                tex.setcount("global", countername, n)
                if id then
                    cache[id] = n
                end
                minimalloc.log(
                    "\_nbb\_pcent s\_pcent d : \_pcent s", alloc, n, id or "<unnamed>")
            end
            return n
        end
    end
}

   \_doc
   We also need to do something about `minim-hooks.tex`, which hooks into
   `\shipout`, but the default \OpTeX/ output routine (and perhaps also the
   user ones) use `\_shipout`.

   Minim also adds to `\everypar`, but that is fine.
   \_cod

\_let\shipout\_shipout

\input minim-hooks

\_catcode`\:=11
\_let\_shipout\minim:shipout:new

% catcodes changes don't propage, since this file is loaded with \opinput
\_endcode