strc-ini.lua /size: 12 Kb    last modification: 2020-07-01 14:35
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
strc-ini
'
]
=
{
2
version
=
1
.
001
,
3
comment
=
"
companion to strc-ini.mkiv
"
,
4
author
=
"
Hans Hagen, PRAGMA-ADE, Hasselt NL
"
,
5
copyright
=
"
PRAGMA ADE / ConTeXt Development Team
"
,
6
license
=
"
see context related readme files
"
7
}
8 9
--[[ 10The restructuring is the (intermediate) result of quite some experiments. I started 11with the basic structure, followed by lists, numbers, enumerations, itemgroups 12and floats. All these have something in common, like pagenumbers and section 13prefixes. I played with some generic datastructure (in order to save space) but 14the code at both the lua and tex end then quickly becomes messy due to the fact 15that access to variables is too different. So, eventually I ended up with 16dedicated structures combined with sharing data. In lua this is quite efficient 17because tables are referenced. However, some precautions are to be taken in 18order to keep the utility file small. Utility data and process data share much 19but it does not make sense to store all processdata. 20 21]]
--
22 23
local
lpegmatch
=
lpeg
.
match
24
local
type
,
next
,
tonumber
,
select
=
type
,
next
,
tonumber
,
select
25 26
local
formatters
=
string
.
formatters
27
local
settings_to_array
=
utilities
.
parsers
.
settings_to_array
28
local
settings_to_hash
=
utilities
.
parsers
.
settings_to_hash
29
local
allocate
=
utilities
.
storage
.
allocate
30 31
local
catcodenumbers
=
catcodes
.
numbers
-- better use the context(...) way to switch
32 33
local
ctxcatcodes
=
catcodenumbers
.
ctxcatcodes
34
local
xmlcatcodes
=
catcodenumbers
.
xmlcatcodes
35
local
notcatcodes
=
catcodenumbers
.
notcatcodes
36
local
txtcatcodes
=
catcodenumbers
.
txtcatcodes
37 38
local
context
=
context
39
local
commands
=
commands
40 41
local
trace_processors
=
false
42
local
report_processors
=
logs
.
reporter
(
"
processors
"
,
"
structure
"
)
43 44
trackers
.
register
(
"
typesetters.processors
"
,
function
(
v
)
trace_processors
=
v
end
)
45 46
local
xmlconvert
=
lxml
.
convert
47
local
xmlstore
=
lxml
.
store
48 49
local
ctx_pushcatcodes
=
context
.
pushcatcodes
50
local
ctx_popcatcodes
=
context
.
popcatcodes
51
local
ctx_xmlsetup
=
context
.
xmlsetup
52
local
ctx_xmlprocessbuffer
=
context
.
xmlprocessbuffer
53 54
-- -- -- namespace -- -- --
55 56
-- This is tricky: we have stored and initialized already some of
57
-- the job.registered tables so we have a forward reference!
58 59
structures
=
structures
or
{
}
60
local
structures
=
structures
61 62
structures
.
blocks
=
structures
.
blocks
or
{
}
63
structures
.
sections
=
structures
.
sections
or
{
}
64
structures
.
pages
=
structures
.
pages
or
{
}
65
structures
.
registers
=
structures
.
registers
or
{
}
66
structures
.
references
=
structures
.
references
or
{
}
67
structures
.
lists
=
structures
.
lists
or
{
}
68
structures
.
helpers
=
structures
.
helpers
or
{
}
69
structures
.
documents
=
structures
.
documents
or
{
}
70
structures
.
notes
=
structures
.
notes
or
{
}
71
structures
.
descriptions
=
structures
.
descriptions
or
{
}
72
structures
.
itemgroups
=
structures
.
itemgroups
or
{
}
73
structures
.
specials
=
structures
.
specials
or
{
}
74
structures
.
counters
=
structures
.
counters
or
{
}
75
structures
.
tags
=
structures
.
tags
or
{
}
76
structures
.
formulas
=
structures
.
formulas
or
{
}
-- not used but reserved
77
structures
.
sets
=
structures
.
sets
or
{
}
78
structures
.
marks
=
structures
.
marks
or
{
}
79
structures
.
floats
=
structures
.
floats
or
{
}
80
structures
.
synonyms
=
structures
.
synonyms
or
{
}
81 82
--~ table.print(structures)
83 84
local
processors
=
typesetters
.
processors
85 86
-- -- -- specials -- -- --
87 88
-- we can store information and get back a reference; this permits
89
-- us to store rather raw data in references
90 91
local
specials
=
structures
.
specials
92 93
local
collected
=
allocate
(
)
94
local
tobesaved
=
allocate
(
)
95 96
specials
.
collected
=
collected
97
specials
.
tobesaved
=
tobesaved
98 99
local
function
initializer
(
)
100
collected
=
specials
.
collected
101
tobesaved
=
specials
.
tobesaved
102
end
103 104
if
job
then
105
job
.
register
(
'
structures.specials.collected
'
,
tobesaved
,
initializer
)
106
end
107 108
function
specials
.
store
(
class
,
data
)
109
if
class
and
data
then
110
local
s
=
tobesaved
[
class
]
111
if
not
s
then
112
s
=
{
}
113
tobesaved
[
class
]
=
s
114
end
115
s
[
#
s
+
1
]
=
data
116
context
(
#
s
)
117
else
118
context
(
0
)
119
end
120
end
121 122
function
specials
.
retrieve
(
class
,
n
)
123
if
class
and
n
then
124
local
c
=
collected
[
class
]
125
return
c
and
c
[
n
]
126
end
127
end
128 129
-- -- -- helpers -- -- --
130 131
local
helpers
=
structures
.
helpers
132 133
-- function helpers.touserdata(str)
134
-- local hash = str and str ~= "" and settings_to_hash(str)
135
-- if hash and next(hash) then
136
-- return hash
137
-- end
138
-- end
139 140
function
helpers
.
touserdata
(
data
)
141
if
type
(
data
)
=
=
"
string
"
then
142
if
data
=
=
"
"
then
143
return
nil
144
else
145
data
=
settings_to_hash
(
data
)
146
end
147
end
148
if
data
and
next
(
data
)
then
149
return
data
150
end
151
end
152 153
local
function
simplify
(
d
,
nodefault
)
154
if
d
then
155
local
t
=
{
}
156
for
k
,
v
in
next
,
d
do
157
local
tv
=
type
(
v
)
158
if
tv
=
=
"
table
"
then
159
if
next
(
v
)
then
160
t
[
k
]
=
simplify
(
v
)
161
end
162
elseif
tv
=
=
"
string
"
then
163
if
v
~
=
"
"
then
164
t
[
k
]
=
v
165
end
166
elseif
tv
=
=
"
boolean
"
then
167
if
v
then
168
t
[
k
]
=
v
169
end
170
else
171
t
[
k
]
=
v
172
end
173
end
174
return
next
(
t
)
and
t
175
elseif
nodefault
then
176
return
nil
177
else
178
return
{
}
179
end
180
end
181 182
-- we only care about the tuc file so this would do too:
183
--
184
-- local function simplify(d,nodefault)
185
-- if d then
186
-- for k, v in next, d do
187
-- local tv = type(v)
188
-- if tv == "string" then
189
-- if v == "" or v == "default" then
190
-- d[k] = nil
191
-- end
192
-- elseif tv == "table" then
193
-- if next(v) then
194
-- simplify(v)
195
-- end
196
-- elseif tv == "boolean" then
197
-- if not v then
198
-- d[k] = nil
199
-- end
200
-- end
201
-- end
202
-- return d
203
-- elseif nodefault then
204
-- return nil
205
-- else
206
-- return { }
207
-- end
208
-- end
209 210
helpers
.
simplify
=
simplify
211 212
function
helpers
.
merged
(
...
)
213
local
t
=
{
}
214
for
k
=
1
,
select
(
"
#
"
,
...
)
do
215
local
v
=
select
(
k
,
...
)
216
if
v
and
v
~
=
"
"
and
not
t
[
k
]
then
217
t
[
k
]
=
v
218
end
219
end
220
return
t
221
end
222 223
local
tags
=
{
224
generic
=
"
ctx:genericentry
"
,
225
section
=
"
ctx:sectionentry
"
,
226
entry
=
"
ctx:registerentry
"
,
227
}
228 229
-- We had the following but it overloads the main document so it's a no-go as we
230
-- no longer push and pop. So now we use the tag as buffername, namespace and also
231
-- (optionally) as a setups to be applied but keep in mind that document setups
232
-- also get applied (when they use #1's).
233
--
234
-- local command = formatters["\\xmlprocessbuffer{%s}{%s}{}"](metadata.xmlroot or "main",tag)
235 236
local
overload_catcodes
=
true
237 238
directives
.
register
(
"
typesetters.processors.overloadcatcodes
"
,
function
(
v
)
239
-- number | true | false | string
240
overload_catcodes
=
v
241
end
)
242 243
local
experiment
=
true
244 245
function
helpers
.
title
(
title
,
metadata
)
-- coding is xml is rather old and not that much needed now
246
if
title
and
title
~
=
"
"
then
-- so it might disappear
247
if
metadata
then
248
local
xmlsetup
=
metadata
.
xmlsetup
249
if
metadata
.
coding
=
=
"
xml
"
then
250
-- title can contain raw xml
251
local
tag
=
tags
[
metadata
.
kind
]
or
tags
.
generic
252
local
xmldata
=
formatters
[
"
<?xml version='1.0'?><%s>%s</%s>
"
]
(
tag
,
title
,
tag
)
253
if
not
experiment
then
254
buffers
.
assign
(
tag
,
xmldata
)
255
end
256
if
trace_processors
then
257
report_processors
(
"
putting xml data in buffer: %s
"
,
xmldata
)
258
report_processors
(
"
processing buffer with setup %a and tag %a
"
,
xmlsetup
,
tag
)
259
end
260
if
experiment
then
261
-- the question is: will this be forgotten ... better store in a via file
262
local
xmltable
=
xmlconvert
(
"
temp
"
,
xmldata
or
"
"
)
263
xmlstore
(
"
temp
"
,
xmltable
)
264
ctx_xmlsetup
(
"
temp
"
,
xmlsetup
or
"
"
)
265
else
266
ctx_xmlprocessbuffer
(
"
dummy
"
,
tag
,
xmlsetup
or
"
"
)
267
end
268
elseif
xmlsetup
then
-- title is reference to node (so \xmlraw should have been used)
269
if
trace_processors
then
270
report_processors
(
"
feeding xmlsetup %a using node %a
"
,
xmlsetup
,
title
)
271
end
272
ctx_xmlsetup
(
title
,
metadata
.
xmlsetup
)
273
else
274
local
catcodes
=
metadata
.
catcodes
275
if
overload_catcodes
=
=
false
then
276
if
trace_processors
then
277
report_processors
(
"
catcodetable %a, text %a
"
,
catcodes
,
title
)
278
end
279
--
280
-- context.sprint(catcodes,title)
281
--
282
-- doesn't work when a newline is in there \section{Test\ A} so we do
283
-- it this way:
284
--
285
ctx_pushcatcodes
(
catcodes
)
286
context
(
title
)
287
ctx_popcatcodes
(
)
288
elseif
overload_catcodes
=
=
true
then
289
if
catcodes
=
=
notcatcodes
or
catcodes
=
=
xmlcatcodes
then
290
-- when was this needed
291
if
trace_processors
then
292
report_processors
(
"
catcodetable %a, overloads %a, text %a
"
,
ctxcatcodes
,
catcodes
,
title
)
293
end
294
context
(
title
)
295
else
296
ctx_pushcatcodes
(
catcodes
)
297
context
(
title
)
298
ctx_popcatcodes
(
)
299
end
300
else
301
if
trace_processors
then
302
report_processors
(
"
catcodetable %a, overloads %a, text %a
"
,
catcodes
,
overload_catcodes
,
title
)
303
end
304
ctx_pushcatcodes
(
overload_catcodes
)
305
context
(
title
)
306
ctx_popcatcodes
(
)
307
end
308
end
309
else
310
-- no catcode switch, was: texsprint(title)
311
context
(
title
)
312
end
313
end
314
end
315 316
-- -- -- sets -- -- --
317 318
local
sets
=
structures
.
sets
319 320
sets
.
setlist
=
sets
.
setlist
or
{
}
321 322
storage
.
register
(
"
structures/sets/setlist
"
,
structures
.
sets
.
setlist
,
"
structures.sets.setlist
"
)
323 324
local
setlist
=
sets
.
setlist
325 326
function
sets
.
define
(
namespace
,
name
,
values
,
default
,
numbers
)
327
local
dn
=
setlist
[
namespace
]
328
if
not
dn
then
329
dn
=
{
}
330
setlist
[
namespace
]
=
dn
331
end
332
if
values
=
=
"
"
then
333
dn
[
name
]
=
{
{
}
,
default
}
334
else
335
local
split
=
settings_to_array
(
values
)
336
if
numbers
then
337
-- convert to numbers (e.g. for reset)
338
for
i
=
1
,
#
split
do
339
split
[
i
]
=
tonumber
(
split
[
i
]
)
or
0
340
end
341
end
342
dn
[
name
]
=
{
split
,
default
}
343
end
344
end
345 346
function
sets
.
getall
(
namespace
,
block
,
name
)
347
local
ds
=
setlist
[
namespace
]
348
if
not
ds
then
349
return
{
}
350
else
351
local
dn
352
if
block
and
block
~
=
"
"
then
353
dn
=
ds
[
block
.
.
"
:
"
.
.
name
]
or
ds
[
name
]
or
ds
[
block
]
or
ds
.
default
354
else
355
dn
=
ds
[
name
]
or
ds
.
default
356
end
357
return
(
dn
and
dn
[
1
]
)
or
{
}
358
end
359
end
360 361
-- messy (will be another keyword, fixedconversion) .. needs to be documented too
362
-- maybe we should cache
363 364
local
splitter
=
lpeg
.
splitat
(
"
::
"
)
365 366
function
sets
.
get
(
namespace
,
block
,
name
,
level
,
default
)
-- check if name is passed
367
--fixed::R:a: ...
368
local
kind
,
rest
=
lpegmatch
(
splitter
,
name
)
369
if
rest
and
kind
=
=
"
fixed
"
then
-- fixed::n,a,i
370
local
s
=
settings_to_array
(
rest
)
371
return
s
[
level
]
or
s
[
#
s
]
or
default
372
end
373
--
374
local
ds
=
setlist
[
namespace
]
375
if
not
ds
then
376
return
default
377
end
378
local
dn
379
if
name
and
name
~
=
"
"
then
380
if
block
and
block
~
=
"
"
then
381
dn
=
ds
[
block
.
.
"
:
"
.
.
name
]
or
ds
[
name
]
or
ds
[
block
]
or
ds
.
default
382
else
383
dn
=
ds
[
name
]
or
ds
.
default
384
end
385
else
386
if
block
and
block
~
=
"
"
then
387
dn
=
ds
[
block
]
or
ds
[
block
.
.
"
:default
"
]
or
ds
.
default
388
else
389
dn
=
ds
.
default
390
end
391
end
392
if
not
dn
then
393
return
default
394
end
395
local
dl
=
dn
[
1
]
[
level
]
396
return
dl
or
dn
[
2
]
or
default
397
end
398 399
-- interface
400 401
interfaces
.
implement
{
402
name
=
"
definestructureset
"
,
403
actions
=
sets
.
define
,
404
arguments
=
{
"
string
"
,
"
string
"
,
"
string
"
,
"
string
"
,
"
boolean
"
}
405
}
406