back-exp.lua /size: 150 Kb    last modification: 2020-07-01 14:35
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
back-exp
'
]
=
{
2
version
=
1
.
001
,
3
comment
=
"
companion to back-exp.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
-- Todo: share properties more with tagged pdf (or thge reverse)
10 11
-- Because we run into the 200 local limit we quite some do .. end wrappers .. not always
12
-- that nice but it has to be.
13 14
-- Experiments demonstrated that mapping to <div> and classes is messy because we have to
15
-- package attributes (some 30) into one set of (space seperatated but prefixed classes)
16
-- which only makes things worse .. so if you want something else, use xslt to get there.
17 18
-- language -> only mainlanguage, local languages should happen through start/stoplanguage
19
-- tocs/registers -> maybe add a stripper (i.e. just don't flush entries in final tree)
20
-- footnotes -> css 3
21
-- bodyfont -> in styles.css
22 23
-- Because we need to look ahead we now always build a tree (this was optional in
24
-- the beginning). The extra overhead in the frontend is neglectable.
25
--
26
-- We can optimize the code ... currently the overhead is some 10% for xml + html so
27
-- there is no hurry.
28 29
-- todo: move critital formatters out of functions
30
-- todo: delay loading (apart from basic tag stuff)
31 32
-- problem : too many local variables
33 34
-- check setting __i__
35 36
local
next
,
type
,
tonumber
=
next
,
type
,
tonumber
37
local
sub
,
gsub
,
match
=
string
.
sub
,
string
.
gsub
,
string
.
match
38
local
validstring
=
string
.
valid
39
local
lpegmatch
=
lpeg
.
match
40
local
utfchar
,
utfvalues
,
utflen
=
utf
.
char
,
utf
.
values
,
utf
.
len
41
local
concat
,
insert
,
remove
,
merge
,
sort
=
table
.
concat
,
table
.
insert
,
table
.
remove
,
table
.
merge
,
table
.
sort
42
local
sortedhash
,
sortedkeys
=
table
.
sortedhash
,
table
.
sortedkeys
43
local
formatters
=
string
.
formatters
44
local
todimen
=
number
.
todimen
45
local
replacetemplate
=
utilities
.
templates
.
replace
46 47
local
trace_export
=
false
trackers
.
register
(
"
export.trace
"
,
function
(
v
)
trace_export
=
v
end
)
48
local
trace_spacing
=
false
trackers
.
register
(
"
export.trace.spacing
"
,
function
(
v
)
trace_spacing
=
v
end
)
49
local
trace_details
=
false
trackers
.
register
(
"
export.trace.details
"
,
function
(
v
)
trace_details
=
v
end
)
50 51
local
less_state
=
false
directives
.
register
(
"
export.lessstate
"
,
function
(
v
)
less_state
=
v
end
)
52
local
show_comment
=
true
directives
.
register
(
"
export.comment
"
,
function
(
v
)
show_comment
=
v
end
)
53 54
show_comment
=
false
-- figure out why break comment
55 56
-- maybe we will also support these:
57
--
58
-- local css_hyphens = false directives.register("export.css.hyphens", function(v) css_hyphens = v end)
59
-- local css_textalign = false directives.register("export.css.textalign", function(v) css_textalign = v end)
60
-- local css_bodyfontsize = false directives.register("export.css.bodyfontsize", function(v) css_bodyfontsize = v end)
61
-- local css_textwidth = false directives.register("export.css.textwidth", function(v) css_textwidth = v end)
62 63
local
report_export
=
logs
.
reporter
(
"
backend
"
,
"
export
"
)
64 65
local
nodes
=
nodes
66
local
attributes
=
attributes
67 68
local
variables
=
interfaces
.
variables
69
local
v_yes
=
variables
.
yes
70
local
v_no
=
variables
.
no
71
local
v_xml
=
variables
.
xml
72
local
v_hidden
=
variables
.
hidden
73 74
local
implement
=
interfaces
.
implement
75 76
local
included
=
backends
.
included
77 78
local
settings_to_array
=
utilities
.
parsers
.
settings_to_array
79
local
settings_to_hash
=
utilities
.
parsers
.
settings_to_hash
80 81
local
setmetatableindex
=
table
.
setmetatableindex
82
local
tasks
=
nodes
.
tasks
83
local
fontchar
=
fonts
.
hashes
.
characters
84
local
fontquads
=
fonts
.
hashes
.
quads
85
local
languagenames
=
languages
.
numbers
86 87
local
texgetcount
=
tex
.
getcount
88 89
local
references
=
structures
.
references
90
local
structurestags
=
structures
.
tags
91
local
taglist
=
structurestags
.
taglist
92
local
specifications
=
structurestags
.
specifications
93
local
properties
=
structurestags
.
properties
94
local
locatedtag
=
structurestags
.
locatedtag
95 96
structurestags
.
usewithcare
=
{
}
97 98
local
starttiming
=
statistics
.
starttiming
99
local
stoptiming
=
statistics
.
stoptiming
100 101
local
characterdata
=
characters
.
data
102
local
overloads
=
fonts
.
mappings
.
overloads
103 104
-- todo: more locals (and optimize)
105 106
local
exportversion
=
"
0.35
"
107
local
mathmlns
=
"
http://www.w3.org/1998/Math/MathML
"
108
local
contextns
=
"
http://www.contextgarden.net/context/export
"
-- whatever suits
109
local
cssnamespaceurl
=
"
@namespace context url('%namespace%') ;
"
110
local
cssnamespace
=
"
context|
"
111
----- cssnamespacenop = "/* no namespace */"
112 113
local
usecssnamespace
=
false
114 115
local
nofcurrentcontent
=
0
-- so we don't free (less garbage collection)
116
local
currentcontent
=
{
}
117
local
currentnesting
=
nil
118
local
currentattribute
=
nil
119
local
last
=
nil
120
local
currentparagraph
=
nil
121 122
local
noftextblocks
=
0
123 124
----- hyphencode = 0xAD
125
local
hyphen
=
utfchar
(
0xAD
)
-- todo: also emdash etc
126
local
tagsplitter
=
structurestags
.
patterns
.
splitter
127
----- colonsplitter = lpeg.splitat(":")
128
----- dashsplitter = lpeg.splitat("-")
129
local
threshold
=
65536
130
local
indexing
=
false
131
local
keephyphens
=
false
132
local
exportproperties
=
false
133 134
local
finetuning
=
{
}
135 136
local
treestack
=
{
}
137
local
nesting
=
{
}
138
local
currentdepth
=
0
139 140
local
wrapups
=
{
}
141 142
local
tree
=
{
data
=
{
}
,
fulltag
=
=
"
root
"
}
-- root
143
local
treeroot
=
tree
144
local
treehash
=
{
}
145
local
extras
=
{
}
146
local
checks
=
{
}
147
local
fixes
=
{
}
148
local
finalizers
=
{
}
149
local
nofbreaks
=
0
150
local
used
=
{
}
151
local
exporting
=
false
152
local
restart
=
false
153
local
specialspaces
=
{
[
0x20
]
=
"
"
}
-- for conversion
154
local
somespace
=
{
[
0x20
]
=
true
,
[
"
"
]
=
true
}
-- for testing
155
local
entities
=
{
[
"
&
"
]
=
"
&amp;
"
,
[
"
>
"
]
=
"
&gt;
"
,
[
"
<
"
]
=
"
&lt;
"
}
156
local
attribentities
=
{
[
"
&
"
]
=
"
&amp;
"
,
[
"
>
"
]
=
"
&gt;
"
,
[
"
<
"
]
=
"
&lt;
"
,
[
'
"
'
]
=
"
quot;
"
}
157 158
local
p_entity
=
lpeg
.
replacer
(
entities
)
-- was: entityremapper = utf.remapper(entities)
159
local
p_attribute
=
lpeg
.
replacer
(
attribentities
)
160
local
p_stripper
=
lpeg
.
patterns
.
stripper
161
local
p_escaped
=
lpeg
.
patterns
.
xml
.
escaped
162 163
local
f_tagid
=
formatters
[
"
%s-%04i
"
]
164 165
-- local alignmapping = {
166
-- flushright = "right",
167
-- middle = "center",
168
-- flushleft = "left",
169
-- }
170 171
local
defaultnature
=
"
mixed
"
-- "inline"
172 173
setmetatableindex
(
used
,
function
(
t
,
k
)
174
if
k
then
175
local
v
=
{
}
176
t
[
k
]
=
v
177
return
v
178
end
179
end
)
180 181
local
f_entity
=
formatters
[
"
&#x%X;
"
]
182
local
f_attribute
=
formatters
[
"
%s=%q
"
]
183
local
f_property
=
formatters
[
"
%s%s=%q
"
]
184 185
setmetatableindex
(
specialspaces
,
function
(
t
,
k
)
186
local
v
=
utfchar
(
k
)
187
t
[
k
]
=
v
188
entities
[
v
]
=
f_entity
(
k
)
189
somespace
[
k
]
=
true
190
somespace
[
v
]
=
true
191
return
v
192
end
)
193 194 195
local
namespaced
=
{
196
-- filled on
197
}
198 199
local
namespaces
=
{
200
msubsup
=
"
m
"
,
201
msub
=
"
m
"
,
202
msup
=
"
m
"
,
203
mn
=
"
m
"
,
204
mi
=
"
m
"
,
205
ms
=
"
m
"
,
206
mo
=
"
m
"
,
207
mtext
=
"
m
"
,
208
mrow
=
"
m
"
,
209
mfrac
=
"
m
"
,
210
mroot
=
"
m
"
,
211
msqrt
=
"
m
"
,
212
munderover
=
"
m
"
,
213
munder
=
"
m
"
,
214
mover
=
"
m
"
,
215
merror
=
"
m
"
,
216
math
=
"
m
"
,
217
mrow
=
"
m
"
,
218
mtable
=
"
m
"
,
219
mtr
=
"
m
"
,
220
mtd
=
"
m
"
,
221
mfenced
=
"
m
"
,
222
maction
=
"
m
"
,
223
mspace
=
"
m
"
,
224
-- only when testing
225
mstacker
=
"
m
"
,
226
mstackertop
=
"
m
"
,
227
mstackermid
=
"
m
"
,
228
mstackerbot
=
"
m
"
,
229
}
230 231
setmetatableindex
(
namespaced
,
function
(
t
,
k
)
232
if
k
then
233
local
namespace
=
namespaces
[
k
]
234
local
v
=
namespace
and
namespace
.
.
"
:
"
.
.
k
or
k
235
t
[
k
]
=
v
236
return
v
237
end
238
end
)
239 240
local
function
attribute
(
key
,
value
)
241
if
value
and
value
~
=
"
"
then
242
return
f_attribute
(
key
,
lpegmatch
(
p_attribute
,
value
)
)
243
else
244
return
"
"
245
end
246
end
247 248
local
function
setattribute
(
di
,
key
,
value
,
escaped
)
249
if
value
and
value
~
=
"
"
then
250
local
a
=
di
.
attributes
251
if
escaped
then
252
value
=
lpegmatch
(
p_escaped
,
value
)
253
end
254
if
not
a
then
255
di
.
attributes
=
{
[
key
]
=
value
}
256
else
257
a
[
key
]
=
value
258
end
259
end
260
end
261 262
local
listdata
=
{
}
-- this has to be done otherwise: each element can just point back to ...
263 264
function
wrapups
.
hashlistdata
(
)
265
local
c
=
structures
.
lists
.
collected
266
for
i
=
1
,
#
c
do
267
local
ci
=
c
[
i
]
268
local
tag
=
ci
.
references
.
tag
269
if
tag
then
270
local
m
=
ci
.
metadata
271
local
t
=
m
.
kind
.
.
"
>
"
.
.
tag
-- todo: use internal (see strc-lst.lua where it's set)
272
listdata
[
t
]
=
ci
273
end
274
end
275
end
276 277
function
structurestags
.
setattributehash
(
attr
,
key
,
value
)
-- public hash
278
local
specification
=
taglist
[
attr
]
279
if
specification
then
280
specification
[
key
]
=
value
281
else
282
-- some kind of error
283
end
284
end
285 286
local
usedstyles
=
{
}
287 288
local
namespacetemplate
=
[[
289/* %what% for file %filename% */ 290 291%cssnamespaceurl% 292
]]
293 294
do
295 296
-- experiment: styles and images
297
--
298
-- officially we should convert to bp but we round anyway
299 300
-- /* padding : ; */
301
-- /* text-justify : inter-word ; */
302
-- /* text-align : justify ; */
303 304
local
documenttemplate
=
[[
305document, 306%namespace%div.document { 307 font-size : %size% !important ; 308 max-width : %width% !important ; 309 text-align : %align% !important ; 310 hyphens : %hyphens% !important ; 311}
]]
312 313
local
styletemplate
=
[[
314%element%[detail="%detail%"], 315%namespace%div.%element%.%detail% { 316 display : inline ; 317 font-style : %style% ; 318 font-variant : %variant% ; 319 font-weight : %weight% ; 320 font-family : %family% ; 321 color : %color% ; 322}
]]
323 324
local
numbertoallign
=
{
325
[
0
]
=
"
justify
"
,
[
"
0
"
]
=
"
justify
"
,
[
variables
.
normal
]
=
"
justify
"
,
326
[
1
]
=
"
right
"
,
[
"
1
"
]
=
"
right
"
,
[
variables
.
flushright
]
=
"
right
"
,
327
[
2
]
=
"
center
"
,
[
"
2
"
]
=
"
center
"
,
[
variables
.
middle
]
=
"
center
"
,
328
[
3
]
=
"
left
"
,
[
"
3
"
]
=
"
left
"
,
[
variables
.
flushleft
]
=
"
left
"
,
329
}
330 331
function
wrapups
.
allusedstyles
(
basename
)
332
local
result
=
{
replacetemplate
(
namespacetemplate
,
{
333
what
=
"
styles
"
,
334
filename
=
basename
,
335
namespace
=
contextns
,
336
-- cssnamespaceurl = usecssnamespace and cssnamespaceurl or cssnamespacenop,
337
cssnamespaceurl
=
cssnamespaceurl
,
338
}
,
false
,
true
)
}
339
--
340
local
bodyfont
=
finetuning
.
bodyfont
341
local
width
=
finetuning
.
width
342
local
hyphen
=
finetuning
.
hyphen
343
local
align
=
finetuning
.
align
344
--
345
if
type
(
bodyfont
)
=
=
"
number
"
then
346
bodyfont
=
todimen
(
bodyfont
)
347
else
348
bodyfont
=
"
12pt
"
349
end
350
if
type
(
width
)
=
=
"
number
"
then
351
width
=
todimen
(
width
)
or
"
50em
"
352
else
353
width
=
"
50em
"
354
end
355
if
hyphen
=
=
v_yes
then
356
hyphen
=
"
manual
"
357
else
358
hyphen
=
"
inherited
"
359
end
360
if
align
then
361
align
=
numbertoallign
[
align
]
362
end
363
if
not
align
then
364
align
=
hyphen
and
"
justify
"
or
"
inherited
"
365
end
366
--
367
result
[
#
result
+
1
]
=
replacetemplate
(
documenttemplate
,
{
368
size
=
bodyfont
,
369
width
=
width
,
370
align
=
align
,
371
hyphens
=
hyphen
372
}
)
373
--
374
local
colorspecification
=
xml
.
css
.
colorspecification
375
local
fontspecification
=
xml
.
css
.
fontspecification
376
for
element
,
details
in
sortedhash
(
usedstyles
)
do
377
for
detail
,
data
in
sortedhash
(
details
)
do
378
local
s
=
fontspecification
(
data
.
style
)
379
local
c
=
colorspecification
(
data
.
color
)
380
detail
=
gsub
(
detail
,
"
[^A-Za-z0-9]+
"
,
"
-
"
)
381
result
[
#
result
+
1
]
=
replacetemplate
(
styletemplate
,
{
382
namespace
=
usecssnamespace
and
cssnamespace
or
"
"
,
383
element
=
element
,
384
detail
=
detail
,
385
style
=
s
.
style
or
"
inherit
"
,
386
variant
=
s
.
variant
or
"
inherit
"
,
387
weight
=
s
.
weight
or
"
inherit
"
,
388
family
=
s
.
family
or
"
inherit
"
,
389
color
=
c
or
"
inherit
"
,
390
display
=
s
.
display
and
"
block
"
or
nil
,
391
}
)
392
end
393
end
394
return
concat
(
result
,
"
\n\n
"
)
395
end
396 397
end
398 399
local
usedimages
=
{
}
400 401
do
402 403
local
imagetemplate
=
[[
404%element%[id="%id%"], %namespace%div.%element%[id="%id%"] { 405 display : block ; 406 background-image : url('%url%') ; 407 background-size : 100%% auto ; 408 background-repeat : no-repeat ; 409 width : %width% ; 410 height : %height% ; 411}
]]
412 413
local
f_svgname
=
formatters
[
"
%s.svg
"
]
414
local
f_svgpage
=
formatters
[
"
%s-page-%s.svg
"
]
415
local
collected
=
{
}
416 417
local
function
usedname
(
name
,
page
)
418
if
file
.
suffix
(
name
)
=
=
"
pdf
"
then
419
-- temp hack .. we will have a remapper
420
if
page
and
page
>
1
then
421
name
=
f_svgpage
(
file
.
nameonly
(
name
)
,
page
)
422
else
423
name
=
f_svgname
(
file
.
nameonly
(
name
)
)
424
end
425
end
426
local
scheme
=
url
.
hasscheme
(
name
)
427
if
not
scheme
or
scheme
=
=
"
file
"
then
428
-- or can we just use the name ?
429
return
file
.
join
(
"
../images
"
,
file
.
basename
(
url
.
filename
(
name
)
)
)
430
else
431
return
name
432
end
433
end
434 435
function
wrapups
.
allusedimages
(
basename
)
436
local
result
=
{
replacetemplate
(
namespacetemplate
,
{
437
what
=
"
images
"
,
438
filename
=
basename
,
439
namespace
=
contextns
,
440
-- cssnamespaceurl = usecssnamespace and cssnamespaceurl or "",
441
cssnamespaceurl
=
cssnamespaceurl
,
442
}
,
false
,
true
)
}
443
for
element
,
details
in
sortedhash
(
usedimages
)
do
444
for
detail
,
data
in
sortedhash
(
details
)
do
445
local
name
=
data
.
name
446
local
page
=
tonumber
(
data
.
page
)
or
1
447
local
spec
=
{
448
element
=
element
,
449
id
=
data
.
id
,
450
name
=
name
,
451
page
=
page
,
452
url
=
usedname
(
name
,
page
)
,
453
width
=
data
.
width
,
454
height
=
data
.
height
,
455
used
=
data
.
used
,
456
namespace
=
usecssnamespace
and
cssnamespace
or
"
"
,
457
}
458
result
[
#
result
+
1
]
=
replacetemplate
(
imagetemplate
,
spec
)
459
collected
[
detail
]
=
spec
460
end
461
end
462
return
concat
(
result
,
"
\n\n
"
)
463
end
464 465
function
wrapups
.
uniqueusedimages
(
)
-- todo: combine these two
466
return
collected
467
end
468 469
end
470 471
--
472 473
properties
.
vspace
=
{
export
=
"
break
"
,
nature
=
"
display
"
}
474
----------------- = { export = "pagebreak", nature = "display" }
475 476
local
function
makebreaklist
(
list
)
477
nofbreaks
=
nofbreaks
+
1
478
local
t
=
{
}
479
local
l
=
list
and
list
.
taglist
480
if
l
then
481
for
i
=
1
,
#
list
do
482
t
[
i
]
=
l
[
i
]
483
end
484
end
485
t
[
#
t
+
1
]
=
"
break>
"
.
.
nofbreaks
-- maybe no number or 0
486
return
{
taglist
=
t
}
487
end
488 489
local
breakattributes
=
{
490
type
=
"
collapse
"
491
}
492 493
local
function
makebreaknode
(
attributes
)
-- maybe no fulltag
494
nofbreaks
=
nofbreaks
+
1
495
return
{
496
tg
=
"
break
"
,
497
fulltag
=
"
break>
"
.
.
nofbreaks
,
498
n
=
nofbreaks
,
499
element
=
"
break
"
,
500
nature
=
"
display
"
,
501
attributes
=
attributes
or
nil
,
502
-- data = { }, -- not needed
503
-- attribute = 0, -- not needed
504
-- parnumber = 0,
505
}
506
end
507 508
do
509 510
local
fields
=
{
"
title
"
,
"
subtitle
"
,
"
author
"
,
"
keywords
"
,
"
url
"
,
"
version
"
}
511 512
local
ignoredelements
=
false
513 514
local
function
checkdocument
(
root
)
515
local
data
=
root
.
data
516
if
data
then
517
for
i
=
1
,
#
data
do
518
local
di
=
data
[
i
]
519
local
tg
=
di
.
tg
520
if
tg
=
=
"
noexport
"
then
521
local
s
=
specifications
[
di
.
fulltag
]
522
local
u
=
s
and
s
.
userdata
523
if
u
then
524
local
comment
=
u
.
comment
525
if
comment
then
526
di
.
element
=
"
comment
"
527
di
.
data
=
{
{
content
=
comment
}
}
528
u
.
comment
=
nil
529
else
530
data
[
i
]
=
false
531
end
532
else
533
data
[
i
]
=
false
534
end
535
elseif
di
.
content
then
536
-- okay
537
elseif
tg
=
=
"
ignore
"
then
538
di
.
element
=
"
"
539
checkdocument
(
di
)
540
elseif
ignoredelements
and
ignoredelements
[
tg
]
then
541
di
.
element
=
"
"
542
checkdocument
(
di
)
543
else
544
checkdocument
(
di
)
-- new, else no noexport handling
545
end
546
end
547
end
548
end
549 550
function
extras
.
document
(
di
,
element
,
n
,
fulltag
)
551
setattribute
(
di
,
"
language
"
,
languagenames
[
texgetcount
(
"
mainlanguagenumber
"
)
]
)
552
if
not
less_state
then
553
setattribute
(
di
,
"
file
"
,
tex
.
jobname
)
554
if
included
.
date
then
555
setattribute
(
di
,
"
date
"
,
backends
.
timestamp
(
)
)
556
end
557
setattribute
(
di
,
"
context
"
,
environment
.
version
)
558
setattribute
(
di
,
"
version
"
,
exportversion
)
559
setattribute
(
di
,
"
xmlns:m
"
,
mathmlns
)
560
local
identity
=
interactions
.
general
.
getidentity
(
)
561
for
i
=
1
,
#
fields
do
562
local
key
=
fields
[
i
]
563
local
value
=
identity
[
key
]
564
if
value
and
value
~
=
"
"
then
565
setattribute
(
di
,
key
,
value
)
566
end
567
end
568
end
569
checkdocument
(
di
)
570
end
571 572
implement
{
573
name
=
"
ignoretagsinexport
"
,
574
arguments
=
"
string
"
,
575
actions
=
function
(
list
)
576
for
tag
in
string
.
gmatch
(
list
,
"
[a-z]+
"
)
do
577
if
ignoredelements
then
578
ignoredelements
[
tag
]
=
true
579
else
580
ignoredelements
=
{
[
tag
]
=
true
}
581
end
582
end
583
end
,
584
}
585 586
end
587 588
do
589 590
local
marginanchors
=
{
}
591
local
margincontent
=
{
}
592 593
implement
{
594
name
=
"
settagmargintext
"
,
595
arguments
=
"
integer
"
,
596
actions
=
function
(
n
)
597
marginanchors
[
locatedtag
(
"
margintext
"
)
]
=
n
598
end
599
}
600 601
implement
{
602
name
=
"
settagmarginanchor
"
,
603
arguments
=
"
integer
"
,
604
actions
=
function
(
n
)
605
marginanchors
[
locatedtag
(
"
marginanchor
"
)
]
=
n
606
end
607
}
608 609
function
checks
.
margintext
(
di
)
610
local
i
=
marginanchors
[
di
.
fulltag
]
611
margincontent
[
i
]
=
di
612
end
613 614
function
checks
.
marginanchor
(
di
)
615
local
i
=
marginanchors
[
di
.
fulltag
]
616
local
d
=
margincontent
[
i
]
617
--
618
di
.
attribute
=
d
.
attribute
619
di
.
data
=
d
.
data
620
di
.
detail
=
d
.
detail
621
di
.
element
=
d
.
element
622
di
.
fulltag
=
d
.
fulltag
623
di
.
nature
=
d
.
nature
624
di
.
samepar
=
true
625
di
.
tg
=
d
.
tg
626
--
627
d
.
skip
=
"
ignore
"
628
end
629 630
end
631 632
do
633 634
local
symbols
=
{
}
635 636
function
structurestags
.
settagdelimitedsymbol
(
symbol
)
637
symbols
[
locatedtag
(
"
delimitedsymbol
"
)
]
=
{
638
symbol
=
symbol
,
639
}
640
end
641 642
function
extras
.
delimitedsymbol
(
di
,
element
,
n
,
fulltag
)
643
local
hash
=
symbols
[
fulltag
]
644
if
hash
then
645
setattribute
(
di
,
"
symbol
"
,
hash
.
symbol
or
nil
)
646
end
647
end
648 649
end
650 651
do
652 653
local
symbols
=
{
}
654 655
function
structurestags
.
settagsubsentencesymbol
(
symbol
)
656
symbols
[
locatedtag
(
"
subsentencesymbol
"
)
]
=
{
657
symbol
=
symbol
,
658
}
659
end
660 661
function
extras
.
subsentencesymbol
(
di
,
element
,
n
,
fulltag
)
662
local
hash
=
symbols
[
fulltag
]
663
if
hash
then
664
setattribute
(
di
,
"
symbol
"
,
hash
.
symbol
or
nil
)
665
end
666
end
667 668
end
669 670
do
671 672
local
itemgroups
=
{
}
673 674
function
structurestags
.
setitemgroup
(
packed
,
level
,
symbol
)
675
itemgroups
[
locatedtag
(
"
itemgroup
"
)
]
=
{
676
packed
=
packed
,
677
symbol
=
symbol
,
678
level
=
level
,
679
}
680
end
681 682
function
structurestags
.
setitem
(
kind
)
683
itemgroups
[
locatedtag
(
"
item
"
)
]
=
{
684
kind
=
kind
,
685
}
686
end
687 688
function
extras
.
itemgroup
(
di
,
element
,
n
,
fulltag
)
689
local
hash
=
itemgroups
[
fulltag
]
690
if
hash
then
691
setattribute
(
di
,
"
packed
"
,
hash
.
packed
and
"
yes
"
or
nil
)
692
setattribute
(
di
,
"
symbol
"
,
hash
.
symbol
)
693
setattribute
(
di
,
"
level
"
,
hash
.
level
)
694
end
695
end
696 697
function
extras
.
item
(
di
,
element
,
n
,
fulltag
)
698
local
hash
=
itemgroups
[
fulltag
]
699
if
hash
then
700
local
kind
=
hash
.
kind
701
if
kind
and
kind
~
=
"
"
then
702
setattribute
(
di
,
"
kind
"
,
kind
)
703
end
704
end
705
end
706 707
end
708 709
do
710 711
function
fixes
.
linenumber
(
di
,
data
,
i
)
712
local
ni
=
data
[
i
+
1
]
713
if
ni
then
714
if
ni
.
data
then
715
while
true
do
716
local
d
=
ni
.
data
[
1
]
717
if
d
then
718
local
e
=
d
.
element
719
if
e
then
720
if
e
=
=
"
line
"
or
e
=
=
"
verbatimline
"
then
721
insert
(
d
.
data
,
1
,
di
)
722
data
[
i
]
=
false
723
return
724
else
725
ni
=
d
726
end
727
else
728
return
729
end
730
else
731
return
732
end
733
end
734
end
735
end
736
end
737 738
end
739 740
do
741 742
local
synonyms
=
{
}
743
local
sortings
=
{
}
744 745
function
structurestags
.
setsynonym
(
tag
)
746
synonyms
[
locatedtag
(
"
synonym
"
)
]
=
tag
747
end
748 749
function
extras
.
synonym
(
di
,
element
,
n
,
fulltag
)
750
local
tag
=
synonyms
[
fulltag
]
751
if
tag
then
752
setattribute
(
di
,
"
tag
"
,
tag
)
753
end
754
end
755 756
function
structurestags
.
setsorting
(
tag
)
757
sortings
[
locatedtag
(
"
sorting
"
)
]
=
tag
758
end
759 760
function
extras
.
sorting
(
di
,
element
,
n
,
fulltag
)
761
local
tag
=
sortings
[
fulltag
]
762
if
tag
then
763
setattribute
(
di
,
"
tag
"
,
tag
)
764
end
765
end
766 767
end
768 769
do
770 771
local
strippedtag
=
structurestags
.
strip
-- we assume global styles
772 773
local
highlight
=
{
}
774
local
construct
=
{
}
775 776
usedstyles
.
highlight
=
highlight
777
usedstyles
.
construct
=
construct
778 779
function
structurestags
.
sethighlight
(
name
,
style
,
color
,
mode
)
780
if
not
highlight
[
name
]
then
781
highlight
[
name
]
=
{
782
style
=
style
,
783
color
=
color
,
784
mode
=
mode
=
=
1
and
"
display
"
or
nil
,
785
}
786
end
787
end
788 789
function
structurestags
.
setconstruct
(
name
,
style
,
color
,
mode
)
790
if
not
construct
[
name
]
then
791
construct
[
name
]
=
{
792
style
=
style
,
793
color
=
color
,
794
mode
=
mode
=
=
1
and
"
display
"
or
nil
,
795
}
796
end
797
end
798 799
end
800 801
do
802 803
local
descriptions
=
{
}
804
local
symbols
=
{
}
805
local
linked
=
{
}
806 807
-- we could move the notation itself to the first reference (can be an option)
808 809
function
structurestags
.
setnotation
(
tag
,
n
)
-- needs checking (is tag needed)
810
-- we can also use the internals hash or list
811
local
nd
=
structures
.
notes
.
get
(
tag
,
n
)
812
if
nd
then
813
local
references
=
nd
.
references
814
descriptions
[
references
and
references
.
internal
]
=
locatedtag
(
"
description
"
)
815
end
816
end
817 818
function
structurestags
.
setnotationsymbol
(
tag
,
n
)
-- needs checking (is tag needed)
819
local
nd
=
structures
.
notes
.
get
(
tag
,
n
)
-- todo: use listdata instead
820
if
nd
then
821
local
references
=
nd
.
references
822
symbols
[
references
and
references
.
internal
]
=
locatedtag
(
"
descriptionsymbol
"
)
823
end
824
end
825 826
function
finalizers
.
descriptions
(
tree
)
827
local
n
=
0
828
for
id
,
tag
in
sortedhash
(
descriptions
)
do
829
local
sym
=
symbols
[
id
]
830
if
sym
then
831
n
=
n
+
1
832
linked
[
tag
]
=
n
833
linked
[
sym
]
=
n
834
end
835
end
836
end
837 838
function
extras
.
description
(
di
,
element
,
n
,
fulltag
)
839
local
id
=
linked
[
fulltag
]
840
if
id
then
841
setattribute
(
di
,
"
insert
"
,
id
)
842
end
843
end
844 845
function
extras
.
descriptionsymbol
(
di
,
element
,
n
,
fulltag
)
846
local
id
=
linked
[
fulltag
]
847
if
id
then
848
setattribute
(
di
,
"
insert
"
,
id
)
849
end
850
end
851 852
end
853 854
-- -- todo: ignore breaks
855
--
856
-- function extras.verbatimline(di,element,n,fulltag)
857
-- inspect(di)
858
-- end
859 860
do
861 862
local
f_id
=
formatters
[
"
%s-%s
"
]
863
local
image
=
{
}
864
usedimages
.
image
=
image
865 866
structurestags
.
usewithcare
.
images
=
image
867 868
function
structurestags
.
setfigure
(
name
,
used
,
page
,
width
,
height
,
label
)
869
local
fulltag
=
locatedtag
(
"
image
"
)
870
local
spec
=
specifications
[
fulltag
]
871
if
spec
then
872
local
page
=
tonumber
(
page
)
873
image
[
fulltag
]
=
{
874
id
=
f_id
(
spec
.
tagname
,
spec
.
tagindex
)
,
875
name
=
name
,
876
used
=
used
,
877
page
=
page
and
page
>
1
and
page
or
nil
,
878
width
=
todimen
(
width
,
"
cm
"
,
"
%0.3F%s
"
)
,
879
height
=
todimen
(
height
,
"
cm
"
,
"
%0.3F%s
"
)
,
880
label
=
label
,
881
}
882
else
883
-- we ignore images in layers in the background / pagebody
884
end
885
end
886 887
function
extras
.
image
(
di
,
element
,
n
,
fulltag
)
888
local
data
=
image
[
fulltag
]
889
if
data
then
890
setattribute
(
di
,
"
name
"
,
data
.
name
)
891
setattribute
(
di
,
"
page
"
,
data
.
page
)
892
setattribute
(
di
,
"
id
"
,
data
.
id
)
893
setattribute
(
di
,
"
width
"
,
data
.
width
)
894
setattribute
(
di
,
"
height
"
,
data
.
height
)
895
setattribute
(
di
,
"
label
"
,
data
.
height
)
896
end
897
end
898 899
end
900 901
do
902 903
local
combinations
=
{
}
904 905
function
structurestags
.
setcombination
(
nx
,
ny
)
906
combinations
[
locatedtag
(
"
combination
"
)
]
=
{
907
nx
=
nx
,
908
ny
=
ny
,
909
}
910
end
911 912
function
extras
.
combination
(
di
,
element
,
n
,
fulltag
)
913
local
data
=
combinations
[
fulltag
]
914
if
data
then
915
setattribute
(
di
,
"
nx
"
,
data
.
nx
)
916
setattribute
(
di
,
"
ny
"
,
data
.
ny
)
917
end
918
end
919 920
end
921 922
-- quite some code deals with exporting references --
923 924
-- links:
925
--
926
-- url :
927
-- file :
928
-- internal : automatic location
929
-- location : named reference
930 931
-- references:
932
--
933
-- implicit : automatic reference
934
-- explicit : named reference
935 936
local
evaluators
=
{
}
937
local
specials
=
{
}
938
local
explicits
=
{
}
939 940
evaluators
.
inner
=
function
(
di
,
var
)
941
local
inner
=
var
.
inner
942
if
inner
then
943
setattribute
(
di
,
"
location
"
,
inner
,
true
)
944
end
945
end
946 947
evaluators
.
outer
=
function
(
di
,
var
)
948
local
file
,
url
=
references
.
checkedfileorurl
(
var
.
outer
,
var
.
outer
)
949
if
url
then
950
setattribute
(
di
,
"
url
"
,
url
,
true
)
951
elseif
file
then
952
setattribute
(
di
,
"
file
"
,
file
,
true
)
953
end
954
end
955 956
evaluators
[
"
outer with inner
"
]
=
function
(
di
,
var
)
957
local
file
=
references
.
checkedfile
(
var
.
f
)
958
if
file
then
959
setattribute
(
di
,
"
file
"
,
file
,
true
)
960
end
961
local
inner
=
var
.
inner
962
if
inner
then
963
setattribute
(
di
,
"
inner
"
,
inner
,
true
)
964
end
965
end
966 967
evaluators
.
special
=
function
(
di
,
var
)
968
local
handler
=
specials
[
var
.
special
]
969
if
handler
then
970
handler
(
di
,
var
)
971
end
972
end
973 974
local
referencehash
=
{
}
975
local
destinationhash
=
{
}
976 977
do
978 979
evaluators
[
"
special outer with operation
"
]
=
evaluators
.
special
980
evaluators
[
"
special operation
"
]
=
evaluators
.
special
981
evaluators
[
"
special operation with arguments
"
]
=
evaluators
.
special
982 983
function
specials
.
url
(
di
,
var
)
984
local
url
=
references
.
checkedurl
(
var
.
operation
)
985
if
url
and
url
~
=
"
"
then
986
setattribute
(
di
,
"
url
"
,
url
,
true
)
987
end
988
end
989 990
function
specials
.
file
(
di
,
var
)
991
local
file
=
references
.
checkedfile
(
var
.
operation
)
992
if
file
and
file
~
=
"
"
then
993
setattribute
(
di
,
"
file
"
,
file
,
true
)
994
end
995
end
996 997
function
specials
.
fileorurl
(
di
,
var
)
998
local
file
,
url
=
references
.
checkedfileorurl
(
var
.
operation
,
var
.
operation
)
999
if
url
and
url
~
=
"
"
then
1000
setattribute
(
di
,
"
url
"
,
url
,
true
)
1001
elseif
file
and
file
~
=
"
"
then
1002
setattribute
(
di
,
"
file
"
,
file
,
true
)
1003
end
1004
end
1005 1006
function
specials
.
internal
(
di
,
var
)
1007
local
internal
=
references
.
checkedurl
(
var
.
operation
)
1008
if
internal
then
1009
setattribute
(
di
,
"
location
"
,
internal
)
1010
end
1011
end
1012 1013
local
function
adddestination
(
di
,
references
)
-- todo: specials -> exporters and then concat
1014
if
references
then
1015
local
reference
=
references
.
reference
1016
if
reference
and
reference
~
=
"
"
then
1017
local
prefix
=
references
.
prefix
1018
if
prefix
and
prefix
~
=
"
"
then
1019
setattribute
(
di
,
"
prefix
"
,
prefix
,
true
)
1020
end
1021
setattribute
(
di
,
"
destination
"
,
reference
,
true
)
1022
for
i
=
1
,
#
references
do
1023
local
r
=
references
[
i
]
1024
local
e
=
evaluators
[
r
.
kind
]
1025
if
e
then
1026
e
(
di
,
r
)
1027
end
1028
end
1029
end
1030
end
1031
end
1032 1033
function
extras
.
addimplicit
(
di
,
references
)
1034
if
references
then
1035
local
internal
=
references
.
internal
1036
if
internal
then
1037
setattribute
(
di
,
"
implicit
"
,
internal
)
1038
end
1039
end
1040
end
1041 1042
function
extras
.
addinternal
(
di
,
references
)
1043
if
references
then
1044
local
internal
=
references
.
internal
1045
if
internal
then
1046
setattribute
(
di
,
"
internal
"
,
internal
)
1047
end
1048
end
1049
end
1050 1051
local
p_firstpart
=
lpeg
.
Cs
(
(
1
-
lpeg
.
P
(
"
,
"
)
)
^
0
)
1052 1053
local
function
addreference
(
di
,
references
)
1054
if
references
then
1055
local
reference
=
references
.
reference
1056
if
reference
and
reference
~
=
"
"
then
1057
local
prefix
=
references
.
prefix
1058
if
prefix
and
prefix
~
=
"
"
then
1059
setattribute
(
di
,
"
prefix
"
,
prefix
)
1060
end
1061
setattribute
(
di
,
"
reference
"
,
reference
,
true
)
1062
setattribute
(
di
,
"
explicit
"
,
lpegmatch
(
p_firstpart
,
reference
)
,
true
)
1063
end
1064
local
internal
=
references
.
internal
1065
if
internal
and
internal
~
=
"
"
then
1066
setattribute
(
di
,
"
implicit
"
,
internal
)
1067
end
1068
end
1069
end
1070 1071
local
function
link
(
di
,
element
,
n
,
fulltag
)
1072
-- for instance in lists a link has nested elements and no own text
1073
local
reference
=
referencehash
[
fulltag
]
1074
if
reference
then
1075
adddestination
(
di
,
structures
.
references
.
get
(
reference
)
)
1076
return
true
1077
else
1078
local
data
=
di
.
data
1079
if
data
then
1080
for
i
=
1
,
#
data
do
1081
local
di
=
data
[
i
]
1082
if
di
then
1083
local
fulltag
=
di
.
fulltag
1084
if
fulltag
and
link
(
di
,
element
,
n
,
fulltag
)
then
1085
return
true
1086
end
1087
end
1088
end
1089
end
1090
end
1091
end
1092 1093
local
function
reference
(
di
,
element
,
n
,
fulltag
)
1094
local
destination
=
destinationhash
[
fulltag
]
1095
if
destination
then
1096
local
d
=
structures
.
references
.
internals
[
destination
]
1097
if
d
then
1098
addreference
(
di
,
d
.
references
)
1099
return
true
1100
else
1101
return
false
1102
end
1103
else
1104
local
data
=
di
.
data
1105
if
data
then
1106
for
i
=
1
,
#
data
do
1107
local
di
=
data
[
i
]
1108
if
di
then
1109
local
fulltag
=
di
.
fulltag
1110
if
fulltag
and
reference
(
di
,
element
,
n
,
fulltag
)
then
1111
return
true
1112
end
1113
end
1114
end
1115
end
1116
end
1117
end
1118 1119
extras
.
adddestination
=
adddestination
1120
extras
.
addreference
=
addreference
1121 1122
extras
.
link
=
link
1123
extras
.
reference
=
reference
1124 1125
end
1126 1127
-- no settings, as these are obscure ones
1128 1129
do
1130 1131
local
automathrows
=
true
directives
.
register
(
"
export.math.autorows
"
,
function
(
v
)
automathrows
=
v
end
)
1132
local
automathapply
=
true
directives
.
register
(
"
export.math.autoapply
"
,
function
(
v
)
automathapply
=
v
end
)
1133
local
automathnumber
=
true
directives
.
register
(
"
export.math.autonumber
"
,
function
(
v
)
automathnumber
=
v
end
)
1134
local
automathstrip
=
true
directives
.
register
(
"
export.math.autostrip
"
,
function
(
v
)
automathstrip
=
v
end
)
1135 1136
local
functions
=
mathematics
.
categories
.
functions
1137 1138
local
function
collapse
(
di
,
i
,
data
,
ndata
,
detail
,
element
)
1139
local
collapsing
=
di
.
data
1140
if
data
then
1141
di
.
element
=
element
1142
di
.
detail
=
nil
1143
i
=
i
+
1
1144
while
i
<
=
ndata
do
1145
local
dn
=
data
[
i
]
1146
if
dn
.
detail
=
=
detail
then
1147
collapsing
[
#
collapsing
+
1
]
=
dn
.
data
[
1
]
1148
dn
.
skip
=
"
ignore
"
1149
i
=
i
+
1
1150
else
1151
break
1152
end
1153
end
1154
end
1155
return
i
1156
end
1157 1158
local
function
collapse_mn
(
di
,
i
,
data
,
ndata
)
1159
-- this is tricky ... we need to make sure that we wrap in mrows if we want
1160
-- to bypass this one
1161
local
collapsing
=
di
.
data
1162
if
data
then
1163
i
=
i
+
1
1164
while
i
<
=
ndata
do
1165
local
dn
=
data
[
i
]
1166
local
tg
=
dn
.
tg
1167
if
tg
=
=
"
mn
"
then
1168
collapsing
[
#
collapsing
+
1
]
=
dn
.
data
[
1
]
1169
dn
.
skip
=
"
ignore
"
1170
i
=
i
+
1
1171
elseif
tg
=
=
"
mo
"
then
1172
local
d
=
dn
.
data
[
1
]
1173
if
d
=
=
"
.
"
then
1174
collapsing
[
#
collapsing
+
1
]
=
d
1175
dn
.
skip
=
"
ignore
"
1176
i
=
i
+
1
1177
else
1178
break
1179
end
1180
else
1181
break
1182
end
1183
end
1184
end
1185
return
i
1186
end
1187 1188
-- maybe delay __i__ till we need it
1189 1190
local
apply_function
=
{
1191
{
1192
element
=
"
mo
"
,
1193
-- comment = "apply function",
1194
-- data = { utfchar(0x2061) },
1195
data
=
{
"
&#x2061;
"
}
,
1196
nature
=
"
mixed
"
,
1197
}
1198
}
1199 1200
local
functioncontent
=
{
}
1201 1202
setmetatableindex
(
functioncontent
,
function
(
t
,
k
)
1203
local
v
=
{
{
content
=
k
}
}
1204
t
[
k
]
=
v
1205
return
v
1206
end
)
1207 1208
local
dummy_nucleus
=
{
1209
element
=
"
mtext
"
,
1210
data
=
{
content
=
"
"
}
,
1211
nature
=
"
inline
"
,
1212
comment
=
"
dummy nucleus
"
,
1213
fulltag
=
"
mtext>0
"
1214
}
1215 1216
local
function
accentchar
(
d
)
1217
for
i
=
1
,
3
do
1218
d
=
d
.
data
1219
if
not
d
then
1220
return
1221
end
1222
d
=
d
[
1
]
1223
if
not
d
then
1224
return
1225
end
1226
local
tg
=
d
.
tg
1227
if
tg
=
=
"
mover
"
then
1228
local
s
=
specifications
[
d
.
fulltag
]
1229
local
t
=
s
.
top
1230
if
t
then
1231
d
=
d
.
data
[
1
]
1232
local
d1
=
d
.
data
[
1
]
1233
d1
.
content
=
utfchar
(
t
)
1234
d
.
data
=
{
d1
}
1235
return
d
1236
end
1237
elseif
tg
=
=
"
munder
"
then
1238
local
s
=
specifications
[
d
.
fulltag
]
1239
local
b
=
s
.
bottom
1240
if
b
then
1241
d
=
d
.
data
[
1
]
1242
local
d1
=
d
.
data
[
1
]
1243
d1
.
content
=
utfchar
(
b
)
1244
d
.
data
=
{
d1
}
1245
return
d
1246
end
1247
end
1248
end
1249
end
1250 1251
local
no_mrow
=
{
1252
mrow
=
true
,
1253
mfenced
=
true
,
1254
mfrac
=
true
,
1255
mroot
=
true
,
1256
msqrt
=
true
,
1257
mtable
=
true
,
1258
mi
=
true
,
1259
mo
=
true
,
1260
mn
=
true
,
1261
}
1262 1263
local
function
checkmath
(
root
)
-- we can provide utf.toentities as an option
1264
local
data
=
root
.
data
1265
if
data
then
1266
local
ndata
=
#
data
1267
local
roottg
=
root
.
tg
1268
if
roottg
=
=
"
msubsup
"
then
1269
-- kind of tricky: we have a diufferent order in display mode
1270
local
nucleus
,
superscript
,
subscript
1271
if
ndata
>
3
then
1272
-- error
1273
else
1274
for
i
=
1
,
ndata
do
1275
local
di
=
data
[
i
]
1276
if
not
di
then
1277
-- weird
1278
elseif
di
.
content
then
1279
-- text
1280
else
1281
local
s
=
specifications
[
di
.
fulltag
]
1282
if
s
.
subscript
then
1283
subscript
=
i
1284
elseif
s
.
superscript
then
1285
superscript
=
i
1286
else
1287
nucleus
=
i
1288
end
1289
end
1290
end
1291
if
superscript
or
subscript
then
1292
-- we probably always have 3 anyway ... needs checking
1293
local
nuc
=
nucleus
and
data
[
nucleus
]
1294
local
sub
=
subscript
and
data
[
subscript
]
1295
local
sup
=
superscript
and
data
[
superscript
]
1296
local
n
=
0
-- play safe
1297
if
nuc
then
n
=
n
+
1
;
data
[
n
]
=
nuc
end
1298
if
sub
then
n
=
n
+
1
;
data
[
n
]
=
sub
end
1299
if
sup
then
n
=
n
+
1
;
data
[
n
]
=
sup
end
1300
end
1301
end
1302
-- elseif roottg == "msup" or roottg == "msub" then
1303
-- -- m$^2$
1304
-- if ndata == 1 then
1305
-- local d = data[1]
1306
-- data[2] = d
1307
-- d.__i__ = 2
1308
-- data[1] = dummy_nucleus
1309
-- end
1310
elseif
roottg
=
=
"
mfenced
"
then
1311
local
s
=
specifications
[
root
.
fulltag
]
1312
local
l
,
m
,
r
=
s
.
left
,
s
.
middle
,
s
.
right
1313
if
l
then
1314
l
=
utfchar
(
l
)
1315
end
1316
if
m
then
1317
local
t
=
{
}
1318
for
i
=
1
,
#
m
do
1319
t
[
i
]
=
utfchar
(
m
[
i
]
)
1320
end
1321
m
=
concat
(
t
)
1322
end
1323
if
r
then
1324
r
=
utfchar
(
r
)
1325
end
1326
root
.
attributes
=
{
1327
open
=
l
,
1328
separators
=
m
,
1329
close
=
r
,
1330
}
1331
end
1332
if
ndata
=
=
0
then
1333
root
.
skip
=
"
comment
"
-- get rid of weird artefacts
1334
root
.
nota
=
"
weird
"
1335
return
1336
elseif
ndata
=
=
1
then
1337
local
d
=
data
[
1
]
1338
if
not
d
or
d
=
=
"
"
then
1339
root
.
skip
=
"
comment
"
1340
return
1341
elseif
d
.
content
then
1342
return
1343
else
-- if ndata == 1 then
1344
local
tg
=
d
.
tg
1345
if
automathrows
and
(
roottg
=
=
"
mrow
"
or
roottg
=
=
"
mtext
"
)
then
1346
-- maybe just always ! check spec first
1347
-- or we can have chesks.* for each as we then can flatten
1348
if
no_mrow
[
tg
]
then
1349
root
.
skip
=
"
comment
"
1350
end
1351
elseif
roottg
=
=
"
mo
"
then
1352
if
tg
=
=
"
mo
"
then
1353
root
.
skip
=
"
comment
"
1354
end
1355
end
1356
end
1357
end
1358
local
i
=
1
1359
while
i
<
=
ndata
do
-- -- -- TOO MUCH NESTED CHECKING -- -- --
1360
local
di
=
data
[
i
]
1361
if
di
and
not
di
.
content
then
1362
local
tg
=
di
.
tg
1363
if
tg
=
=
"
math
"
then
1364
-- di.element = "mrow" -- when properties
1365
di
.
skip
=
"
comment
"
1366
checkmath
(
di
)
1367
i
=
i
+
1
1368
elseif
tg
=
=
"
mover
"
then
1369
local
s
=
specifications
[
di
.
fulltag
]
1370
if
s
.
accent
then
1371
local
t
=
s
.
top
1372
local
d
=
di
.
data
1373
-- todo: accent = "false" (for scripts like limits)
1374
di
.
attributes
=
{
1375
accent
=
"
true
"
,
1376
}
1377
-- todo: p.topfixed
1378
if
t
then
1379
-- mover
1380
d
[
1
]
.
data
[
1
]
.
content
=
utfchar
(
t
)
1381
di
.
data
=
{
d
[
2
]
,
d
[
1
]
}
1382
end
1383
else
1384
-- can't happen
1385
end
1386
checkmath
(
di
)
1387
i
=
i
+
1
1388
elseif
tg
=
=
"
munder
"
then
1389
local
s
=
specifications
[
di
.
fulltag
]
1390
if
s
.
accent
then
1391
local
b
=
s
.
bottom
1392
local
d
=
di
.
data
1393
-- todo: accent = "false" (for scripts like limits)
1394
di
.
attributes
=
{
1395
accent
=
"
true
"
,
1396
}
1397
-- todo: p.bottomfixed
1398
if
b
then
1399
-- munder
1400
d
[
2
]
.
data
[
1
]
.
content
=
utfchar
(
b
)
1401
end
1402
else
1403
-- can't happen
1404
end
1405
checkmath
(
di
)
1406
i
=
i
+
1
1407
elseif
tg
=
=
"
munderover
"
then
1408
local
s
=
specifications
[
di
.
fulltag
]
1409
if
s
.
accent
then
1410
local
t
=
s
.
top
1411
local
b
=
s
.
bottom
1412
local
d
=
di
.
data
1413
-- todo: accent = "false" (for scripts like limits)
1414
-- todo: accentunder = "false" (for scripts like limits)
1415
di
.
attributes
=
{
1416
accent
=
"
true
"
,
1417
accentunder
=
"
true
"
,
1418
}
1419
-- todo: p.topfixed
1420
-- todo: p.bottomfixed
1421
if
t
and
b
then
1422
-- munderover
1423
d
[
1
]
.
data
[
1
]
.
content
=
utfchar
(
t
)
1424
d
[
3
]
.
data
[
1
]
.
content
=
utfchar
(
b
)
1425
di
.
data
=
{
d
[
2
]
,
d
[
3
]
,
d
[
1
]
}
1426
else
1427
-- can't happen
1428
end
1429
else
1430
-- can't happen
1431
end
1432
checkmath
(
di
)
1433
i
=
i
+
1
1434
elseif
tg
=
=
"
mstacker
"
then
1435
local
d
=
di
.
data
1436
local
d1
=
d
[
1
]
1437
local
d2
=
d
[
2
]
1438
local
d3
=
d
[
3
]
1439
local
t1
=
d1
and
d1
.
tg
1440
local
t2
=
d2
and
d2
.
tg
1441
local
t3
=
d3
and
d3
.
tg
1442
local
m
=
nil
-- d1.data[1]
1443
local
t
=
nil
1444
local
b
=
nil
1445
-- only accent when top / bot have stretch
1446
-- normally we flush [base under over] which is better for tagged pdf
1447
if
t1
=
=
"
mstackermid
"
then
1448
m
=
accentchar
(
d1
)
-- or m
1449
if
t2
=
=
"
mstackertop
"
then
1450
if
t3
=
=
"
mstackerbot
"
then
1451
t
=
accentchar
(
d2
)
1452
b
=
accentchar
(
d3
)
1453
di
.
element
=
"
munderover
"
1454
di
.
data
=
{
m
or
d1
.
data
[
1
]
,
b
or
d3
.
data
[
1
]
,
t
or
d2
.
data
[
1
]
}
1455
else
1456
t
=
accentchar
(
d2
)
1457
di
.
element
=
"
mover
"
1458
di
.
data
=
{
m
or
d1
.
data
[
1
]
,
t
or
d2
.
data
[
1
]
}
1459
end
1460
elseif
t2
=
=
"
mstackerbot
"
then
1461
if
t3
=
=
"
mstackertop
"
then
1462
b
=
accentchar
(
d2
)
1463
t
=
accentchar
(
d3
)
1464
di
.
element
=
"
munderover
"
1465
di
.
data
=
{
m
or
d1
.
data
[
1
]
,
t
or
d3
.
data
[
1
]
,
m
,
b
or
d2
.
data
[
1
]
}
1466
else
1467
b
=
accentchar
(
d2
)
1468
di
.
element
=
"
munder
"
1469
di
.
data
=
{
m
or
d1
.
data
[
1
]
,
b
or
d2
.
data
[
1
]
}
1470
end
1471
else
1472
-- can't happen
1473
end
1474
else
1475
-- can't happen
1476
end
1477
if
t
or
b
then
1478
di
.
attributes
=
{
1479
accent
=
t
and
"
true
"
or
nil
,
1480
accentunder
=
b
and
"
true
"
or
nil
,
1481
}
1482
di
.
detail
=
nil
1483
end
1484
checkmath
(
di
)
1485
i
=
i
+
1
1486
elseif
tg
=
=
"
mroot
"
then
1487
local
data
=
di
.
data
1488
local
size
=
#
data
1489
if
size
=
=
1
then
1490
-- else firefox complains ... code in math-tag (for pdf tagging)
1491
di
.
element
=
"
msqrt
"
1492
elseif
size
=
=
2
then
1493
data
[
1
]
,
data
[
2
]
=
data
[
2
]
,
data
[
1
]
1494
end
1495
checkmath
(
di
)
1496
i
=
i
+
1
1497
elseif
tg
=
=
"
break
"
then
1498
di
.
skip
=
"
comment
"
1499
i
=
i
+
1
1500
elseif
tg
=
=
"
mtext
"
then
1501
-- this is only needed for unboxed mtexts ... all kind of special
1502
-- tex border cases and optimizations ... trial and error
1503
local
data
=
di
.
data
1504
if
#
data
>
1
then
1505
for
i
=
1
,
#
data
do
1506
local
di
=
data
[
i
]
1507
local
content
=
di
.
content
1508
if
content
then
1509
data
[
i
]
=
{
1510
element
=
"
mtext
"
,
1511
nature
=
"
inline
"
,
1512
data
=
{
di
}
,
1513
n
=
0
,
1514
}
1515
elseif
di
.
tg
=
=
"
math
"
then
1516
local
di
=
di
.
data
[
1
]
1517
if
di
then
1518
data
[
i
]
=
di
1519
checkmath
(
di
)
1520
end
1521
end
1522
end
1523
di
.
element
=
"
mrow
"
1524
-- di.tg = "mrow"
1525
-- di.nature = "inline"
1526
end
1527
checkmath
(
di
)
1528
i
=
i
+
1
1529
elseif
tg
=
=
"
mrow
"
and
detail
then
-- hm, falls through
1530
di
.
detail
=
nil
1531
checkmath
(
di
)
1532
di
=
{
1533
element
=
"
maction
"
,
1534
nature
=
"
display
"
,
1535
attributes
=
{
actiontype
=
detail
}
,
1536
data
=
{
di
}
,
1537
n
=
0
,
1538
}
1539
data
[
i
]
=
di
1540
i
=
i
+
1
1541
else
1542
local
category
=
di
.
mathcategory
1543
if
category
then
1544
-- no checkmath(di) here
1545
if
category
=
=
1
then
-- mo
1546
i
=
collapse
(
di
,
i
,
data
,
ndata
,
detail
,
"
mo
"
)
1547
elseif
category
=
=
2
then
-- mi
1548
i
=
collapse
(
di
,
i
,
data
,
ndata
,
detail
,
"
mi
"
)
1549
elseif
category
=
=
3
then
-- mn
1550
i
=
collapse
(
di
,
i
,
data
,
ndata
,
detail
,
"
mn
"
)
1551
elseif
category
=
=
4
then
-- ms
1552
i
=
collapse
(
di
,
i
,
data
,
ndata
,
detail
,
"
ms
"
)
1553
elseif
category
>
=
1000
then
1554
local
apply
=
category
>
=
2000
1555
if
apply
then
1556
category
=
category
-
1000
1557
end
1558
if
tg
=
=
"
mi
"
then
-- function
1559
if
roottg
=
=
"
mrow
"
then
1560
root
.
skip
=
"
comment
"
1561
root
.
element
=
"
function
"
1562
end
1563
i
=
collapse
(
di
,
i
,
data
,
ndata
,
detail
,
"
mi
"
)
1564
local
tag
=
functions
[
category
]
1565
if
tag
then
1566
di
.
data
=
functioncontent
[
tag
]
1567
end
1568
if
apply
then
1569
di
.
after
=
apply_function
1570
elseif
automathapply
then
-- make function
1571
local
following
1572
if
i
<
=
ndata
then
1573
-- normally not the case
1574
following
=
data
[
i
]
1575
else
1576
local
parent
=
di
.
__p__
-- == root
1577
if
parent
.
tg
=
=
"
mrow
"
then
1578
parent
=
parent
.
__p__
1579
end
1580
local
index
=
parent
.
__i__
1581
following
=
parent
.
data
[
index
+
1
]
1582
end
1583
if
following
then
1584
local
tg
=
following
.
tg
1585
if
tg
=
=
"
mrow
"
or
tg
=
=
"
mfenced
"
then
-- we need to figure out the right condition
1586
di
.
after
=
apply_function
1587
end
1588
end
1589
end
1590
else
-- some problem
1591
checkmath
(
di
)
1592
i
=
i
+
1
1593
end
1594
else
1595
checkmath
(
di
)
1596
i
=
i
+
1
1597
end
1598
elseif
automathnumber
and
tg
=
=
"
mn
"
then
1599
checkmath
(
di
)
1600
i
=
collapse_mn
(
di
,
i
,
data
,
ndata
)
1601
else
1602
checkmath
(
di
)
1603
i
=
i
+
1
1604
end
1605
end
1606
else
-- can be string or boolean
1607
if
parenttg
~
=
"
mtext
"
and
di
=
=
"
"
then
1608
data
[
i
]
=
false
1609
end
1610
i
=
i
+
1
1611
end
1612
end
1613
end
1614
end
1615 1616
local
function
stripmath
(
di
)
1617
if
not
di
then
1618
--
1619
elseif
di
.
content
then
1620
return
di
1621
else
1622
local
tg
=
di
.
tg
1623
if
tg
=
=
"
mtext
"
or
tg
=
=
"
ms
"
then
1624
return
di
1625
else
1626
local
data
=
di
.
data
1627
local
ndata
=
#
data
1628
local
n
=
0
1629
for
i
=
1
,
ndata
do
1630
local
d
=
data
[
i
]
1631
if
d
and
not
d
.
content
then
1632
d
=
stripmath
(
d
)
1633
end
1634
if
d
then
1635
local
content
=
d
.
content
1636
if
not
content
then
1637
n
=
n
+
1
1638
d
.
__i__
=
n
1639
data
[
n
]
=
d
1640
elseif
content
=
=
"
"
or
content
=
=
"
"
then
1641
if
di
.
tg
=
=
"
mspace
"
then
1642
-- we append or prepend a space to a preceding or following mtext
1643
local
parent
=
di
.
__p__
1644
local
index
=
di
.
__i__
-- == i
1645
local
data
=
parent
.
data
1646
if
index
>
1
then
1647
local
d
=
data
[
index
-1
]
1648
if
d
.
tg
=
=
"
mtext
"
then
1649
local
dd
=
d
.
data
1650
local
dn
=
dd
[
#
dd
]
1651
local
dc
=
dn
.
content
1652
if
dc
then
1653
dn
.
content
=
dc
.
.
content
1654
end
1655
end
1656
elseif
index
<
ndata
then
1657
local
d
=
data
[
index
+
1
]
1658
if
d
.
tg
=
=
"
mtext
"
then
1659
local
dd
=
d
.
data
1660
local
dn
=
dd
[
1
]
1661
local
dc
=
dn
.
content
1662
if
dc
then
1663
dn
.
content
=
content
.
.
dc
1664
end
1665
end
1666
end
1667
end
1668
else
1669
n
=
n
+
1
1670
data
[
n
]
=
d
1671
end
1672
end
1673
end
1674
for
i
=
ndata
,
n
+
1
,
-1
do
1675
data
[
i
]
=
nil
1676
end
1677
if
#
data
>
0
then
1678
return
di
1679
end
1680
end
1681
end
1682
end
1683 1684
function
checks
.
math
(
di
)
1685
if
di
.
skip
=
=
"
comment
"
then
1686
-- already done, kind of weird, happens in mathmatrix, maybe some collapse
1687
-- issue that i need to look into
1688
else
1689
local
specification
=
specifications
[
di
.
fulltag
]
1690
local
mode
=
specification
and
specification
.
mode
=
=
"
display
"
and
"
block
"
or
"
inline
"
1691
di
.
attributes
=
{
1692
[
"
display
"
]
=
mode
,
1693
[
"
xmlns:m
"
]
=
mathmlns
,
1694
}
1695
-- can be option if needed:
1696
if
mode
=
=
"
inline
"
then
1697
-- di.nature = "mixed" -- else spacing problem (maybe inline)
1698
di
.
nature
=
"
inline
"
-- we need to catch x$X$x and x $X$ x
1699
else
1700
di
.
nature
=
"
display
"
1701
end
1702
if
automathstrip
then
1703
stripmath
(
di
)
1704
end
1705
checkmath
(
di
)
1706
end
1707
end
1708 1709
-- this one can replace some of the previous code .. todo (test on mathmatrix)
1710 1711
-- ignore with no data can be removed
1712 1713
local
function
checked
(
d
)
1714
local
n
=
#
d
1715
if
n
=
=
1
then
1716
local
di
=
d
[
1
]
1717
local
tg
=
di
.
tg
1718
if
tg
=
=
"
ignore
"
then
1719
-- todo: we can move ignore's data one level up
1720
return
1
1721
elseif
di
.
content
then
1722
return
1
1723
else
1724
local
dd
=
di
.
data
1725
if
#
dd
>
0
and
checked
(
dd
)
>
0
then
1726
return
1
1727
else
1728
return
0
1729
end
1730
end
1731
else
1732
local
m
=
0
1733
for
i
=
1
,
n
do
1734
local
di
=
d
[
i
]
1735
local
tg
=
di
.
tg
1736
if
tg
=
=
"
ignore
"
then
1737
-- skip
1738
elseif
di
.
content
then
1739
m
=
m
+
1
1740
d
[
m
]
=
di
1741
else
1742
local
dd
=
di
.
data
1743
if
#
dd
>
0
and
checked
(
dd
)
>
0
then
1744
m
=
m
+
1
1745
d
[
m
]
=
di
1746
end
1747
end
1748
end
1749
if
m
<
n
then
1750
for
i
=
n
,
m
+
1
,
-1
do
1751
d
[
i
]
=
nil
1752
end
1753
end
1754
return
m
1755
end
1756
end
1757 1758
function
checks
.
mrow
(
di
)
1759
-- local d = di.data
1760
-- if d then
1761
-- checked(d)
1762
-- end
1763
end
1764 1765
-- we can move more checks here
1766 1767
local
function
flatten
(
di
)
1768
local
r
=
di
.
__p__
1769
while
r
do
1770
local
d
=
r
.
data
1771
local
n
=
#
d
1772
if
d
and
n
>
1
then
1773
n
=
checked
(
d
)
1774
end
1775
local
tg
=
r
.
tg
1776
if
n
=
=
1
and
(
tg
=
=
"
mtext
"
or
tg
=
=
"
mrow
"
)
then
1777
r
.
skip
=
"
comment
"
-- weird error
1778
r
=
r
.
__p__
1779
else
1780
break
1781
end
1782
end
1783
end
1784 1785
function
checks
.
mtable
(
di
)
1786
flatten
(
di
)
1787
local
d
=
di
.
data
1788
for
i
=
1
,
#
d
do
1789
local
d
=
d
[
i
]
1790
if
d
.
tg
=
=
"
mtr
"
then
1791
local
d
=
d
.
data
1792
for
i
=
1
,
#
d
do
1793
local
d
=
d
[
i
]
1794
if
d
.
tg
=
=
"
mtd
"
then
1795
-- okay
1796
elseif
d
.
content
then
1797
d
.
content
=
"
"
1798
else
1799
d
.
skip
=
"
comment
"
-- weird error
1800
end
1801
end
1802
elseif
d
.
content
then
1803
d
.
content
=
"
"
1804
else
1805
d
.
skip
=
"
comment
"
-- weird error
1806
end
1807
end
1808
end
1809 1810
do
1811 1812
local
a
,
z
,
A
,
Z
=
0x61
,
0x7A
,
0x41
,
0x5A
1813 1814
function
extras
.
mi
(
di
,
element
,
n
,
fulltag
)
-- check with content
1815
local
str
=
di
.
data
[
1
]
.
content
1816
if
str
and
sub
(
str
,
1
,
1
)
~
=
"
&
"
then
-- hack but good enough (maybe gsub op eerste)
1817
for
v
in
utfvalues
(
str
)
do
1818
if
(
v
>
=
a
and
v
<
=
z
)
or
(
v
>
=
A
and
v
<
=
Z
)
then
1819
local
a
=
di
.
attributes
1820
if
a
then
1821
a
.
mathvariant
=
"
normal
"
1822
else
1823
di
.
attributes
=
{
mathvariant
=
"
normal
"
}
1824
end
1825
end
1826
end
1827
end
1828
end
1829 1830
end
1831 1832
function
extras
.
msub
(
di
,
element
,
n
,
fulltag
)
1833
-- m$^2$
1834
local
data
=
di
.
data
1835
if
#
data
=
=
1
then
1836
local
d
=
data
[
1
]
1837
data
[
2
]
=
d
1838
d
.
__i__
=
2
1839
data
[
1
]
=
dummy_nucleus
1840
end
1841
end
1842 1843
extras
.
msup
=
extras
.
msub
1844 1845
end
1846 1847
do
1848 1849
local
registered
=
{
}
1850 1851
function
structurestags
.
setformulacontent
(
n
)
1852
registered
[
locatedtag
(
"
formulacontent
"
)
]
=
{
1853
n
=
n
,
1854
}
1855
end
1856 1857
function
extras
.
formulacontent
(
di
,
element
,
n
,
fulltag
)
1858
local
r
=
registered
[
fulltag
]
1859
if
r
then
1860
setattribute
(
di
,
"
n
"
,
r
.
n
)
1861
end
1862
end
1863 1864
end
1865 1866
do
1867 1868
local
registered
=
structures
.
sections
.
registered
1869 1870
local
function
resolve
(
di
,
element
,
n
,
fulltag
)
1871
local
data
=
listdata
[
fulltag
]
1872
if
data
then
1873
extras
.
addreference
(
di
,
data
.
references
)
1874
return
true
1875
else
1876
local
data
=
di
.
data
1877
if
data
then
1878
for
i
=
1
,
#
data
do
1879
local
di
=
data
[
i
]
1880
if
di
then
1881
local
ft
=
di
.
fulltag
1882
if
ft
and
resolve
(
di
,
element
,
n
,
ft
)
then
1883
return
true
1884
end
1885
end
1886
end
1887
end
1888
end
1889
end
1890 1891
function
extras
.
section
(
di
,
element
,
n
,
fulltag
)
1892
local
r
=
registered
[
specifications
[
fulltag
]
.
detail
]
1893
if
r
then
1894
setattribute
(
di
,
"
level
"
,
r
.
level
)
1895
end
1896
resolve
(
di
,
element
,
n
,
fulltag
)
1897
end
1898 1899
local
floats
=
{
}
1900 1901
function
structurestags
.
setfloat
(
options
,
method
)
1902
floats
[
locatedtag
(
"
float
"
)
]
=
{
1903
options
=
options
,
1904
method
=
method
,
1905
}
1906
end
1907 1908
function
extras
.
float
(
di
,
element
,
n
,
fulltag
)
1909
local
hash
=
floats
[
fulltag
]
1910
if
hash
then
1911
local
method
=
hash
.
method
1912
if
not
method
or
method
=
=
"
"
then
1913
method
=
"
here
"
1914
end
1915
setattribute
(
di
,
"
method
"
,
method
)
1916
local
options
=
hash
.
options
1917
if
options
and
options
~
=
"
"
then
1918
options
=
settings_to_hash
(
options
)
1919
options
[
method
]
=
nil
1920
options
=
concat
(
sortedkeys
(
options
)
,
"
,
"
)
1921
if
#
options
>
0
then
1922
setattribute
(
di
,
"
options
"
,
options
)
1923
end
1924
end
1925
end
1926
resolve
(
di
,
element
,
n
,
fulltag
)
1927
end
1928 1929
-- todo: internal is already hashed
1930 1931
function
structurestags
.
setlist
(
n
)
1932
local
data
=
structures
.
lists
.
getresult
(
n
)
1933
if
data
then
1934
referencehash
[
locatedtag
(
"
listitem
"
)
]
=
data
1935
end
1936
end
1937 1938
function
extras
.
listitem
(
di
,
element
,
n
,
fulltag
)
1939
local
data
=
referencehash
[
fulltag
]
1940
if
data
then
1941
extras
.
addinternal
(
di
,
data
.
references
)
1942
return
true
1943
end
1944
end
1945 1946
end
1947 1948
do
1949 1950
-- todo: internal is already hashed
1951 1952
function
structurestags
.
setregister
(
tag
,
n
)
-- check if tag is needed
1953
local
data
=
structures
.
registers
.
get
(
tag
,
n
)
1954
if
data
then
1955
referencehash
[
locatedtag
(
"
registerlocation
"
)
]
=
data
1956
end
1957
end
1958 1959
function
extras
.
registerlocation
(
di
,
element
,
n
,
fulltag
)
1960
local
data
=
referencehash
[
fulltag
]
1961
if
type
(
data
)
=
=
"
table
"
then
1962
extras
.
addinternal
(
di
,
data
.
references
)
1963
return
true
1964
else
1965
-- needs checking, probably bookmarks
1966
end
1967
end
1968 1969
function
extras
.
registerpages
(
di
,
element
,
n
,
fulltag
)
-- ignorebreaks
1970
local
data
=
di
.
data
1971
for
i
=
1
,
#
data
do
1972
local
d
=
data
[
i
]
1973
if
d
.
content
=
=
"
"
then
1974
d
.
content
=
"
"
1975
end
1976
end
1977
end
1978 1979
function
extras
.
registerseparator
(
di
,
element
,
n
,
fulltag
)
-- ignorespaces
1980
local
data
=
di
.
data
1981
for
i
=
1
,
#
data
do
1982
local
d
=
data
[
i
]
1983
local
c
=
d
.
content
1984
if
type
(
c
)
=
=
"
string
"
then
1985
d
.
content
=
lpegmatch
(
p_stripper
,
c
)
1986
end
1987
end
1988
end
1989 1990
end
1991 1992
do
1993 1994
local
tabledata
=
{
}
1995 1996
local
function
hascontent
(
data
)
1997
for
i
=
1
,
#
data
do
1998
local
di
=
data
[
i
]
1999
if
not
di
or
di
.
tg
=
=
"
ignore
"
then
2000
--
2001
else
2002
local
content
=
di
.
content
2003
if
content
=
=
"
"
then
2004
--
2005
elseif
content
then
2006
return
true
2007
else
2008
local
d
=
di
.
data
2009
if
d
and
#
d
>
0
and
hascontent
(
d
)
then
2010
return
true
2011
end
2012
end
2013
end
2014
end
2015
end
2016 2017
function
structurestags
.
settablecell
(
rows
,
columns
,
align
)
2018
if
align
>
0
or
rows
>
1
or
columns
>
1
then
-- or kind > 0
2019
tabledata
[
locatedtag
(
"
tablecell
"
)
]
=
{
2020
rows
=
rows
,
2021
columns
=
columns
,
2022
align
=
align
,
2023
}
2024
end
2025
end
2026 2027
function
structurestags
.
gettablecell
(
fulltag
)
2028
return
tabledata
[
fulltag
]
2029
end
2030 2031
function
extras
.
tablecell
(
di
,
element
,
n
,
fulltag
)
2032
local
hash
=
tabledata
[
fulltag
]
2033
if
hash
then
2034
local
columns
=
hash
.
columns
2035
if
columns
and
columns
>
1
then
2036
setattribute
(
di
,
"
columns
"
,
columns
)
2037
end
2038
local
rows
=
hash
.
rows
2039
if
rows
and
rows
>
1
then
2040
setattribute
(
di
,
"
rows
"
,
rows
)
2041
end
2042
local
align
=
hash
.
align
2043
if
not
align
or
align
=
=
0
then
2044
-- normal
2045
elseif
align
=
=
1
then
-- use numbertoalign here
2046
setattribute
(
di
,
"
align
"
,
"
flushright
"
)
2047
elseif
align
=
=
2
then
2048
setattribute
(
di
,
"
align
"
,
"
middle
"
)
2049
elseif
align
=
=
3
then
2050
setattribute
(
di
,
"
align
"
,
"
flushleft
"
)
2051
end
2052
end
2053
end
2054 2055
local
tabulatedata
=
{
}
2056 2057
function
structurestags
.
settabulatecell
(
align
,
kind
)
2058
if
align
>
0
or
kind
>
0
then
2059
tabulatedata
[
locatedtag
(
"
tabulatecell
"
)
]
=
{
2060
align
=
align
,
2061
kind
=
kind
,
-- 1 = bold head
2062
}
2063
end
2064
end
2065 2066
function
structurestags
.
gettabulatecell
(
fulltag
)
2067
return
tabulatedata
[
fulltag
]
2068
end
2069 2070
function
extras
.
tabulate
(
di
,
element
,
n
,
fulltag
)
2071
local
data
=
di
.
data
2072
for
i
=
1
,
#
data
do
2073
local
di
=
data
[
i
]
2074
if
di
.
tg
=
=
"
tabulaterow
"
and
not
hascontent
(
di
.
data
)
then
2075
di
.
element
=
"
"
-- or simply remove
2076
end
2077
end
2078
end
2079 2080
function
extras
.
tabulatecell
(
di
,
element
,
n
,
fulltag
)
2081
local
hash
=
tabulatedata
[
fulltag
]
2082
if
hash
then
2083
local
align
=
hash
.
align
2084
if
not
align
or
align
=
=
0
then
2085
-- normal
2086
elseif
align
=
=
1
then
2087
setattribute
(
di
,
"
align
"
,
"
flushleft
"
)
2088
elseif
align
=
=
2
then
2089
setattribute
(
di
,
"
align
"
,
"
flushright
"
)
2090
elseif
align
=
=
3
then
2091
setattribute
(
di
,
"
align
"
,
"
middle
"
)
2092
end
2093
local
kind
=
hash
.
kind
2094
if
kind
=
=
1
then
2095
setattribute
(
di
,
"
kind
"
,
"
strong
"
)
2096
elseif
kind
=
=
2
then
2097
setattribute
(
di
,
"
kind
"
,
"
equals
"
)
2098
end
2099
end
2100
end
2101 2102
end
2103 2104
do
2105 2106
local
usedpublications
=
{
}
2107
local
tagsindatasets
=
setmetatableindex
(
"
table
"
)
2108
local
serialize
=
false
2109 2110
function
structurestags
.
setpublication
(
dataset
,
tag
,
rendering
)
2111
usedpublications
[
locatedtag
(
"
publication
"
)
]
=
{
2112
dataset
=
dataset
,
2113
tag
=
tag
,
2114
rendering
=
rendering
2115
}
2116
tagsindatasets
[
dataset
]
[
tag
]
=
true
2117
if
not
serialize
then
2118
structures
.
tags
.
registerextradata
(
"
btx
"
,
function
(
)
2119
local
t
=
{
"
<btxdata>
"
}
2120
for
dataset
,
used
in
sortedhash
(
tagsindatasets
)
do
2121
t
[
#
t
+
1
]
=
publications
.
converttoxml
(
dataset
,
true
,
false
,
true
,
false
,
true
,
true
)
2122
end
2123
t
[
#
t
+
1
]
=
"
</btxdata>
"
2124
return
concat
(
t
,
"
\n
"
)
2125
end
)
2126
end
2127
end
2128 2129
function
extras
.
publication
(
di
,
element
,
n
,
fulltag
)
2130
local
hash
=
usedpublications
[
fulltag
]
2131
if
hash
then
2132
setattribute
(
di
,
"
dataset
"
,
hash
.
dataset
)
2133
setattribute
(
di
,
"
tag
"
,
hash
.
tag
)
2134
end
2135
end
2136 2137
end
2138 2139
do
2140 2141
local
usedparagraphs
=
{
}
2142 2143
function
structurestags
.
setparagraph
(
align
)
2144
if
align
~
=
"
"
then
2145
usedparagraphs
[
locatedtag
(
"
paragraph
"
)
]
=
{
2146
dataset
=
dataset
,
2147
tag
=
tag
,
2148
align
=
align
,
2149
}
2150
end
2151
end
2152 2153
function
extras
.
paragraph
(
di
,
element
,
n
,
fulltag
)
2154
local
hash
=
usedparagraphs
[
fulltag
]
2155
if
hash
then
2156
setattribute
(
di
,
"
align
"
,
hash
.
align
)
2157
end
2158
end
2159 2160
end
2161 2162
-- flusher
2163 2164
do
2165 2166
local
f_detail
=
formatters
[
'
detail="%s"
'
]
2167
local
f_chain
=
formatters
[
'
chain="%s"
'
]
2168
local
f_index
=
formatters
[
'
n="%s"
'
]
2169
local
f_spacing
=
formatters
[
'
<c p="%s">%s</c>
'
]
2170 2171
local
f_empty_inline
=
formatters
[
"
<%s/>
"
]
2172
local
f_empty_mixed
=
formatters
[
"
%w<%s/>\n
"
]
2173
local
f_empty_display
=
formatters
[
"
\n%w<%s/>\n
"
]
2174
local
f_empty_inline_attr
=
formatters
[
"
<%s%s/>
"
]
2175
local
f_empty_mixed_attr
=
formatters
[
"
%w<%s%s/>
"
]
2176
local
f_empty_display_attr
=
formatters
[
"
\n%w<%s%s/>\n
"
]
2177 2178
local
f_begin_inline
=
formatters
[
"
<%s>
"
]
2179
local
f_begin_mixed
=
formatters
[
"
%w<%s>
"
]
2180
local
f_begin_display
=
formatters
[
"
\n%w<%s>\n
"
]
2181
local
f_begin_inline_attr
=
formatters
[
"
<%s%s>
"
]
2182
local
f_begin_mixed_attr
=
formatters
[
"
%w<%s%s>
"
]
2183
local
f_begin_display_attr
=
formatters
[
"
\n%w<%s%s>\n
"
]
2184 2185
local
f_end_inline
=
formatters
[
"
</%s>
"
]
2186
local
f_end_mixed
=
formatters
[
"
</%s>\n
"
]
2187
local
f_end_display
=
formatters
[
"
%w</%s>\n
"
]
2188 2189
local
f_begin_inline_comment
=
formatters
[
"
<!-- %s --><%s>
"
]
2190
local
f_begin_mixed_comment
=
formatters
[
"
%w<!-- %s --><%s>
"
]
2191
local
f_begin_display_comment
=
formatters
[
"
\n%w<!-- %s -->\n%w<%s>\n
"
]
2192
local
f_begin_inline_attr_comment
=
formatters
[
"
<!-- %s --><%s%s>
"
]
2193
local
f_begin_mixed_attr_comment
=
formatters
[
"
%w<!-- %s --><%s%s>
"
]
2194
local
f_begin_display_attr_comment
=
formatters
[
"
\n%w<!-- %s -->\n%w<%s%s>\n
"
]
2195 2196
local
f_comment_begin_inline
=
formatters
[
"
<!-- begin %s -->
"
]
2197
local
f_comment_begin_mixed
=
formatters
[
"
%w<!-- begin %s -->
"
]
2198
local
f_comment_begin_display
=
formatters
[
"
\n%w<!-- begin %s -->\n
"
]
2199 2200
local
f_comment_end_inline
=
formatters
[
"
<!-- end %s -->
"
]
2201
local
f_comment_end_mixed
=
formatters
[
"
<!-- end %s -->\n
"
]
2202
local
f_comment_end_display
=
formatters
[
"
%w<!-- end %s -->\n
"
]
2203 2204
local
f_metadata_begin
=
formatters
[
"
\n%w<metadata>\n
"
]
2205
local
f_metadata
=
formatters
[
"
%w<metavariable name=%q>%s</metavariable>\n
"
]
2206
local
f_metadata_end
=
formatters
[
"
%w</metadata>\n
"
]
2207 2208
local
function
attributes
(
a
)
2209
local
r
=
{
}
2210
local
n
=
0
2211
for
k
,
v
in
next
,
a
do
2212
n
=
n
+
1
2213
r
[
n
]
=
f_attribute
(
k
,
tostring
(
v
)
)
-- tostring because of %q
2214
end
2215
sort
(
r
)
2216
return
concat
(
r
,
"
"
)
2217
end
2218 2219
local
function
properties
(
a
)
2220
local
r
=
{
}
2221
local
n
=
0
2222
for
k
,
v
in
next
,
a
do
2223
n
=
n
+
1
2224
r
[
n
]
=
f_property
(
exportproperties
,
k
,
tostring
(
v
)
)
-- tostring because of %q
2225
end
2226
sort
(
r
)
2227
return
concat
(
r
,
"
"
)
2228
end
2229 2230
local
depth
=
0
2231
local
inline
=
0
2232 2233
local
function
emptytag
(
result
,
element
,
nature
,
di
)
-- currently only break but at some point
2234
local
a
=
di
.
attributes
-- we might add detail etc
2235
if
a
then
-- happens seldom
2236
if
nature
=
=
"
display
"
then
2237
result
[
#
result
+
1
]
=
f_empty_display_attr
(
depth
,
namespaced
[
element
]
,
attributes
(
a
)
)
2238
elseif
nature
=
=
"
mixed
"
then
2239
result
[
#
result
+
1
]
=
f_empty_mixed_attr
(
depth
,
namespaced
[
element
]
,
attributes
(
a
)
)
2240
else
2241
result
[
#
result
+
1
]
=
f_empty_inline_attr
(
namespaced
[
element
]
,
attributes
(
a
)
)
2242
end
2243
else
2244
if
nature
=
=
"
display
"
then
2245
result
[
#
result
+
1
]
=
f_empty_display
(
depth
,
namespaced
[
element
]
)
2246
elseif
nature
=
=
"
mixed
"
then
2247
result
[
#
result
+
1
]
=
f_empty_mixed
(
depth
,
namespaced
[
element
]
)
2248
else
2249
result
[
#
result
+
1
]
=
f_empty_inline
(
namespaced
[
element
]
)
2250
end
2251
end
2252
end
2253 2254
-- local function stripspaces(di)
2255
-- local d = di.data
2256
-- local n = #d
2257
-- local m = 0
2258
-- for i=1,n do
2259
-- local di = d[i]
2260
-- if di.tg then
2261
-- m = m + 1
2262
-- d[m] = di
2263
-- end
2264
-- end
2265
-- for i=n,m+1,-1 do
2266
-- d[i] = nil
2267
-- end
2268
-- end
2269
--
2270
-- -- simpler:
2271 2272
local
function
stripspaces
(
di
)
2273
local
d
=
di
.
data
2274
for
i
=
1
,
#
d
do
2275
local
di
=
d
[
i
]
2276
if
not
di
.
tg
then
2277
di
.
content
=
"
"
2278
end
2279
end
2280
end
2281 2282
local
function
begintag
(
result
,
element
,
nature
,
di
,
skip
)
2283
local
index
=
di
.
n
2284
local
fulltag
=
di
.
fulltag
2285
local
specification
=
specifications
[
fulltag
]
or
{
}
-- we can have a dummy
2286
local
comment
=
di
.
comment
2287
local
detail
=
specification
.
detail
2288
if
skip
=
=
"
comment
"
then
2289
if
show_comment
then
2290
if
nature
=
=
"
inline
"
or
inline
>
0
then
2291
result
[
#
result
+
1
]
=
f_comment_begin_inline
(
namespaced
[
element
]
)
2292
inline
=
inline
+
1
2293
elseif
nature
=
=
"
mixed
"
then
2294
result
[
#
result
+
1
]
=
f_comment_begin_mixed
(
depth
,
namespaced
[
element
]
)
2295
depth
=
depth
+
1
2296
inline
=
1
2297
else
2298
result
[
#
result
+
1
]
=
f_comment_begin_display
(
depth
,
namespaced
[
element
]
)
2299
depth
=
depth
+
1
2300
end
2301
end
2302
elseif
skip
then
2303
-- ignore
2304
else
2305 2306
local
n
=
0
2307
local
r
=
{
}
-- delay this
2308
if
detail
then
2309
detail
=
gsub
(
detail
,
"
[^A-Za-z0-9]+
"
,
"
-
"
)
2310
specification
.
detail
=
detail
-- we use it later in for the div
2311
n
=
n
+
1
2312
r
[
n
]
=
f_detail
(
detail
)
2313
end
2314
local
parents
=
specification
.
parents
2315
if
parents
then
2316
parents
=
gsub
(
parents
,
"
[^A-Za-z0-9 ]+
"
,
"
-
"
)
2317
specification
.
parents
=
parents
-- we use it later in for the div
2318
n
=
n
+
1
2319
r
[
n
]
=
f_chain
(
parents
)
2320
end
2321
if
indexing
and
index
then
2322
n
=
n
+
1
2323
r
[
n
]
=
f_index
(
index
)
2324
end
2325
--
2326
local
extra
=
extras
[
element
]
2327
if
extra
then
2328
extra
(
di
,
element
,
index
,
fulltag
)
2329
end
2330
--
2331
if
di
.
record
then
2332
stripspaces
(
di
)
2333
end
2334
--
2335
if
exportproperties
then
2336
local
p
=
specification
.
userdata
2337
if
not
p
then
2338
-- skip
2339
elseif
exportproperties
=
=
v_yes
then
2340
n
=
n
+
1
2341
r
[
n
]
=
attributes
(
p
)
2342
else
2343
n
=
n
+
1
2344
r
[
n
]
=
properties
(
p
)
2345
end
2346
end
2347
local
a
=
di
.
attributes
2348
if
a
then
2349
if
trace_spacing
then
2350
a
.
p
=
di
.
parnumber
or
0
2351
end
2352
n
=
n
+
1
2353
r
[
n
]
=
attributes
(
a
)
2354
elseif
trace_spacing
then
2355
n
=
n
+
1
2356
r
[
n
]
=
attributes
{
p
=
di
.
parnumber
or
0
}
2357
end
2358
if
n
=
=
0
then
2359
if
nature
=
=
"
inline
"
or
inline
>
0
then
2360
if
show_comment
and
comment
then
2361
result
[
#
result
+
1
]
=
f_begin_inline_comment
(
comment
,
namespaced
[
element
]
)
2362
else
2363
result
[
#
result
+
1
]
=
f_begin_inline
(
namespaced
[
element
]
)
2364
end
2365
inline
=
inline
+
1
2366
elseif
nature
=
=
"
mixed
"
then
2367
if
show_comment
and
comment
then
2368
result
[
#
result
+
1
]
=
f_begin_mixed_comment
(
depth
,
comment
,
namespaced
[
element
]
)
2369
else
2370
result
[
#
result
+
1
]
=
f_begin_mixed
(
depth
,
namespaced
[
element
]
)
2371
end
2372
depth
=
depth
+
1
2373
inline
=
1
2374
else
2375
if
show_comment
and
comment
then
2376
result
[
#
result
+
1
]
=
f_begin_display_comment
(
depth
,
comment
,
depth
,
namespaced
[
element
]
)
2377
else
2378
result
[
#
result
+
1
]
=
f_begin_display
(
depth
,
namespaced
[
element
]
)
2379
end
2380
depth
=
depth
+
1
2381
end
2382
else
2383
r
=
concat
(
r
,
"
"
,
1
,
n
)
2384
if
nature
=
=
"
inline
"
or
inline
>
0
then
2385
if
show_comment
and
comment
then
2386
result
[
#
result
+
1
]
=
f_begin_inline_attr_comment
(
comment
,
namespaced
[
element
]
,
r
)
2387
else
2388
result
[
#
result
+
1
]
=
f_begin_inline_attr
(
namespaced
[
element
]
,
r
)
2389
end
2390
inline
=
inline
+
1
2391
elseif
nature
=
=
"
mixed
"
then
2392
if
show_comment
and
comment
then
2393
result
[
#
result
+
1
]
=
f_begin_mixed_attr_comment
(
depth
,
comment
,
namespaced
[
element
]
,
r
)
2394
else
2395
result
[
#
result
+
1
]
=
f_begin_mixed_attr
(
depth
,
namespaced
[
element
]
,
r
)
2396
end
2397
depth
=
depth
+
1
2398
inline
=
1
2399
else
2400
if
show_comment
and
comment
then
2401
result
[
#
result
+
1
]
=
f_begin_display_attr_comment
(
depth
,
comment
,
depth
,
namespaced
[
element
]
,
r
)
2402
else
2403
result
[
#
result
+
1
]
=
f_begin_display_attr
(
depth
,
namespaced
[
element
]
,
r
)
2404
end
2405
depth
=
depth
+
1
2406
end
2407
end
2408
end
2409
used
[
element
]
[
detail
or
"
"
]
=
{
nature
,
specification
.
parents
}
-- for template css
2410
-- also in last else ?
2411
local
metadata
=
specification
.
metadata
2412
if
metadata
then
2413
result
[
#
result
+
1
]
=
f_metadata_begin
(
depth
)
2414
for
k
,
v
in
table
.
sortedpairs
(
metadata
)
do
2415
if
v
~
=
"
"
then
2416
result
[
#
result
+
1
]
=
f_metadata
(
depth
+
1
,
k
,
lpegmatch
(
p_entity
,
v
)
)
2417
end
2418
end
2419
result
[
#
result
+
1
]
=
f_metadata_end
(
depth
)
2420
end
2421
end
2422 2423
local
function
endtag
(
result
,
element
,
nature
,
di
,
skip
)
2424
if
skip
=
=
"
comment
"
then
2425
if
show_comment
then
2426
if
nature
=
=
"
display
"
and
(
inline
=
=
0
or
inline
=
=
1
)
then
2427
depth
=
depth
-
1
2428
result
[
#
result
+
1
]
=
f_comment_end_display
(
depth
,
namespaced
[
element
]
)
2429
inline
=
0
2430
elseif
nature
=
=
"
mixed
"
and
(
inline
=
=
0
or
inline
=
=
1
)
then
2431
depth
=
depth
-
1
2432
result
[
#
result
+
1
]
=
f_comment_end_mixed
(
namespaced
[
element
]
)
2433
inline
=
0
2434
else
2435
inline
=
inline
-
1
2436
result
[
#
result
+
1
]
=
f_comment_end_inline
(
namespaced
[
element
]
)
2437
end
2438
end
2439
elseif
skip
then
2440
-- ignore
2441
else
2442
if
nature
=
=
"
display
"
and
(
inline
=
=
0
or
inline
=
=
1
)
then
2443
depth
=
depth
-
1
2444
result
[
#
result
+
1
]
=
f_end_display
(
depth
,
namespaced
[
element
]
)
2445
inline
=
0
2446
elseif
nature
=
=
"
mixed
"
and
(
inline
=
=
0
or
inline
=
=
1
)
then
2447
depth
=
depth
-
1
2448
result
[
#
result
+
1
]
=
f_end_mixed
(
namespaced
[
element
]
)
2449
inline
=
0
2450
else
2451
inline
=
inline
-
1
2452
result
[
#
result
+
1
]
=
f_end_inline
(
namespaced
[
element
]
)
2453
end
2454
end
2455
end
2456 2457
local
function
flushtree
(
result
,
data
,
nature
)
2458
local
nofdata
=
#
data
2459
for
i
=
1
,
nofdata
do
2460
local
di
=
data
[
i
]
2461
if
not
di
then
-- hm, di can be string
2462
-- whatever
2463
else
2464
local
content
=
di
.
content
2465
-- also optimize for content == "" : trace that first
2466
if
content
then
2467
-- already has breaks
2468
local
content
=
lpegmatch
(
p_entity
,
content
)
2469
if
i
=
=
nofdata
and
sub
(
content
,
-1
)
=
=
"
\n
"
then
-- move check
2470
-- can be an end of line in par but can also be the last line
2471
if
trace_spacing
then
2472
result
[
#
result
+
1
]
=
f_spacing
(
di
.
parnumber
or
0
,
sub
(
content
,
1
,
-2
)
)
2473
else
2474
result
[
#
result
+
1
]
=
sub
(
content
,
1
,
-2
)
2475
end
2476
result
[
#
result
+
1
]
=
"
"
2477
else
2478
if
trace_spacing
then
2479
result
[
#
result
+
1
]
=
f_spacing
(
di
.
parnumber
or
0
,
content
)
2480
else
2481
result
[
#
result
+
1
]
=
content
2482
end
2483
end
2484
elseif
not
di
.
collapsed
then
-- ignore collapsed data (is appended, reconstructed par)
2485
local
element
=
di
.
element
2486
if
not
element
then
2487
-- skip
2488
elseif
element
=
=
"
break
"
then
-- or element == "pagebreak"
2489
emptytag
(
result
,
element
,
nature
,
di
)
2490
elseif
element
=
=
"
"
or
di
.
skip
=
=
"
ignore
"
then
2491
-- skip
2492
else
2493
if
di
.
before
then
2494
flushtree
(
result
,
di
.
before
,
nature
)
2495
end
2496
local
natu
=
di
.
nature
2497
local
skip
=
di
.
skip
2498
if
di
.
breaknode
then
2499
emptytag
(
result
,
"
break
"
,
"
display
"
,
di
)
2500
end
2501
begintag
(
result
,
element
,
natu
,
di
,
skip
)
2502
flushtree
(
result
,
di
.
data
,
natu
)
2503
endtag
(
result
,
element
,
natu
,
di
,
skip
)
2504
if
di
.
after
then
2505
flushtree
(
result
,
di
.
after
,
nature
)
2506
end
2507
end
2508
end
2509
end
2510
end
2511
end
2512 2513
local
function
breaktree
(
tree
,
parent
,
parentelement
)
-- also removes double breaks
2514
local
data
=
tree
.
data
2515
if
data
then
2516
local
nofdata
=
#
data
2517
local
prevelement
2518
local
prevnature
2519
local
prevparnumber
2520
local
newdata
=
{
}
2521
local
nofnewdata
=
0
2522
for
i
=
1
,
nofdata
do
2523
local
di
=
data
[
i
]
2524
if
not
di
then
2525
-- skip
2526
elseif
di
.
skip
=
=
"
ignore
"
then
2527
-- skip (new)
2528
elseif
di
.
tg
=
=
"
ignore
"
then
2529
-- skip (new)
2530
elseif
di
.
content
then
2531
if
di
.
samepar
then
2532
prevparnumber
=
false
2533
else
2534
local
parnumber
=
di
.
parnumber
2535
if
prevnature
=
=
"
inline
"
and
prevparnumber
and
prevparnumber
~
=
parnumber
then
2536
nofnewdata
=
nofnewdata
+
1
2537
if
trace_spacing
then
2538
newdata
[
nofnewdata
]
=
makebreaknode
{
type
=
"
a
"
,
p
=
prevparnumber
,
n
=
parnumber
}
2539
else
2540
newdata
[
nofnewdata
]
=
makebreaknode
(
)
2541
end
2542
end
2543
prevelement
=
nil
2544
prevparnumber
=
parnumber
2545
end
2546
prevnature
=
"
inline
"
2547
nofnewdata
=
nofnewdata
+
1
2548
newdata
[
nofnewdata
]
=
di
2549
elseif
not
di
.
collapsed
then
2550
local
element
=
di
.
element
2551
if
element
=
=
"
break
"
then
-- or element == "pagebreak"
2552
if
prevelement
=
=
"
break
"
then
2553
di
.
element
=
"
"
2554
end
2555
prevelement
=
element
2556
prevnature
=
"
display
"
2557
nofnewdata
=
nofnewdata
+
1
2558
newdata
[
nofnewdata
]
=
di
2559
elseif
element
=
=
"
"
or
di
.
skip
=
=
"
ignore
"
then
2560
-- skip
2561
else
2562
if
di
.
samepar
then
2563
prevnature
=
"
inline
"
2564
prevparnumber
=
false
2565
else
2566
local
nature
=
di
.
nature
2567
local
parnumber
=
di
.
parnumber
2568
if
prevnature
=
=
"
inline
"
and
nature
=
=
"
inline
"
and
prevparnumber
and
prevparnumber
~
=
parnumber
then
2569
nofnewdata
=
nofnewdata
+
1
2570
if
trace_spacing
then
2571
newdata
[
nofnewdata
]
=
makebreaknode
{
type
=
"
b
"
,
p
=
prevparnumber
,
n
=
parnumber
}
2572
else
2573
newdata
[
nofnewdata
]
=
makebreaknode
(
)
2574
end
2575
end
2576
prevnature
=
nature
2577
prevparnumber
=
parnumber
2578
end
2579
prevelement
=
element
2580
breaktree
(
di
,
tree
,
element
)
2581
nofnewdata
=
nofnewdata
+
1
2582
newdata
[
nofnewdata
]
=
di
2583
end
2584
else
2585
if
di
.
samepar
then
2586
prevnature
=
"
inline
"
2587
prevparnumber
=
false
2588
else
2589
local
nature
=
di
.
nature
2590
local
parnumber
=
di
.
parnumber
2591
if
prevnature
=
=
"
inline
"
and
nature
=
=
"
inline
"
and
prevparnumber
and
prevparnumber
~
=
parnumber
then
2592
nofnewdata
=
nofnewdata
+
1
2593
if
trace_spacing
then
2594
newdata
[
nofnewdata
]
=
makebreaknode
{
type
=
"
c
"
,
p
=
prevparnumber
,
n
=
parnumber
}
2595
else
2596
newdata
[
nofnewdata
]
=
makebreaknode
(
)
2597
end
2598
end
2599
prevnature
=
nature
2600
prevparnumber
=
parnumber
2601
end
2602
nofnewdata
=
nofnewdata
+
1
2603
newdata
[
nofnewdata
]
=
di
2604
end
2605
end
2606
tree
.
data
=
newdata
2607
end
2608
end
2609 2610
-- also tabulaterow reconstruction .. maybe better as a checker
2611
-- i.e cell attribute
2612 2613
local
function
collapsetree
(
tree
)
2614
-- for tag, trees in sortedhash(treehash) do
2615
for
tag
,
trees
in
next
,
treehash
do
2616
local
d
=
trees
[
1
]
.
data
2617
-- print("!!!!!!!!",tag)
2618
-- inspect(trees)
2619
if
d
then
2620
local
nd
=
#
d
2621
if
nd
>
0
then
2622
for
i
=
2
,
#
trees
do
2623
local
currenttree
=
trees
[
i
]
2624
local
currentdata
=
currenttree
.
data
2625
local
currentpar
=
currenttree
.
parnumber
2626
local
previouspar
=
trees
[
i
-1
]
.
parnumber
2627
currenttree
.
collapsed
=
true
2628
-- is the next ok?
2629
if
previouspar
=
=
0
or
not
(
di
and
di
.
content
)
then
2630
previouspar
=
nil
-- no need anyway so no further testing needed
2631
end
2632
for
j
=
1
,
#
currentdata
do
2633
local
cd
=
currentdata
[
j
]
2634
if
not
cd
or
cd
=
=
"
"
then
2635
-- skip
2636
elseif
cd
.
skip
=
=
"
ignore
"
then
2637
-- skip
2638
elseif
cd
.
content
then
2639
if
not
currentpar
then
2640
-- add space ?
2641
elseif
not
previouspar
then
2642
-- add space ?
2643
elseif
currentpar
~
=
previouspar
then
2644
nd
=
nd
+
1
2645
if
trace_spacing
then
2646
d
[
nd
]
=
makebreaknode
{
type
=
"
d
"
,
p
=
previouspar
,
n
=
currentpar
}
2647
else
2648
d
[
nd
]
=
makebreaknode
(
)
2649
end
2650
end
2651
previouspar
=
currentpar
2652
nd
=
nd
+
1
2653
d
[
nd
]
=
cd
2654
else
2655
nd
=
nd
+
1
2656
d
[
nd
]
=
cd
2657
end
2658
currentdata
[
j
]
=
false
2659
end
2660
end
2661
end
2662
end
2663
end
2664
end
2665 2666
local
function
finalizetree
(
tree
)
2667
for
_
,
finalizer
in
next
,
finalizers
do
2668
finalizer
(
tree
)
2669
end
2670
end
2671 2672
-- local function showtree(data,when,where)
2673
-- if data then
2674
-- for i=1,#data do
2675
-- local d = data[i]
2676
-- if type(d) == "table" and d.element then
2677
-- print(when,where,i,d.element,d.parnumber or 0)
2678
-- end
2679
-- end
2680
-- end
2681
-- end
2682 2683
local
function
indextree
(
tree
)
2684
local
data
=
tree
.
data
2685
if
data
then
2686
local
n
,
new
=
0
,
{
}
2687
-- showtree(data,"before","index")
2688
for
i
=
1
,
#
data
do
2689
local
d
=
data
[
i
]
2690
if
not
d
then
2691
-- skip
2692
elseif
d
.
content
then
2693
n
=
n
+
1
2694
new
[
n
]
=
d
2695
elseif
not
d
.
collapsed
then
2696
n
=
n
+
1
2697
d
.
__i__
=
n
2698
d
.
__p__
=
tree
2699
indextree
(
d
)
2700
new
[
n
]
=
d
2701
end
2702
end
2703
tree
.
data
=
new
2704
-- showtree(new,"after","index")
2705
end
2706
end
2707 2708
local
function
checktree
(
tree
)
2709
local
data
=
tree
.
data
2710
if
data
then
2711
-- showtree(data,"before","check")
2712
for
i
=
1
,
#
data
do
2713
local
d
=
data
[
i
]
2714
if
type
(
d
)
=
=
"
table
"
then
2715
local
check
=
checks
[
d
.
tg
]
2716
if
check
then
2717
check
(
d
,
data
,
i
)
2718
end
2719
checktree
(
d
)
-- so parts can pass twice
2720
end
2721
end
2722
-- showtree(data,"after","check")
2723
end
2724
end
2725 2726
local
function
fixtree
(
tree
)
2727
local
data
=
tree
.
data
2728
if
data
then
2729
-- showtree(data,"before","fix")
2730
for
i
=
1
,
#
data
do
2731
local
d
=
data
[
i
]
2732
if
type
(
d
)
=
=
"
table
"
then
2733
local
fix
=
fixes
[
d
.
tg
]
2734
if
fix
then
2735
fix
(
d
,
data
,
i
)
2736
end
2737
fixtree
(
d
)
-- so parts can pass twice
2738
end
2739
end
2740
-- showtree(data,"after","fix")
2741
end
2742
end
2743 2744
wrapups
.
flushtree
=
flushtree
2745
wrapups
.
breaktree
=
breaktree
2746
wrapups
.
collapsetree
=
collapsetree
2747
wrapups
.
finalizetree
=
finalizetree
2748
wrapups
.
indextree
=
indextree
2749
wrapups
.
checktree
=
checktree
2750
wrapups
.
fixtree
=
fixtree
2751 2752
end
2753 2754
-- collector code
2755 2756
local
function
push
(
fulltag
,
depth
)
2757
local
tg
,
n
,
detail
,
element
,
nature
,
record
2758
local
specification
=
specifications
[
fulltag
]
2759
if
specification
then
2760
tg
=
specification
.
tagname
2761
n
=
specification
.
tagindex
2762
detail
=
specification
.
detail
2763
else
2764
-- a break (more efficient if we don't store those in specifications)
2765
tg
,
n
=
lpegmatch
(
tagsplitter
,
fulltag
)
2766
n
=
tonumber
(
n
)
-- to tonumber in tagsplitter
2767
end
2768
local
p
=
properties
[
tg
]
2769
if
p
then
2770
element
=
p
.
export
or
tg
2771
nature
=
p
.
nature
or
"
inline
"
-- defaultnature
2772
record
=
p
.
record
2773
end
2774
local
treedata
=
tree
.
data
2775
local
t
=
{
-- maybe we can use the tag table
2776
tg
=
tg
,
2777
fulltag
=
fulltag
,
2778
detail
=
detail
,
2779
n
=
n
,
-- already a number
2780
element
=
element
,
2781
nature
=
nature
,
2782
data
=
{
}
,
2783
attribute
=
currentattribute
,
2784
parnumber
=
currentparagraph
,
2785
record
=
record
,
-- we can consider storing properties
2786
}
2787
treedata
[
#
treedata
+
1
]
=
t
2788
currentdepth
=
currentdepth
+
1
2789
nesting
[
currentdepth
]
=
fulltag
2790
treestack
[
currentdepth
]
=
tree
2791
if
trace_export
then
2792
if
detail
and
detail
~
=
"
"
then
2793
report_export
(
"
%w<%s trigger=%q n=%q paragraph=%q index=%q detail=%q>
"
,
currentdepth
-1
,
tg
,
n
,
currentattribute
or
0
,
currentparagraph
or
0
,
#
treedata
,
detail
)
2794
else
2795
report_export
(
"
%w<%s trigger=%q n=%q paragraph=%q index=%q>
"
,
currentdepth
-1
,
tg
,
n
,
currentattribute
or
0
,
currentparagraph
or
0
,
#
treedata
)
2796
end
2797
end
2798
tree
=
t
2799
if
tg
=
=
"
break
"
then
2800
-- no need for this
2801
else
2802
local
h
=
treehash
[
fulltag
]
2803
if
h
then
2804
h
[
#
h
+
1
]
=
t
2805
else
2806
treehash
[
fulltag
]
=
{
t
}
2807
end
2808
end
2809
end
2810 2811
local
function
pop
(
)
2812
if
currentdepth
>
0
then
2813
local
top
=
nesting
[
currentdepth
]
2814
tree
=
treestack
[
currentdepth
]
2815
currentdepth
=
currentdepth
-
1
2816
if
trace_export
then
2817
if
top
then
2818
report_export
(
"
%w</%s>
"
,
currentdepth
,
match
(
top
,
"
[^>]+
"
)
)
2819
else
2820
report_export
(
"
</BAD>
"
)
2821
end
2822
end
2823
else
2824
report_export
(
"
%w<!-- too many pops -->
"
,
currentdepth
)
2825
end
2826
end
2827 2828
local
function
continueexport
(
)
2829
if
nofcurrentcontent
>
0
then
2830
if
trace_export
then
2831
report_export
(
"
%w<!-- injecting pagebreak space -->
"
,
currentdepth
)
2832
end
2833
nofcurrentcontent
=
nofcurrentcontent
+
1
2834
currentcontent
[
nofcurrentcontent
]
=
"
"
-- pagebreak
2835
end
2836
end
2837 2838
local
function
pushentry
(
current
)
2839
if
not
current
then
2840
-- bad news
2841
return
2842
end
2843
current
=
current
.
taglist
2844
if
not
current
then
2845
-- even worse news
2846
return
2847
end
2848
if
restart
then
2849
continueexport
(
)
2850
restart
=
false
2851
end
2852
local
newdepth
=
#
current
2853
local
olddepth
=
currentdepth
2854
if
trace_export
then
2855
report_export
(
"
%w<!-- moving from depth %s to %s (%s) -->
"
,
currentdepth
,
olddepth
,
newdepth
,
current
[
newdepth
]
)
2856
end
2857
if
olddepth
<
=
0
then
2858
for
i
=
1
,
newdepth
do
2859
push
(
current
[
i
]
,
i
)
2860
end
2861
else
2862
local
difference
2863
if
olddepth
<
newdepth
then
2864
for
i
=
1
,
olddepth
do
2865
if
current
[
i
]
~
=
nesting
[
i
]
then
2866
difference
=
i
2867
break
2868
end
2869
end
2870
else
2871
for
i
=
1
,
newdepth
do
2872
if
current
[
i
]
~
=
nesting
[
i
]
then
2873
difference
=
i
2874
break
2875
end
2876
end
2877
end
2878
if
difference
then
2879
for
i
=
olddepth
,
difference
,
-1
do
2880
pop
(
)
2881
end
2882
for
i
=
difference
,
newdepth
do
2883
push
(
current
[
i
]
,
i
)
2884
end
2885
elseif
newdepth
>
olddepth
then
2886
for
i
=
olddepth
+
1
,
newdepth
do
2887
push
(
current
[
i
]
,
i
)
2888
end
2889
elseif
newdepth
<
olddepth
then
2890
for
i
=
olddepth
,
newdepth
,
-1
do
2891
pop
(
)
2892
end
2893
elseif
trace_export
then
2894
report_export
(
"
%w<!-- staying at depth %s (%s) -->
"
,
currentdepth
,
newdepth
,
nesting
[
newdepth
]
or
"
?
"
)
2895
end
2896
end
2897
return
olddepth
,
newdepth
2898
end
2899 2900
local
function
pushcontent
(
oldparagraph
,
newparagraph
)
2901
if
nofcurrentcontent
>
0
then
2902
if
oldparagraph
then
2903
if
currentcontent
[
nofcurrentcontent
]
=
=
"
\n
"
then
2904
if
trace_export
then
2905
report_export
(
"
%w<!-- removing newline -->
"
,
currentdepth
)
2906
end
2907
nofcurrentcontent
=
nofcurrentcontent
-
1
2908
end
2909
end
2910
local
content
=
concat
(
currentcontent
,
"
"
,
1
,
nofcurrentcontent
)
2911
if
content
=
=
"
"
then
2912
-- omit; when oldparagraph we could push, remove spaces, pop
2913
elseif
somespace
[
content
]
and
oldparagraph
then
2914
-- omit; when oldparagraph we could push, remove spaces, pop
2915
else
2916
local
olddepth
,
newdepth
2917
local
list
=
taglist
[
currentattribute
]
2918
if
list
then
2919
olddepth
,
newdepth
=
pushentry
(
list
)
2920
end
2921
if
tree
then
2922
local
td
=
tree
.
data
2923
local
nd
=
#
td
2924
td
[
nd
+
1
]
=
{
parnumber
=
oldparagraph
or
currentparagraph
,
content
=
content
}
2925
if
trace_export
then
2926
report_export
(
"
%w<!-- start content with length %s -->
"
,
currentdepth
,
utflen
(
content
)
)
2927
report_export
(
"
%w%s
"
,
currentdepth
,
(
gsub
(
content
,
"
\n
"
,
"
\\n
"
)
)
)
2928
report_export
(
"
%w<!-- stop content -->
"
,
currentdepth
)
2929
end
2930
if
olddepth
then
2931
for
i
=
newdepth
-1
,
olddepth
,
-1
do
2932
pop
(
)
2933
end
2934
end
2935
end
2936
end
2937
nofcurrentcontent
=
0
2938
end
2939
if
oldparagraph
then
2940
pushentry
(
makebreaklist
(
currentnesting
)
)
2941
if
trace_export
then
2942
report_export
(
"
%w<!-- break added between paragraph %a and %a -->
"
,
currentdepth
,
oldparagraph
,
newparagraph
)
2943
end
2944
end
2945
end
2946 2947
local
function
finishexport
(
)
2948
if
trace_export
then
2949
report_export
(
"
%w<!-- start finalizing -->
"
,
currentdepth
)
2950
end
2951
if
nofcurrentcontent
>
0
then
2952
if
somespace
[
currentcontent
[
nofcurrentcontent
]
]
then
2953
if
trace_export
then
2954
report_export
(
"
%w<!-- removing space -->
"
,
currentdepth
)
2955
end
2956
nofcurrentcontent
=
nofcurrentcontent
-
1
2957
end
2958
pushcontent
(
)
2959
end
2960
for
i
=
currentdepth
,
1
,
-1
do
2961
pop
(
)
2962
end
2963
currentcontent
=
{
}
-- we're nice and do a cleanup
2964
if
trace_export
then
2965
report_export
(
"
%w<!-- stop finalizing -->
"
,
currentdepth
)
2966
end
2967
end
2968 2969
-- inserts ?
2970 2971
local
collectresults
do
-- too many locals otherwise
2972 2973
local
nodecodes
=
nodes
.
nodecodes
2974
local
gluecodes
=
nodes
.
gluecodes
2975
local
listcodes
=
nodes
.
listcodes
2976
local
whatsitcodes
=
nodes
.
whatsitcodes
2977 2978
local
subtypes
=
nodes
.
subtypes
2979 2980
local
hlist_code
=
nodecodes
.
hlist
2981
local
vlist_code
=
nodecodes
.
vlist
2982
local
glyph_code
=
nodecodes
.
glyph
2983
local
glue_code
=
nodecodes
.
glue
2984
local
kern_code
=
nodecodes
.
kern
2985
local
disc_code
=
nodecodes
.
disc
2986
local
whatsit_code
=
nodecodes
.
whatsit
2987
local
localpar_code
=
nodecodes
.
localpar
2988 2989
local
userskip_code
=
gluecodes
.
userskip
2990
local
rightskip_code
=
gluecodes
.
rightskip
2991
local
parfillskip_code
=
gluecodes
.
parfillskip
2992
local
spaceskip_code
=
gluecodes
.
spaceskip
2993
local
xspaceskip_code
=
gluecodes
.
xspaceskip
2994 2995
local
linelist_code
=
listcodes
.
line
2996 2997
local
userdefinedwhatsit_code
=
whatsitcodes
.
userdefined
2998 2999
local
privateattribute
=
attributes
.
private
3000
local
a_image
=
privateattribute
(
'
image
'
)
3001
local
a_reference
=
privateattribute
(
'
reference
'
)
3002
local
a_destination
=
privateattribute
(
'
destination
'
)
3003
local
a_characters
=
privateattribute
(
'
characters
'
)
3004
local
a_exportstatus
=
privateattribute
(
'
exportstatus
'
)
3005
local
a_tagged
=
privateattribute
(
'
tagged
'
)
3006
local
a_taggedpar
=
privateattribute
(
"
taggedpar
"
)
3007
local
a_textblock
=
privateattribute
(
"
textblock
"
)
3008 3009
local
inline_mark
=
nodes
.
pool
.
userids
[
"
margins.inline
"
]
3010 3011
local
nuts
=
nodes
.
nuts
3012 3013
local
getnext
=
nuts
.
getnext
3014
local
getdisc
=
nuts
.
getdisc
3015
local
getlist
=
nuts
.
getlist
3016
local
getid
=
nuts
.
getid
3017
local
getattr
=
nuts
.
getattr
3018
local
setattr
=
nuts
.
setattr
-- maybe use properties
3019
local
isglyph
=
nuts
.
isglyph
3020
local
getkern
=
nuts
.
getkern
3021
local
getwidth
=
nuts
.
getwidth
3022 3023
local
start_of_par
=
nuts
.
start_of_par
3024 3025
local
nexthlist
=
nuts
.
traversers
.
hlist
3026
local
nextnode
=
nuts
.
traversers
.
node
3027 3028
local
function
addtomaybe
(
maybewrong
,
c
,
case
)
3029
if
trace_export
then
3030
report_export
(
"
%w<!-- possible paragraph mixup at %C case %i -->
"
,
currentdepth
,
c
,
case
)
3031
else
3032
local
s
=
formatters
[
"
%C
"
]
(
c
)
3033
if
maybewrong
then
3034
maybewrong
[
#
maybewrong
+
1
]
=
s
3035
else
3036
maybewrong
=
{
s
}
3037
end
3038
return
maybewrong
3039
end
3040
end
3041 3042
local
function
showmaybe
(
maybewrong
)
3043
if
not
trace_export
then
3044
report_export
(
"
fuzzy paragraph: % t
"
,
maybewrong
)
3045
end
3046
end
3047 3048
local
function
showdetail
(
n
,
id
,
subtype
)
3049
local
a
=
getattr
(
n
,
a_tagged
)
3050
local
t
=
taglist
[
a
]
3051
local
c
=
nodecodes
[
id
]
3052
local
s
=
subtypes
[
id
]
[
subtype
]
3053
if
a
and
t
then
3054
report_export
(
"
node %a, subtype %a, tag %a, element %a, tree '% t'
"
,
c
,
s
,
a
,
t
.
tagname
,
t
.
taglist
)
3055
else
3056
report_export
(
"
node %a, subtype %a, untagged
"
,
c
,
s
)
3057
end
3058
end
3059 3060
local
function
collectresults
(
head
,
list
,
pat
,
pap
)
-- is last used (we also have currentattribute)
3061
local
p
3062
local
localparagraph
3063
local
maybewrong
3064
local
pid
3065
for
n
,
id
,
subtype
in
nextnode
,
head
do
3066
if
trace_details
then
3067
showdetail
(
n
,
id
,
subtype
)
3068
end
3069
if
id
=
=
glyph_code
then
3070
local
c
,
f
=
isglyph
(
n
)
3071
local
at
=
getattr
(
n
,
a_tagged
)
or
pat
3072
if
not
at
then
3073
-- we need to tag the pagebody stuff as being valid skippable
3074
--
3075
-- report_export("skipping character: %C (no attribute)",n.char)
3076
else
3077
if
last
~
=
at
then
3078
local
tl
=
taglist
[
at
]
3079
local
ap
=
getattr
(
n
,
a_taggedpar
)
or
pap
3080
if
localparagraph
and
(
not
ap
or
ap
<
localparagraph
)
then
3081
maybewrong
=
addtomaybe
(
maybewrong
,
c
,
1
)
3082
end
3083
pushcontent
(
)
3084
currentnesting
=
tl
3085
currentparagraph
=
ap
3086
currentattribute
=
at
3087
last
=
at
3088
pushentry
(
currentnesting
)
3089
if
trace_export
then
3090
report_export
(
"
%w<!-- processing glyph %C tagged %a -->
"
,
currentdepth
,
c
,
at
)
3091
end
3092
-- We need to intercept this here; maybe I will also move this
3093
-- to a regular setter at the tex end.
3094
local
r
=
getattr
(
n
,
a_reference
)
3095
if
r
then
3096
local
t
=
tl
.
taglist
3097
referencehash
[
t
[
#
t
]
]
=
r
-- fulltag
3098
end
3099
local
d
=
getattr
(
n
,
a_destination
)
3100
if
d
then
3101
local
t
=
tl
.
taglist
3102
destinationhash
[
t
[
#
t
]
]
=
d
-- fulltag
3103
end
3104
--
3105
elseif
last
then
3106
-- we can consider tagging the pars (lines) in the parbuilder but then we loose some
3107
-- information unless we inject a special node (but even then we can run into nesting
3108
-- issues)
3109
local
ap
=
getattr
(
n
,
a_taggedpar
)
or
pap
3110
if
ap
~
=
currentparagraph
then
3111
pushcontent
(
currentparagraph
,
ap
)
3112
pushentry
(
currentnesting
)
3113
currentattribute
=
last
3114
currentparagraph
=
ap
3115
end
3116
if
localparagraph
and
(
not
ap
or
ap
<
localparagraph
)
then
3117
maybewrong
=
addtomaybe
(
maybewrong
,
c
,
2
)
3118
end
3119
if
trace_export
then
3120
report_export
(
"
%w<!-- processing glyph %C tagged %a -->
"
,
currentdepth
,
c
,
last
)
3121
end
3122
else
3123
if
trace_export
then
3124
report_export
(
"
%w<!-- processing glyph %C tagged %a -->
"
,
currentdepth
,
c
,
at
)
3125
end
3126
end
3127
local
s
=
getattr
(
n
,
a_exportstatus
)
3128
if
s
then
3129
c
=
s
3130
end
3131
if
c
=
=
0
then
3132
if
trace_export
then
3133
report_export
(
"
%w<!-- skipping last glyph -->
"
,
currentdepth
)
3134
end
3135
elseif
c
=
=
0x20
then
3136
local
a
=
getattr
(
n
,
a_characters
)
3137
nofcurrentcontent
=
nofcurrentcontent
+
1
3138
if
a
then
3139
if
trace_export
then
3140
report_export
(
"
%w<!-- turning last space into special space %U -->
"
,
currentdepth
,
a
)
3141
end
3142
currentcontent
[
nofcurrentcontent
]
=
specialspaces
[
a
]
-- special space
3143
else
3144
currentcontent
[
nofcurrentcontent
]
=
"
"
3145
end
3146
else
3147
local
fc
=
fontchar
[
f
]
3148
if
fc
then
3149
fc
=
fc
and
fc
[
c
]
3150
if
fc
then
3151
local
u
=
fc
.
unicode
3152
if
not
u
then
3153
nofcurrentcontent
=
nofcurrentcontent
+
1
3154
currentcontent
[
nofcurrentcontent
]
=
utfchar
(
c
)
3155
elseif
type
(
u
)
=
=
"
table
"
then
3156
for
i
=
1
,
#
u
do
3157
nofcurrentcontent
=
nofcurrentcontent
+
1
3158
currentcontent
[
nofcurrentcontent
]
=
utfchar
(
u
[
i
]
)
3159
end
3160
else
3161
nofcurrentcontent
=
nofcurrentcontent
+
1
3162
currentcontent
[
nofcurrentcontent
]
=
utfchar
(
u
)
3163
end
3164
elseif
c
>
0
then
3165
nofcurrentcontent
=
nofcurrentcontent
+
1
3166
currentcontent
[
nofcurrentcontent
]
=
utfchar
(
c
)
3167
else
3168
-- we can have -1 as side effect of an explicit hyphen (unless we expand)
3169
end
3170
elseif
c
>
0
then
3171
nofcurrentcontent
=
nofcurrentcontent
+
1
3172
currentcontent
[
nofcurrentcontent
]
=
utfchar
(
c
)
3173
else
3174
-- we can have -1 as side effect of an explicit hyphen (unless we expand)
3175
end
3176
end
3177
end
3178
elseif
id
=
=
disc_code
then
-- probably too late
3179
local
pre
,
post
,
replace
=
getdisc
(
n
)
3180
if
keephyphens
then
3181
if
pre
and
not
getnext
(
pre
)
and
isglyph
(
pre
)
=
=
0xAD
then
-- hyphencode then
3182
nofcurrentcontent
=
nofcurrentcontent
+
1
3183
currentcontent
[
nofcurrentcontent
]
=
hyphen
3184
end
3185
end
3186
if
replace
then
3187
collectresults
(
replace
,
nil
)
3188
end
3189
elseif
id
=
=
glue_code
then
3190
-- we need to distinguish between hskips and vskips
3191
local
ca
=
getattr
(
n
,
a_characters
)
3192
if
ca
=
=
0
then
3193
-- skip this one ... already converted special character (node-acc)
3194
elseif
ca
then
3195
local
a
=
getattr
(
n
,
a_tagged
)
or
pat
3196
if
a
then
3197
local
c
=
specialspaces
[
ca
]
3198
if
last
~
=
a
then
3199
local
tl
=
taglist
[
a
]
3200
if
trace_export
then
3201
report_export
(
"
%w<!-- processing space glyph %U tagged %a case 1 -->
"
,
currentdepth
,
ca
,
a
)
3202
end
3203
pushcontent
(
)
3204
currentnesting
=
tl
3205
currentparagraph
=
getattr
(
n
,
a_taggedpar
)
or
pap
3206
currentattribute
=
a
3207
last
=
a
3208
pushentry
(
currentnesting
)
3209
-- no reference check (see above)
3210
elseif
last
then
3211
local
ap
=
getattr
(
n
,
a_taggedpar
)
or
pap
3212
if
ap
~
=
currentparagraph
then
3213
pushcontent
(
currentparagraph
,
ap
)
3214
pushentry
(
currentnesting
)
3215
currentattribute
=
last
3216
currentparagraph
=
ap
3217
end
3218
if
trace_export
then
3219
report_export
(
"
%w<!-- processing space glyph %U tagged %a case 2 -->
"
,
currentdepth
,
ca
,
last
)
3220
end
3221
end
3222
-- if somespace[currentcontent[nofcurrentcontent]] then
3223
-- if trace_export then
3224
-- report_export("%w<!-- removing space -->",currentdepth)
3225
-- end
3226
-- nofcurrentcontent = nofcurrentcontent - 1
3227
-- end
3228
nofcurrentcontent
=
nofcurrentcontent
+
1
3229
currentcontent
[
nofcurrentcontent
]
=
c
3230
end
3231
elseif
subtype
=
=
userskip_code
then
3232
if
getwidth
(
n
)
>
threshold
then
3233
if
last
and
not
somespace
[
currentcontent
[
nofcurrentcontent
]
]
then
3234
local
a
=
getattr
(
n
,
a_tagged
)
or
pat
3235
if
a
=
=
last
then
3236
if
trace_export
then
3237
report_export
(
"
%w<!-- injecting spacing 5a -->
"
,
currentdepth
)
3238
end
3239
nofcurrentcontent
=
nofcurrentcontent
+
1
3240
currentcontent
[
nofcurrentcontent
]
=
"
"
3241
elseif
a
then
3242
-- e.g LOGO<space>LOGO
3243
if
trace_export
then
3244
report_export
(
"
%w<!-- processing glue > threshold tagged %s becomes %s -->
"
,
currentdepth
,
last
,
a
)
3245
end
3246
pushcontent
(
)
3247
if
trace_export
then
3248
report_export
(
"
%w<!-- injecting spacing 5b -->
"
,
currentdepth
)
3249
end
3250
last
=
a
3251
nofcurrentcontent
=
nofcurrentcontent
+
1
3252
currentcontent
[
nofcurrentcontent
]
=
"
"
3253
currentnesting
=
taglist
[
last
]
3254
pushentry
(
currentnesting
)
3255
currentattribute
=
last
3256
end
3257
end
3258
end
3259
elseif
subtype
=
=
spaceskip_code
or
subtype
=
=
xspaceskip_code
then
3260
if
not
somespace
[
currentcontent
[
nofcurrentcontent
]
]
then
3261
local
a
=
getattr
(
n
,
a_tagged
)
or
pat
3262
if
a
=
=
last
then
3263
if
trace_export
then
3264
report_export
(
"
%w<!-- injecting spacing 7 (stay in element) -->
"
,
currentdepth
)
3265
end
3266
nofcurrentcontent
=
nofcurrentcontent
+
1
3267
currentcontent
[
nofcurrentcontent
]
=
"
"
3268
else
3269
if
trace_export
then
3270
report_export
(
"
%w<!-- injecting spacing 7 (end of element) -->
"
,
currentdepth
)
3271
end
3272
last
=
a
3273
pushcontent
(
)
3274
nofcurrentcontent
=
nofcurrentcontent
+
1
3275
currentcontent
[
nofcurrentcontent
]
=
"
"
3276
currentnesting
=
taglist
[
last
]
3277
pushentry
(
currentnesting
)
3278
currentattribute
=
last
3279
end
3280
end
3281
elseif
subtype
=
=
rightskip_code
then
3282
-- a line
3283
if
nofcurrentcontent
>
0
then
3284
local
r
=
currentcontent
[
nofcurrentcontent
]
3285
if
r
=
=
hyphen
then
3286
if
not
keephyphens
then
3287
nofcurrentcontent
=
nofcurrentcontent
-
1
3288
end
3289
elseif
pid
=
=
disc_code
then
3290
-- go on .. tricky: we should mark the glyhs as coming from a disc
3291
elseif
not
somespace
[
r
]
then
3292
local
a
=
getattr
(
n
,
a_tagged
)
or
pat
3293
if
a
=
=
last
then
3294
if
trace_export
then
3295
report_export
(
"
%w<!-- injecting spacing 1 (end of line, stay in element) -->
"
,
currentdepth
)
3296
end
3297
nofcurrentcontent
=
nofcurrentcontent
+
1
3298
currentcontent
[
nofcurrentcontent
]
=
"
"
3299
else
3300
if
trace_export
then
3301
report_export
(
"
%w<!-- injecting spacing 1 (end of line, end of element) -->
"
,
currentdepth
)
3302
end
3303
last
=
a
3304
pushcontent
(
)
3305
nofcurrentcontent
=
nofcurrentcontent
+
1
3306
currentcontent
[
nofcurrentcontent
]
=
"
"
3307
currentnesting
=
taglist
[
last
]
3308
pushentry
(
currentnesting
)
3309
currentattribute
=
last
3310
end
3311
end
3312
end
3313
elseif
subtype
=
=
parfillskip_code
then
3314
-- deal with paragraph endings (crossings) elsewhere and we quit here
3315
-- as we don't want the rightskip space addition
3316
if
maybewrong
then
3317
showmaybe
(
maybewrong
)
3318
end
3319
return
3320
end
3321
elseif
id
=
=
hlist_code
or
id
=
=
vlist_code
then
3322
local
ai
=
getattr
(
n
,
a_image
)
3323
if
ai
then
3324
local
at
=
getattr
(
n
,
a_tagged
)
or
pat
3325
if
nofcurrentcontent
>
0
then
3326
pushcontent
(
)
3327
pushentry
(
currentnesting
)
-- ??
3328
end
3329
pushentry
(
taglist
[
at
]
)
-- has an index, todo: flag empty element
3330
if
trace_export
then
3331
report_export
(
"
%w<!-- processing image tagged %a
"
,
currentdepth
,
last
)
3332
end
3333
last
=
nil
3334
currentparagraph
=
nil
3335
else
3336
-- we need to determine an end-of-line
3337
local
list
=
getlist
(
n
)
3338
if
list
then
3339
-- todo: no par checking needed in math
3340
local
at
=
getattr
(
n
,
a_tagged
)
or
pat
3341
collectresults
(
list
,
n
,
at
)
3342
end
3343
end
3344
elseif
id
=
=
kern_code
then
3345
local
kern
=
getkern
(
n
)
3346
if
kern
>
0
then
3347
local
a
=
getattr
(
n
,
a_tagged
)
or
pat
3348
local
t
=
taglist
[
a
]
3349
if
not
t
or
t
.
tagname
~
=
"
ignore
"
then
-- maybe earlier on top)
3350
local
limit
=
threshold
3351
if
p
then
3352
local
c
,
f
=
isglyph
(
p
)
3353
if
c
then
3354
limit
=
fontquads
[
f
]
/
4
3355
end
3356
end
3357
if
kern
>
limit
then
3358
if
last
and
not
somespace
[
currentcontent
[
nofcurrentcontent
]
]
then
3359
-- local a = getattr(n,a_tagged) or pat
3360
if
a
=
=
last
then
3361
if
not
somespace
[
currentcontent
[
nofcurrentcontent
]
]
then
3362
if
trace_export
then
3363
report_export
(
"
%w<!-- injecting spacing 8 (kern %p) -->
"
,
currentdepth
,
kern
)
3364
end
3365
nofcurrentcontent
=
nofcurrentcontent
+
1
3366
currentcontent
[
nofcurrentcontent
]
=
"
"
3367
end
3368
elseif
a
then
3369
-- e.g LOGO<space>LOGO
3370
if
trace_export
then
3371
report_export
(
"
%w<!-- processing kern, threshold %p, tag %s => %s -->
"
,
currentdepth
,
limit
,
last
,
a
)
3372
end
3373
last
=
a
3374
pushcontent
(
)
3375
if
trace_export
then
3376
report_export
(
"
%w<!-- injecting spacing 9 (kern %p) -->
"
,
currentdepth
,
kern
)
3377
end
3378
nofcurrentcontent
=
nofcurrentcontent
+
1
3379
currentcontent
[
nofcurrentcontent
]
=
"
"
3380
-- currentnesting = taglist[last]
3381
currentnesting
=
t
3382
pushentry
(
currentnesting
)
3383
currentattribute
=
last
3384
end
3385
end
3386
end
3387
end
3388
end
3389
elseif
id
=
=
whatsit_code
then
3390
if
subtype
=
=
userdefinedwhatsit_code
then
3391
-- similar to images, see above
3392
local
at
=
getattr
(
n
,
a_tagged
)
3393
if
nofcurrentcontent
>
0
then
3394
pushcontent
(
)
3395
pushentry
(
currentnesting
)
-- ??
3396
end
3397
pushentry
(
taglist
[
at
]
)
3398
if
trace_export
then
3399
report_export
(
"
%w<!-- processing anchor tagged %a
"
,
currentdepth
,
last
)
3400
end
3401
last
=
nil
3402
currentparagraph
=
nil
3403
end
3404
elseif
not
localparagraph
and
id
=
=
localpar_code
and
start_of_par
(
n
)
then
3405
localparagraph
=
getattr
(
n
,
a_taggedpar
)
3406
end
3407
p
=
n
3408
pid
=
id
3409
end
3410
if
maybewrong
then
3411
showmaybe
(
maybewrong
)
3412
end
3413
end
3414 3415
function
nodes
.
handlers
.
export
(
head
)
-- hooks into the page builder
3416
starttiming
(
treehash
)
3417
if
trace_export
then
3418
report_export
(
"
%w<!-- start flushing page -->
"
,
currentdepth
)
3419
end
3420
-- continueexport()
3421
restart
=
true
3422
collectresults
(
head
)
3423
if
trace_export
then
3424
report_export
(
"
%w<!-- stop flushing page -->
"
,
currentdepth
)
3425
end
3426
stoptiming
(
treehash
)
3427
return
head
3428
end
3429 3430
function
nodes
.
handlers
.
checkparcounter
(
p
)
3431
setattr
(
p
,
a_taggedpar
,
texgetcount
(
"
tagparcounter
"
)
+
1
)
3432
return
p
3433
end
3434 3435
function
builders
.
paragraphs
.
tag
(
head
)
3436
noftextblocks
=
noftextblocks
+
1
3437
for
n
,
subtype
in
nexthlist
,
head
do
3438
if
subtype
=
=
linelist_code
then
3439
setattr
(
n
,
a_textblock
,
noftextblocks
)
3440
elseif
subtype
=
=
glue_code
or
subtype
=
=
kern_code
then
-- no need to set fontkerns
3441
setattr
(
n
,
a_textblock
,
0
)
3442
end
3443
end
3444
return
false
3445
end
3446 3447
end
3448 3449
do
3450 3451
local
xmlcollected
=
xml
.
collected
3452
local
xmlsetcomment
=
xml
.
setcomment
3453 3454
local
xmlpreamble
=
[[
3455<?xml version="1.0" encoding="UTF-8" standalone="%standalone%" ?> 3456 3457<!-- 3458 3459 input filename : %filename% 3460 processing date : %date% 3461 context version : %contextversion% 3462 exporter version : %exportversion% 3463 3464--> 3465 3466
]]
3467 3468
local
flushtree
=
wrapups
.
flushtree
3469 3470
local
function
wholepreamble
(
standalone
)
3471
return
replacetemplate
(
xmlpreamble
,
{
3472
standalone
=
standalone
and
"
yes
"
or
"
no
"
,
3473
filename
=
tex
.
jobname
,
3474
date
=
included
.
date
and
backends
.
timestamp
(
)
,
3475
contextversion
=
environment
.
version
,
3476
exportversion
=
exportversion
,
3477
}
)
3478
end
3479 3480 3481
local
csspreamble
=
[[
3482<?xml-stylesheet type="text/css" href="%filename%" ?> 3483
]]
3484 3485
local
cssheadlink
=
[[
3486<link type="text/css" rel="stylesheet" href="%filename%" /> 3487
]]
3488 3489
local
function
allusedstylesheets
(
cssfiles
,
files
,
path
)
3490
local
done
=
{
}
3491
local
result
=
{
}
3492
local
extras
=
{
}
3493
for
i
=
1
,
#
cssfiles
do
3494
local
cssfile
=
cssfiles
[
i
]
3495
if
type
(
cssfile
)
~
=
"
string
"
then
3496
-- error
3497
elseif
cssfile
=
=
"
export-example.css
"
then
3498
-- ignore
3499
elseif
not
done
[
cssfile
]
then
3500
cssfile
=
file
.
join
(
path
,
cssfile
)
3501
report_export
(
"
adding css reference '%s'
"
,
cssfile
)
3502
files
[
#
files
+
1
]
=
cssfile
3503
result
[
#
result
+
1
]
=
replacetemplate
(
csspreamble
,
{
filename
=
cssfile
}
)
3504
extras
[
#
extras
+
1
]
=
replacetemplate
(
cssheadlink
,
{
filename
=
cssfile
}
)
3505
done
[
cssfile
]
=
true
3506
end
3507
end
3508
return
concat
(
result
)
,
concat
(
extras
)
3509
end
3510 3511
local
elementtemplate
=
[[
3512/* element="%element%" detail="%detail%" chain="%chain%" */ 3513 3514%element%, 3515%namespace%div.%element% { 3516 display: %display% ; 3517}
]]
3518 3519
local
detailtemplate
=
[[
3520/* element="%element%" detail="%detail%" chain="%chain%" */ 3521 3522%element%[detail=%detail%], 3523%namespace%div.%element%.%detail% { 3524 display: %display% ; 3525}
]]
3526 3527
-- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd" >
3528 3529
local
htmltemplate
=
[[
3530%preamble% 3531 3532<html xmlns="http://www.w3.org/1999/xhtml" xmlns:math="http://www.w3.org/1998/Math/MathML"> 3533 3534 <head> 3535 3536 <meta charset="utf-8"/> 3537 3538 <title>%title%</title> 3539 3540%style% 3541 3542 </head> 3543 <body> 3544 <div class="document" xmlns="http://www.pragma-ade.com/context/export"> 3545 3546<div class="warning">Rendering can be suboptimal because there is no default/fallback css loaded.</div> 3547 3548%body% 3549 3550 </div> 3551 </body> 3552</html> 3553
]]
3554 3555
local
displaymapping
=
{
3556
inline
=
"
inline
"
,
3557
display
=
"
block
"
,
3558
mixed
=
"
inline
"
,
3559
}
3560 3561
local
function
allusedelements
(
basename
)
3562
local
result
=
{
replacetemplate
(
namespacetemplate
,
{
3563
what
=
"
template
"
,
3564
filename
=
basename
,
3565
namespace
=
contextns
,
3566
-- cssnamespaceurl = usecssnamespace and cssnamespaceurl or "",
3567
cssnamespaceurl
=
cssnamespaceurl
,
3568
}
,
false
,
true
)
}
3569
for
element
,
details
in
sortedhash
(
used
)
do
3570
if
namespaces
[
element
]
then
3571
-- skip math
3572
else
3573
for
detail
,
what
in
sortedhash
(
details
)
do
3574
local
nature
=
what
[
1
]
or
"
display
"
3575
local
chain
=
what
[
2
]
3576
local
display
=
displaymapping
[
nature
]
or
"
block
"
3577
if
detail
=
=
"
"
then
3578
result
[
#
result
+
1
]
=
replacetemplate
(
elementtemplate
,
{
3579
element
=
element
,
3580
display
=
display
,
3581
chain
=
chain
,
3582
namespace
=
usecssnamespace
and
namespace
or
"
"
,
3583
}
)
3584
else
3585
result
[
#
result
+
1
]
=
replacetemplate
(
detailtemplate
,
{
3586
element
=
element
,
3587
display
=
display
,
3588
detail
=
detail
,
3589
chain
=
chain
,
3590
namespace
=
usecssnamespace
and
cssnamespace
or
"
"
,
3591
}
)
3592
end
3593
end
3594
end
3595
end
3596
return
concat
(
result
,
"
\n\n
"
)
3597
end
3598 3599
local
function
allcontent
(
tree
,
embed
)
3600
local
result
=
{
}
3601
flushtree
(
result
,
tree
.
data
,
"
display
"
)
-- we need to collect images
3602
result
=
concat
(
result
)
3603
-- no need to lpeg .. fast enough
3604
result
=
gsub
(
result
,
"
\n *\n
"
,
"
\n
"
)
3605
result
=
gsub
(
result
,
"
\n +([^< ])
"
,
"
\n%1
"
)
3606
return
result
3607
end
3608 3609
-- local xhtmlpreamble = [[
3610
-- <!DOCTYPE html PUBLIC
3611
-- "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN"
3612
-- "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd"
3613
-- >
3614
-- ]]
3615 3616
local
function
cleanxhtmltree
(
xmltree
)
3617
if
xmltree
then
3618
local
implicits
=
{
}
3619
local
explicits
=
{
}
3620
local
overloads
=
{
}
3621
for
e
in
xmlcollected
(
xmltree
,
"
*
"
)
do
3622
local
at
=
e
.
at
3623
if
at
then
3624
local
explicit
=
at
.
explicit
3625
local
implicit
=
at
.
implicit
3626
if
explicit
then
3627
if
not
explicits
[
explicit
]
then
3628
explicits
[
explicit
]
=
true
3629
at
.
id
=
explicit
3630
if
implicit
then
3631
overloads
[
implicit
]
=
explicit
3632
end
3633
end
3634
else
3635
if
implicit
and
not
implicits
[
implicit
]
then
3636
implicits
[
implicit
]
=
true
3637
at
.
id
=
"
aut:
"
.
.
implicit
3638
end
3639
end
3640
end
3641
end
3642
for
e
in
xmlcollected
(
xmltree
,
"
*
"
)
do
3643
local
at
=
e
.
at
3644
if
at
then
3645
local
internal
=
at
.
internal
3646
local
location
=
at
.
location
3647
if
internal
then
3648
if
location
then
3649
local
explicit
=
overloads
[
location
]
3650
if
explicit
then
3651
at
.
href
=
"
#
"
.
.
explicit
3652
else
3653
at
.
href
=
"
#aut:
"
.
.
internal
3654
end
3655
else
3656
at
.
href
=
"
#aut:
"
.
.
internal
3657
end
3658
else
3659
if
location
then
3660
at
.
href
=
"
#
"
.
.
location
3661
else
3662
local
url
=
at
.
url
3663
if
url
then
3664
at
.
href
=
url
3665
else
3666
local
file
=
at
.
file
3667
if
file
then
3668
at
.
href
=
file
3669
end
3670
end
3671
end
3672
end
3673
end
3674
end
3675
return
xmltree
3676
else
3677
return
xml
.
convert
(
'
<?xml version="1.0"?>\n<error>invalid xhtml tree</error>
'
)
3678
end
3679
end
3680 3681
-- maybe the reverse: be explicit about what is permitted
3682 3683
local
private
=
{
3684
destination
=
true
,
3685
prefix
=
true
,
3686
reference
=
true
,
3687
--
3688
id
=
true
,
3689
href
=
true
,
3690
--
3691
implicit
=
true
,
3692
explicit
=
true
,
3693
--
3694
url
=
true
,
3695
file
=
true
,
3696
internal
=
true
,
3697
location
=
true
,
3698
--
3699
name
=
true
,
-- image name
3700
used
=
true
,
-- image name
3701
page
=
true
,
-- image name
3702
width
=
true
,
3703
height
=
true
,
3704
--
3705
}
3706 3707
local
addclicks
=
true
3708
local
f_onclick
=
formatters
[
[[
location.href='%s'
]]
]
3709
local
f_onclick
=
formatters
[
[[
location.href='%s'
]]
]
3710 3711
local
p_cleanid
=
lpeg
.
replacer
{
[
"
:
"
]
=
"
-
"
}
3712
local
p_cleanhref
=
lpeg
.
Cs
(
lpeg
.
P
(
"
#
"
)
*
p_cleanid
)
3713 3714
local
p_splitter
=
lpeg
.
Ct
(
(
3715
lpeg
.
Carg
(
1
)
*
lpeg
.
C
(
(
1
-
lpeg
.
P
(
"
"
)
)
^
1
)
/
function
(
d
,
s
)
if
not
d
[
s
]
then
d
[
s
]
=
true
return
s
end
end
3716
*
lpeg
.
P
(
"
"
)
^
0
)
^
1
)
3717 3718 3719
local
classes
=
table
.
setmetatableindex
(
function
(
t
,
k
)
3720
local
v
=
concat
(
lpegmatch
(
p_splitter
,
k
,
1
,
{
}
)
,
"
"
)
3721
t
[
k
]
=
v
3722
return
v
3723
end
)
3724 3725
local
function
makeclass
(
tg
,
at
)
3726
local
detail
=
at
.
detail
3727
local
chain
=
at
.
chain
3728
local
extra
=
nil
3729
local
classes
=
{
}
3730
local
nofclasses
=
0
3731
at
.
detail
=
nil
3732
at
.
chain
=
nil
3733
for
k
,
v
in
next
,
at
do
3734
if
not
private
[
k
]
then
3735
nofclasses
=
nofclasses
+
1
3736
classes
[
nofclasses
]
=
k
.
.
"
-
"
.
.
v
3737
end
3738
end
3739
if
detail
and
detail
~
=
"
"
then
3740
if
chain
and
chain
~
=
"
"
then
3741
if
chain
~
=
detail
then
3742
extra
=
classes
[
tg
.
.
"
"
.
.
chain
.
.
"
"
.
.
detail
]
3743
elseif
tg
~
=
detail
then
3744
extra
=
detail
3745
end
3746
elseif
tg
~
=
detail
then
3747
extra
=
detail
3748
end
3749
elseif
chain
and
chain
~
=
"
"
then
3750
if
tg
~
=
chain
then
3751
extra
=
chain
3752
end
3753
end
3754
-- in this order
3755
if
nofclasses
>
0
then
3756
sort
(
classes
)
3757
classes
=
concat
(
classes
,
"
"
)
3758
if
extra
then
3759
return
tg
.
.
"
"
.
.
extra
.
.
"
"
.
.
classes
3760
else
3761
return
tg
.
.
"
"
.
.
classes
3762
end
3763
else
3764
if
extra
then
3765
return
tg
.
.
"
"
.
.
extra
3766
else
3767
return
tg
3768
end
3769
end
3770
end
3771 3772
-- Some elements are not supported (well) in css so we need to retain them. For
3773
-- instance, tablecells have no colspan so basically that renders css table div
3774
-- elements quite useless. A side effect is that we nwo can have conflicts when
3775
-- we mix in with other html (as there is no reset). Of course, when it eventually
3776
-- gets added, there is a change then that those not using the div abstraction
3777
-- will be rediculed.
3778
--
3779
-- a table tr td th thead tbody tfoot
3780
--
3781 3782
local
crappycss
=
{
3783
table
=
"
table
"
,
tabulate
=
"
table
"
,
3784
tablehead
=
"
thead
"
,
tabulatehead
=
"
thead
"
,
3785
tablebody
=
"
tbody
"
,
tabulatebody
=
"
tbody
"
,
3786
tablefoot
=
"
tfoot
"
,
tabulatefoot
=
"
tfoot
"
,
3787
tablerow
=
"
tr
"
,
tabulaterow
=
"
tr
"
,
3788
tablecell
=
"
td
"
,
tabulatecell
=
"
td
"
,
3789
}
3790 3791
local
cssmapping
=
false
3792 3793
directives
.
register
(
"
export.nativetags
"
,
function
(
v
)
3794
cssmapping
=
v
and
crappycss
or
false
3795
end
)
3796 3797
local
function
remap
(
specification
,
source
,
target
)
3798
local
comment
=
nil
-- share comments
3799
for
c
in
xmlcollected
(
source
,
"
*
"
)
do
3800
if
not
c
.
special
then
3801
local
tg
=
c
.
tg
3802
local
ns
=
c
.
ns
3803
if
ns
=
=
"
m
"
then
3804
if
false
then
-- yes or no
3805
c
.
ns
=
"
"
3806
c
.
at
[
"
xmlns:m
"
]
=
nil
3807
end
3808
-- elseif tg == "a" then
3809
-- c.ns = ""
3810
else
3811
local
dt
=
c
.
dt
3812
local
nt
=
#
dt
3813
if
nt
=
=
0
or
(
nt
=
=
1
and
dt
[
1
]
=
=
"
"
)
then
3814
if
comment
then
3815
c
.
dt
=
comment
3816
else
3817
xmlsetcomment
(
c
,
"
empty
"
)
3818
comment
=
c
.
dt
3819
end
3820
end
3821
local
at
=
c
.
at
3822
local
class
=
nil
3823
local
label
=
nil
3824
if
tg
=
=
"
document
"
then
3825
at
.
href
=
nil
3826
at
.
detail
=
nil
3827
at
.
chain
=
nil
3828
elseif
tg
=
=
"
metavariable
"
then
3829
label
=
at
.
name
3830
at
.
detail
=
"
metaname-
"
.
.
label
3831
class
=
makeclass
(
tg
,
at
)
3832
else
3833
class
=
makeclass
(
tg
,
at
)
3834
end
3835
local
id
=
at
.
id
3836
local
href
=
at
.
href
3837
local
attr
=
nil
3838
if
id
then
3839
id
=
lpegmatch
(
p_cleanid
,
id
)
or
id
3840
if
href
then
3841
href
=
lpegmatch
(
p_cleanhref
,
href
)
or
href
3842
attr
=
{
3843
class
=
class
,
3844
id
=
id
,
3845
href
=
href
,
3846
onclick
=
addclicks
and
f_onclick
(
href
)
or
nil
,
3847
}
3848
else
3849
attr
=
{
3850
class
=
class
,
3851
id
=
id
,
3852
}
3853
end
3854
else
3855
if
href
then
3856
href
=
lpegmatch
(
p_cleanhref
,
href
)
or
href
3857
attr
=
{
3858
class
=
class
,
3859
href
=
href
,
3860
onclick
=
addclicks
and
f_onclick
(
href
)
or
nil
,
3861
}
3862
else
3863
attr
=
{
3864
class
=
class
,
3865
}
3866
end
3867
end
3868
c
.
at
=
attr
3869
if
label
then
3870
attr
.
label
=
label
3871
end
3872
c
.
tg
=
cssmapping
and
cssmapping
[
tg
]
or
"
div
"
3873
end
3874
end
3875
end
3876
end
3877 3878
-- local cssfile = nil directives.register("backend.export.css", function(v) cssfile = v end)
3879 3880
local
addsuffix
=
file
.
addsuffix
3881
local
joinfile
=
file
.
join
3882
local
nameonly
=
file
.
nameonly
3883
local
basename
=
file
.
basename
3884 3885
local
embedfile
=
false
directives
.
register
(
"
export.embed
"
,
function
(
v
)
embedfile
=
v
end
)
3886 3887
function
structurestags
.
finishexport
(
)
3888 3889
if
exporting
then
3890
exporting
=
false
3891
else
3892
return
3893
end
3894 3895
local
onlyxml
=
finetuning
.
export
=
=
v_xml
3896 3897
starttiming
(
treehash
)
3898
--
3899
finishexport
(
)
3900
--
3901
report_export
(
"
"
)
3902
if
onlyxml
then
3903
report_export
(
"
exporting xml, no other files
"
)
3904
else
3905
report_export
(
"
exporting xml, xhtml, html and css files
"
)
3906
end
3907
report_export
(
"
"
)
3908
--
3909
wrapups
.
fixtree
(
tree
)
3910
wrapups
.
collapsetree
(
tree
)
3911
wrapups
.
indextree
(
tree
)
3912
wrapups
.
checktree
(
tree
)
3913
wrapups
.
breaktree
(
tree
)
3914
wrapups
.
finalizetree
(
tree
)
3915
--
3916
wrapups
.
hashlistdata
(
)
3917
--
3918
local
askedname
=
finetuning
.
file
3919
--
3920
-- we use a dedicated subpath:
3921
--
3922
-- ./jobname-export
3923
-- ./jobname-export/images
3924
-- ./jobname-export/styles
3925
-- ./jobname-export/styles
3926
-- ./jobname-export/jobname-export.xml
3927
-- ./jobname-export/jobname-export.xhtml
3928
-- ./jobname-export/jobname-export.html
3929
-- ./jobname-export/jobname-specification.lua
3930
-- ./jobname-export/styles/jobname-defaults.css
3931
-- ./jobname-export/styles/jobname-styles.css
3932
-- ./jobname-export/styles/jobname-images.css
3933
-- ./jobname-export/styles/jobname-templates.css
3934 3935
if
type
(
askedname
)
~
=
"
string
"
or
askedname
=
=
"
"
then
3936
askedname
=
tex
.
jobname
3937
end
3938 3939
local
usedname
=
nameonly
(
askedname
)
3940
local
basepath
=
usedname
.
.
"
-export
"
3941
local
imagepath
=
joinfile
(
basepath
,
"
images
"
)
3942
local
stylepath
=
joinfile
(
basepath
,
"
styles
"
)
3943 3944
local
function
validpath
(
what
,
pathname
)
3945
if
lfs
.
isdir
(
pathname
)
then
3946
report_export
(
"
using existing %s path %a
"
,
what
,
pathname
)
3947
return
pathname
3948
end
3949
lfs
.
mkdir
(
pathname
)
3950
if
lfs
.
isdir
(
pathname
)
then
3951
report_export
(
"
using cretated %s path %a
"
,
what
,
basepath
)
3952
return
pathname
3953
else
3954
report_export
(
"
unable to create %s path %a
"
,
what
,
basepath
)
3955
return
false
3956
end
3957
end
3958 3959
if
not
(
validpath
(
"
export
"
,
basepath
)
and
validpath
(
"
images
"
,
imagepath
)
and
validpath
(
"
styles
"
,
stylepath
)
)
then
3960
return
3961
end
3962 3963
-- we're now on the dedicated export subpath so we can't clash names
3964
--
3965
-- a xhtml suffix no longer seems to be work well with browsers
3966 3967
local
xmlfilebase
=
addsuffix
(
usedname
.
.
"
-raw
"
,
"
xml
"
)
3968
local
xhtmlfilebase
=
addsuffix
(
usedname
.
.
"
-tag
"
,
"
xhtml
"
)
3969
local
htmlfilebase
=
addsuffix
(
usedname
.
.
"
-div
"
,
"
html
"
)
3970
local
specificationfilebase
=
addsuffix
(
usedname
.
.
"
-pub
"
,
"
lua
"
)
3971 3972
local
xmlfilename
=
joinfile
(
basepath
,
xmlfilebase
)
3973
local
xhtmlfilename
=
joinfile
(
basepath
,
xhtmlfilebase
)
3974
local
htmlfilename
=
joinfile
(
basepath
,
htmlfilebase
)
3975
local
specificationfilename
=
joinfile
(
basepath
,
specificationfilebase
)
3976
--
3977
local
defaultfilebase
=
addsuffix
(
usedname
.
.
"
-defaults
"
,
"
css
"
)
3978
local
imagefilebase
=
addsuffix
(
usedname
.
.
"
-images
"
,
"
css
"
)
3979
local
stylefilebase
=
addsuffix
(
usedname
.
.
"
-styles
"
,
"
css
"
)
3980
local
templatefilebase
=
addsuffix
(
usedname
.
.
"
-templates
"
,
"
css
"
)
3981
--
3982
local
defaultfilename
=
joinfile
(
stylepath
,
defaultfilebase
)
3983
local
imagefilename
=
joinfile
(
stylepath
,
imagefilebase
)
3984
local
stylefilename
=
joinfile
(
stylepath
,
stylefilebase
)
3985
local
templatefilename
=
joinfile
(
stylepath
,
templatefilebase
)
3986 3987
local
cssfile
=
finetuning
.
cssfile
3988 3989
-- we keep track of all used files
3990 3991
local
files
=
{
3992
}
3993 3994
-- we always load the defaults and optionally extra css files; we also copy the example
3995
-- css file so that we always have the latest version
3996 3997
local
cssfiles
=
{
3998
defaultfilebase
,
3999
imagefilebase
,
4000
stylefilebase
,
4001
}
4002 4003
local
cssextra
=
cssfile
and
table
.
unique
(
settings_to_array
(
cssfile
)
)
or
{
}
4004 4005
-- at this point we're ready for the content; the collector also does some
4006
-- housekeeping and data collecting; at this point we still have an xml
4007
-- representation that uses verbose element names and carries information in
4008
-- attributes
4009 4010
local
data
=
tree
.
data
4011
for
i
=
1
,
#
data
do
4012
if
data
[
i
]
.
tg
~
=
"
document
"
then
4013
data
[
i
]
=
{
}
4014
end
4015
end
4016 4017
local
result
=
allcontent
(
tree
,
embedmath
)
-- embedfile is for testing
4018 4019
-- ugly but so be it:
4020 4021
local
extradata
=
structures
.
tags
.
getextradata
(
)
4022
if
extradata
then
4023
local
t
=
{
"
"
}
4024
t
[
#
t
+
1
]
=
"
<extradata>
"
4025
for
name
,
action
in
sortedhash
(
extradata
)
do
4026
t
[
#
t
+
1
]
=
action
(
)
4027
end
4028
t
[
#
t
+
1
]
=
"
</extradata>
"
4029
t
[
#
t
+
1
]
=
"
</document>
"
4030
-- we use a function because otherwise we can have a bad capture index
4031
result
=
gsub
(
result
,
"
</document>
"
,
function
(
)
4032
return
concat
(
t
,
"
\n
"
)
4033
end
)
4034
end
4035 4036
-- done with ugly
4037 4038
if
onlyxml
then
4039 4040
os
.
remove
(
defaultfilename
)
4041
os
.
remove
(
imagefilename
)
4042
os
.
remove
(
stylefilename
)
4043
os
.
remove
(
templatefilename
)
4044 4045
for
i
=
1
,
#
cssextra
do
4046
os
.
remove
(
joinfile
(
stylepath
,
basename
(
source
)
)
)
4047
end
4048 4049
-- os.remove(xmlfilename)
4050 4051
os
.
remove
(
imagefilename
)
4052
os
.
remove
(
stylefilename
)
4053
os
.
remove
(
templatefilename
)
4054
os
.
remove
(
xhtmlfilename
)
4055
os
.
remove
(
specificationfilename
)
4056
os
.
remove
(
htmlfilename
)
4057 4058
result
=
concat
{
4059
wholepreamble
(
true
)
,
4060
"
<!-- This export file is used for filtering runtime only! -->\n
"
,
4061
result
,
4062
}
4063 4064
report_export
(
"
saving xml data in %a
"
,
xmlfilename
)
4065
io
.
savedata
(
xmlfilename
,
result
)
4066 4067
return
4068 4069
end
4070 4071
local
examplefilename
=
resolvers
.
findfile
(
"
export-example.css
"
)
4072
if
examplefilename
then
4073
local
data
=
io
.
loaddata
(
examplefilename
)
4074
if
not
data
or
data
=
=
"
"
then
4075
data
=
"
/* missing css file */
"
4076
elseif
not
usecssnamespace
then
4077
data
=
gsub
(
data
,
cssnamespace
,
"
"
)
4078
end
4079
io
.
savedata
(
defaultfilename
,
data
)
4080
end
4081 4082
if
cssfile
then
4083
for
i
=
1
,
#
cssextra
do
4084
local
source
=
addsuffix
(
cssextra
[
i
]
,
"
css
"
)
4085
local
target
=
joinfile
(
stylepath
,
basename
(
source
)
)
4086
cssfiles
[
#
cssfiles
+
1
]
=
source
4087
if
not
lfs
.
isfile
(
source
)
then
4088
source
=
joinfile
(
"
../
"
,
source
)
4089
end
4090
if
lfs
.
isfile
(
source
)
then
4091
report_export
(
"
copying %s
"
,
source
)
4092
file
.
copy
(
source
,
target
)
4093
end
4094
end
4095
end
4096 4097
local
x_styles
,
h_styles
=
allusedstylesheets
(
cssfiles
,
files
,
"
styles
"
)
4098 4099
local
attach
=
backends
.
nodeinjections
.
attachfile
4100 4101
if
embedfile
and
attach
then
4102
-- only for testing
4103
attach
{
4104
data
=
concat
{
wholepreamble
(
true
)
,
result
}
,
4105
name
=
basename
(
xmlfilename
)
,
4106
registered
=
"
export
"
,
4107
title
=
"
raw xml export
"
,
4108
method
=
v_hidden
,
4109
mimetype
=
"
application/mathml+xml
"
,
4110
}
4111
end
4112 4113
result
=
concat
{
4114
wholepreamble
(
true
)
,
4115
x_styles
,
-- adds to files
4116
result
,
4117
}
4118 4119
cssfiles
=
table
.
unique
(
cssfiles
)
4120 4121
-- we're now ready for saving the result in the xml file
4122 4123
report_export
(
"
saving xml data in %a
"
,
xmlfilename
)
4124
io
.
savedata
(
xmlfilename
,
result
)
4125 4126
report_export
(
"
saving css image definitions in %a
"
,
imagefilename
)
4127
io
.
savedata
(
imagefilename
,
wrapups
.
allusedimages
(
usedname
)
)
4128 4129
report_export
(
"
saving css style definitions in %a
"
,
stylefilename
)
4130
io
.
savedata
(
stylefilename
,
wrapups
.
allusedstyles
(
usedname
)
)
4131 4132
report_export
(
"
saving css template in %a
"
,
templatefilename
)
4133
io
.
savedata
(
templatefilename
,
allusedelements
(
usedname
)
)
4134 4135
-- additionally we save an xhtml file; for that we load the file as xml tree
4136 4137
report_export
(
"
saving xhtml variant in %a
"
,
xhtmlfilename
)
4138 4139
local
xmltree
=
cleanxhtmltree
(
xml
.
convert
(
result
)
)
4140 4141
-- local xmltree = xml.convert(result)
4142
-- for c in xml.collected(xmltree,"m:mtext[lastindex()=1]/m:mrow") do
4143
-- print(c)
4144
-- end
4145
-- for c in xml.collected(xmltree,"mtext/mrow") do
4146
-- print(c)
4147
-- end
4148
-- local xmltree = cleanxhtmltree(xmltree)
4149 4150
xml
.
save
(
xmltree
,
xhtmlfilename
)
4151 4152
-- now we save a specification file that can b eused for generating an epub file
4153 4154
-- looking at identity is somewhat redundant as we also inherit from interaction
4155
-- at the tex end
4156 4157
local
identity
=
interactions
.
general
.
getidentity
(
)
4158
local
metadata
=
structures
.
tags
.
getmetadata
(
)
4159 4160
local
specification
=
{
4161
name
=
usedname
,
4162
identifier
=
os
.
uuid
(
)
,
4163
images
=
wrapups
.
uniqueusedimages
(
)
,
4164
imagefile
=
joinfile
(
"
styles
"
,
imagefilebase
)
,
4165
imagepath
=
"
images
"
,
4166
stylepath
=
"
styles
"
,
4167
xmlfiles
=
{
xmlfilebase
}
,
4168
xhtmlfiles
=
{
xhtmlfilebase
}
,
4169
htmlfiles
=
{
htmlfilebase
}
,
4170
styles
=
cssfiles
,
4171
htmlroot
=
htmlfilebase
,
4172
language
=
languagenames
[
texgetcount
(
"
mainlanguagenumber
"
)
]
,
4173
title
=
validstring
(
finetuning
.
title
)
or
validstring
(
identity
.
title
)
,
4174
subtitle
=
validstring
(
finetuning
.
subtitle
)
or
validstring
(
identity
.
subtitle
)
,
4175
author
=
validstring
(
finetuning
.
author
)
or
validstring
(
identity
.
author
)
,
4176
firstpage
=
validstring
(
finetuning
.
firstpage
)
,
4177
lastpage
=
validstring
(
finetuning
.
lastpage
)
,
4178
metadata
=
metadata
,
4179
}
4180 4181
report_export
(
"
saving specification in %a
"
,
specificationfilename
,
specificationfilename
)
4182 4183
xml
.
wipe
(
xmltree
,
"
metadata
"
)
-- maybe optional
4184 4185
io
.
savedata
(
specificationfilename
,
table
.
serialize
(
specification
,
true
)
)
4186 4187
-- the html export for epub is different in the sense that it uses div's instead of
4188
-- specific tags
4189 4190
report_export
(
"
saving div based alternative in %a
"
,
htmlfilename
)
4191 4192
remap
(
specification
,
xmltree
)
4193 4194
-- believe it or not, but a <title/> can prevent viewing in browsers
4195 4196
local
title
=
specification
.
title
4197 4198
if
not
title
or
title
=
=
"
"
then
4199
title
=
metadata
.
title
4200
if
not
title
or
title
=
=
"
"
then
4201
title
=
usedname
-- was: "no title"
4202
end
4203
end
4204 4205
local
variables
=
{
4206
style
=
h_styles
,
4207
body
=
xml
.
tostring
(
xml
.
first
(
xmltree
,
"
/div
"
)
)
,
4208
preamble
=
wholepreamble
(
false
)
,
4209
title
=
title
,
4210
}
4211 4212
io
.
savedata
(
htmlfilename
,
replacetemplate
(
htmltemplate
,
variables
,
"
xml
"
)
)
4213 4214
-- finally we report how an epub file can be made (using the specification)
4215 4216
report_export
(
"
"
)
4217
report_export
(
'
create epub with: mtxrun --script epub --make "%s" [--purge --rename --svgmath]
'
,
usedname
)
4218
report_export
(
"
"
)
4219 4220
stoptiming
(
treehash
)
4221
end
4222 4223
local
enableaction
=
nodes
.
tasks
.
enableaction
4224 4225
function
structurestags
.
initializeexport
(
)
4226
if
not
exporting
then
4227
report_export
(
"
enabling export to xml
"
)
4228
enableaction
(
"
shipouts
"
,
"
nodes.handlers.export
"
)
4229
enableaction
(
"
shipouts
"
,
"
nodes.handlers.accessibility
"
)
4230
enableaction
(
"
math
"
,
"
noads.handlers.tags
"
)
4231
enableaction
(
"
everypar
"
,
"
nodes.handlers.checkparcounter
"
)
4232
luatex
.
registerstopactions
(
structurestags
.
finishexport
)
4233
exporting
=
true
4234
end
4235
end
4236 4237
function
structurestags
.
setupexport
(
t
)
4238
merge
(
finetuning
,
t
)
4239
keephyphens
=
finetuning
.
hyphen
=
=
v_yes
4240
exportproperties
=
finetuning
.
properties
4241
if
exportproperties
=
=
v_no
then
4242
exportproperties
=
false
4243
end
4244
end
4245 4246
statistics
.
register
(
"
xml exporting time
"
,
function
(
)
4247
if
exporting
then
4248
return
string
.
format
(
"
%s seconds, version %s
"
,
statistics
.
elapsedtime
(
treehash
)
,
exportversion
)
4249
end
4250
end
)
4251 4252
end
4253 4254
-- These are called at the tex end:
4255 4256
implement
{
4257
name
=
"
setupexport
"
,
4258
actions
=
structurestags
.
setupexport
,
4259
arguments
=
{
4260
{
4261
{
"
align
"
}
,
4262
{
"
bodyfont
"
,
"
dimen
"
}
,
4263
{
"
width
"
,
"
dimen
"
}
,
4264
{
"
properties
"
}
,
4265
{
"
hyphen
"
}
,
4266
{
"
title
"
}
,
4267
{
"
subtitle
"
}
,
4268
{
"
author
"
}
,
4269
{
"
firstpage
"
}
,
4270
{
"
lastpage
"
}
,
4271
{
"
svgstyle
"
}
,
4272
{
"
cssfile
"
}
,
4273
{
"
file
"
}
,
4274
{
"
export
"
}
,
4275
}
4276
}
4277
}
4278 4279
implement
{
4280
name
=
"
finishexport
"
,
4281
actions
=
structurestags
.
finishexport
,
4282
}
4283 4284
implement
{
4285
name
=
"
initializeexport
"
,
4286
actions
=
structurestags
.
initializeexport
,
4287
}
4288 4289
implement
{
4290
name
=
"
settagitemgroup
"
,
4291
actions
=
structurestags
.
setitemgroup
,
4292
arguments
=
{
"
boolean
"
,
"
integer
"
,
"
string
"
}
4293
}
4294 4295
implement
{
4296
name
=
"
settagitem
"
,
4297
actions
=
structurestags
.
setitem
,
4298
arguments
=
"
string
"
4299
}
4300 4301
implement
{
4302
name
=
"
settagfloat
"
,
4303
actions
=
structurestags
.
setfloat
,
4304
arguments
=
"
2 strings
"
,
4305
}
4306 4307
implement
{
4308
name
=
"
settagformulacontent
"
,
4309
actions
=
structurestags
.
setformulacontent
,
4310
arguments
=
"
integer
"
,
4311
}
4312 4313
implement
{
4314
name
=
"
settagdelimitedsymbol
"
,
4315
actions
=
structurestags
.
settagdelimitedsymbol
,
4316
arguments
=
"
string
"
4317
}
4318 4319
implement
{
4320
name
=
"
settagsubsentencesymbol
"
,
4321
actions
=
structurestags
.
settagsubsentencesymbol
,
4322
arguments
=
"
string
"
4323
}
4324 4325
implement
{
4326
name
=
"
settagsynonym
"
,
4327
actions
=
structurestags
.
setsynonym
,
4328
arguments
=
"
string
"
4329
}
4330 4331
implement
{
4332
name
=
"
settagsorting
"
,
4333
actions
=
structurestags
.
setsorting
,
4334
arguments
=
"
string
"
4335
}
4336 4337
implement
{
4338
name
=
"
settagnotation
"
,
4339
actions
=
structurestags
.
setnotation
,
4340
arguments
=
{
"
string
"
,
"
integer
"
}
4341
}
4342 4343
implement
{
4344
name
=
"
settagnotationsymbol
"
,
4345
actions
=
structurestags
.
setnotationsymbol
,
4346
arguments
=
{
"
string
"
,
"
integer
"
}
4347
}
4348 4349
implement
{
4350
name
=
"
settaghighlight
"
,
4351
actions
=
structurestags
.
sethighlight
,
4352
arguments
=
{
"
string
"
,
"
string
"
,
"
integer
"
,
"
integer
"
}
4353
}
4354 4355
implement
{
4356
name
=
"
settagconstruct
"
,
4357
actions
=
structurestags
.
setconstruct
,
4358
arguments
=
{
"
string
"
,
"
string
"
,
"
integer
"
,
"
integer
"
}
4359
}
4360 4361
implement
{
4362
name
=
"
settagfigure
"
,
4363
actions
=
structurestags
.
setfigure
,
4364
arguments
=
{
"
string
"
,
"
string
"
,
"
string
"
,
"
dimen
"
,
"
dimen
"
,
"
string
"
}
4365
}
4366 4367
implement
{
4368
name
=
"
settagcombination
"
,
4369
actions
=
structurestags
.
setcombination
,
4370
arguments
=
{
"
integer
"
,
"
integer
"
}
4371
}
4372 4373
implement
{
4374
name
=
"
settagtablecell
"
,
4375
actions
=
structurestags
.
settablecell
,
4376
arguments
=
{
"
integer
"
,
"
integer
"
,
"
integer
"
}
4377
}
4378 4379
implement
{
4380
name
=
"
settagtabulatecell
"
,
4381
actions
=
structurestags
.
settabulatecell
,
4382
arguments
=
{
"
integer
"
,
"
integer
"
}
,
4383
}
4384 4385
implement
{
4386
name
=
"
settagregister
"
,
4387
actions
=
structurestags
.
setregister
,
4388
arguments
=
{
"
string
"
,
"
integer
"
}
4389
}
4390 4391
implement
{
4392
name
=
"
settaglist
"
,
4393
actions
=
structurestags
.
setlist
,
4394
arguments
=
"
integer
"
4395
}
4396 4397
implement
{
4398
name
=
"
settagpublication
"
,
4399
actions
=
structurestags
.
setpublication
,
4400
arguments
=
"
2 strings
"
4401
}
4402 4403
implement
{
4404
name
=
"
settagparagraph
"
,
4405
actions
=
structurestags
.
setparagraph
,
4406
arguments
=
"
string
"
4407
}
4408