buff-ver.lua /size: 30 Kb    last modification: 2020-07-01 14:35
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
buff-ver
'
]
=
{
2
version
=
1
.
001
,
3
comment
=
"
companion to buff-ver.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
-- The default visualizers have reserved names starting with buff-imp-*. Users are
10
-- supposed to use different names for their own variants.
11
--
12
-- todo: skip=auto
13
--
14
-- todo: update to match context scite lexing
15 16
local
type
,
next
,
rawset
,
rawget
,
setmetatable
,
getmetatable
,
tonumber
=
type
,
next
,
rawset
,
rawget
,
setmetatable
,
getmetatable
,
tonumber
17
local
lower
,
upper
,
match
,
find
,
sub
=
string
.
lower
,
string
.
upper
,
string
.
match
,
string
.
find
,
string
.
sub
18
local
splitlines
=
string
.
splitlines
19
local
concat
=
table
.
concat
20
local
C
,
P
,
R
,
S
,
V
,
Carg
,
Cc
,
Cs
=
lpeg
.
C
,
lpeg
.
P
,
lpeg
.
R
,
lpeg
.
S
,
lpeg
.
V
,
lpeg
.
Carg
,
lpeg
.
Cc
,
lpeg
.
Cs
21
local
patterns
,
lpegmatch
,
is_lpeg
=
lpeg
.
patterns
,
lpeg
.
match
,
lpeg
.
is_lpeg
22 23
local
trace_visualize
=
false
trackers
.
register
(
"
buffers.visualize
"
,
function
(
v
)
trace_visualize
=
v
end
)
24
local
report_visualizers
=
logs
.
reporter
(
"
buffers
"
,
"
visualizers
"
)
25 26
local
allocate
=
utilities
.
storage
.
allocate
27 28
visualizers
=
visualizers
or
{
}
29
local
specifications
=
allocate
(
)
30
visualizers
.
specifications
=
specifications
31 32
local
context
=
context
33
local
commands
=
commands
34
local
implement
=
interfaces
.
implement
35 36
local
formatters
=
string
.
formatters
37 38
local
tabtospace
=
utilities
.
strings
.
tabtospace
39
local
variables
=
interfaces
.
variables
40
local
settings_to_array
=
utilities
.
parsers
.
settings_to_array
41
local
variables
=
interfaces
.
variables
42
local
findfile
=
resolvers
.
findfile
43
local
addsuffix
=
file
.
addsuffix
44 45
local
v_yes
=
variables
.
yes
46
local
v_no
=
variables
.
no
47
local
v_last
=
variables
.
last
48
local
v_all
=
variables
.
all
49
local
v_absolute
=
variables
.
absolute
50
----- v_inline = variables.inline -- not !
51
----- v_display = variables.display -- not !
52 53
-- beware, all macros have an argument:
54 55
local
ctx_inlineverbatimnewline
=
context
.
doinlineverbatimnewline
56
local
ctx_inlineverbatimbeginline
=
context
.
doinlineverbatimbeginline
57
local
ctx_inlineverbatimemptyline
=
context
.
doinlineverbatimemptyline
58
local
ctx_inlineverbatimstart
=
context
.
doinlineverbatimstart
59
local
ctx_inlineverbatimstop
=
context
.
doinlineverbatimstop
60 61
local
ctx_displayverbatiminitialize
=
context
.
dodisplayverbatiminitialize
-- the number of arguments might change over time
62
local
ctx_displayverbatimnewline
=
context
.
dodisplayverbatimnewline
63
local
ctx_displayverbatimbeginline
=
context
.
dodisplayverbatimbeginline
64
local
ctx_displayverbatimemptyline
=
context
.
dodisplayverbatimemptyline
65
local
ctx_displayverbatimstart
=
context
.
dodisplayverbatimstart
66
local
ctx_displayverbatimstop
=
context
.
dodisplayverbatimstop
67 68
local
ctx_verbatim
=
context
.
verbatim
69
local
ctx_verbatimspace
=
context
.
doverbatimspace
70 71
local
CargOne
=
Carg
(
1
)
72 73
local
function
f_emptyline
(
s
,
settings
)
74
if
settings
and
settings
.
nature
=
=
"
inline
"
then
75
ctx_inlineverbatimemptyline
(
)
76
else
77
ctx_displayverbatimemptyline
(
)
78
end
79
end
80 81
local
function
f_beginline
(
s
,
settings
)
82
if
settings
and
settings
.
nature
=
=
"
inline
"
then
83
ctx_inlineverbatimbeginline
(
)
84
else
85
ctx_displayverbatimbeginline
(
)
86
end
87
end
88 89
local
function
f_newline
(
s
,
settings
)
90
if
settings
and
settings
.
nature
=
=
"
inline
"
then
91
ctx_inlineverbatimnewline
(
)
92
else
93
ctx_displayverbatimnewline
(
)
94
end
95
end
96 97
local
function
f_start
(
s
,
settings
)
98
if
settings
and
settings
.
nature
=
=
"
inline
"
then
99
ctx_inlineverbatimstart
(
)
100
else
101
ctx_displayverbatimstart
(
)
102
end
103
end
104 105
local
function
f_stop
(
s
,
settings
)
106
if
settings
and
settings
.
nature
=
=
"
inline
"
then
107
ctx_inlineverbatimstop
(
)
108
else
109
ctx_displayverbatimstop
(
)
110
end
111
end
112 113
local
function
f_default
(
s
)
-- (s,settings)
114
ctx_verbatim
(
s
)
115
end
116 117
local
function
f_space
(
)
-- (s,settings)
118
ctx_verbatimspace
(
)
119
end
120 121
local
function
f_signal
(
)
-- (s,settings)
122
-- we use these for special purposes
123
end
124 125
local
signal
=
"
\000
"
126 127
visualizers
.
signal
=
signal
128
visualizers
.
signalpattern
=
P
(
signal
)
129 130
local
functions
=
{
131
__index
=
{
132
emptyline
=
f_emptyline
,
133
newline
=
f_newline
,
134
default
=
f_default
,
135
beginline
=
f_beginline
,
136
space
=
f_space
,
137
start
=
f_start
,
138
stop
=
f_stop
,
139
signal
=
f_signal
,
140
}
141
}
142 143
local
handlers
=
{
}
144 145
function
visualizers
.
newhandler
(
name
,
data
)
146
local
tname
=
type
(
name
)
147
local
tdata
=
type
(
data
)
148
if
tname
=
=
"
table
"
then
-- (data)
149
setmetatable
(
name
,
getmetatable
(
name
)
or
functions
)
150
return
name
151
elseif
tname
=
=
"
string
"
then
152
if
tdata
=
=
"
string
"
then
-- ("name","parent")
153
local
result
=
{
}
154
setmetatable
(
result
,
getmetatable
(
handlers
[
data
]
)
or
functions
)
155
handlers
[
name
]
=
result
156
return
result
157
elseif
tdata
=
=
"
table
"
then
-- ("name",data)
158
setmetatable
(
data
,
getmetatable
(
data
)
or
functions
)
159
handlers
[
name
]
=
data
160
return
data
161
else
-- ("name")
162
local
result
=
{
}
163
setmetatable
(
result
,
functions
)
164
handlers
[
name
]
=
result
165
return
result
166
end
167
else
-- ()
168
local
result
=
{
}
169
setmetatable
(
result
,
functions
)
170
return
result
171
end
172
end
173 174
function
visualizers
.
newgrammar
(
name
,
t
)
175
name
=
lower
(
name
)
176
t
=
t
or
{
}
177
local
g
=
visualizers
.
specifications
[
name
]
178
g
=
g
and
g
.
grammar
179
if
g
then
180
if
trace_visualize
then
181
report_visualizers
(
"
cloning grammar %a
"
,
name
)
182
end
183
for
k
,
v
in
next
,
g
do
184
if
not
t
[
k
]
then
185
t
[
k
]
=
v
186
end
187
if
is_lpeg
(
v
)
then
188
t
[
name
.
.
"
:
"
.
.
k
]
=
v
189
end
190
end
191
end
192
return
t
193
end
194 195
local
function
getvisualizer
(
method
,
nature
)
196
method
=
lower
(
method
)
197
local
m
=
specifications
[
method
]
or
specifications
.
default
198
if
nature
then
199
if
trace_visualize
then
200
report_visualizers
(
"
getting visualizer %a with nature %a
"
,
method
,
nature
)
201
end
202
return
m
and
(
m
[
nature
]
or
m
.
parser
)
or
nil
203
else
204
if
trace_visualize
then
205
report_visualizers
(
"
getting visualizer %a
"
,
method
)
206
end
207
return
m
and
m
.
parser
or
nil
208
end
209
end
210 211
local
ctx_fallback
=
ctx_verbatim
212 213
local
function
makepattern
(
visualizer
,
replacement
,
pattern
)
214
if
not
pattern
then
215
report_visualizers
(
"
error in visualizer %a
"
,
replacement
)
216
return
patterns
.
alwaystrue
217
else
218
if
type
(
visualizer
)
=
=
"
table
"
and
type
(
replacement
)
=
=
"
string
"
then
219
replacement
=
visualizer
[
replacement
]
or
ctx_fallback
220
else
221
replacement
=
ctx_fallback
222
end
223
return
(
C
(
pattern
)
*
CargOne
)
/
replacement
224
end
225
end
226 227
local
function
makenested
(
handler
,
how
,
start
,
stop
)
228
local
b
,
e
,
f
=
P
(
start
)
,
P
(
stop
)
,
how
229
if
type
(
how
)
=
=
"
string
"
then
230
f
=
function
(
s
)
getvisualizer
(
how
,
"
direct
"
)
(
s
)
end
231
end
232
return
makepattern
(
handler
,
"
name
"
,
b
)
233
*
(
(
1
-
e
)
^
1
/
f
)
234
*
makepattern
(
handler
,
"
name
"
,
e
)
235
end
236 237
visualizers
.
pattern
=
makepattern
238
visualizers
.
makepattern
=
makepattern
239
visualizers
.
makenested
=
makenested
240 241
function
visualizers
.
load
(
name
)
242
name
=
lower
(
name
)
243
if
rawget
(
specifications
,
name
)
=
=
nil
then
244
name
=
lower
(
name
)
245
local
impname
=
"
buff-imp-
"
.
.
name
246
local
texname
=
findfile
(
addsuffix
(
impname
,
"
mkiv
"
)
)
247
local
luaname
=
findfile
(
addsuffix
(
impname
,
"
lua
"
)
)
248
if
texname
=
=
"
"
or
luaname
=
=
"
"
then
249
-- assume a user specific file
250
luaname
=
findfile
(
addsuffix
(
name
,
"
mkiv
"
)
)
251
texname
=
findfile
(
addsuffix
(
name
,
"
lua
"
)
)
252
end
253
if
texname
=
=
"
"
or
luaname
=
=
"
"
then
254
if
trace_visualize
then
255
report_visualizers
(
"
unknown visualizer %a
"
,
name
)
256
end
257
else
258
if
trace_visualize
then
259
report_visualizers
(
"
loading visualizer %a
"
,
name
)
260
end
261
lua
.
registercode
(
luaname
)
-- only used here, end up in format
262
context
.
input
(
texname
)
263
end
264
if
rawget
(
specifications
,
name
)
=
=
nil
then
265
rawset
(
specifications
,
name
,
false
)
266
end
267
end
268
end
269 270
function
visualizers
.
register
(
name
,
specification
)
271
name
=
lower
(
name
)
272
if
trace_visualize
then
273
report_visualizers
(
"
registering visualizer %a
"
,
name
)
274
end
275
specifications
[
name
]
=
specification
276
local
parser
=
specification
.
parser
277
local
handler
=
specification
.
handler
278
local
displayparser
=
specification
.
display
or
parser
279
local
inlineparser
=
specification
.
inline
or
parser
280
local
isparser
=
is_lpeg
(
parser
)
281
local
start
,
stop
282
if
isparser
then
283
start
=
makepattern
(
handler
,
"
start
"
,
patterns
.
alwaysmatched
)
284
stop
=
makepattern
(
handler
,
"
stop
"
,
patterns
.
alwaysmatched
)
285
end
286
if
handler
then
287
if
isparser
then
288
specification
.
display
=
function
(
content
,
settings
)
289
if
handler
.
startdisplay
then
handler
.
startdisplay
(
settings
)
end
290
lpegmatch
(
start
*
displayparser
*
stop
,
content
,
1
,
settings
)
291
if
handler
.
stopdisplay
then
handler
.
stopdisplay
(
settings
)
end
292
end
293
specification
.
inline
=
function
(
content
,
settings
)
294
if
handler
.
startinline
then
handler
.
startinline
(
settings
)
end
295
lpegmatch
(
start
*
inlineparser
*
stop
,
content
,
1
,
settings
)
296
if
handler
.
stopinline
then
handler
.
stopinline
(
settings
)
end
297
end
298
specification
.
direct
=
function
(
content
,
settings
)
299
lpegmatch
(
parser
,
content
,
1
,
settings
)
300
end
301
elseif
parser
then
302
specification
.
display
=
function
(
content
,
settings
)
303
if
handler
.
startdisplay
then
handler
.
startdisplay
(
settings
)
end
304
parser
(
content
,
settings
)
305
if
handler
.
stopdisplay
then
handler
.
stopdisplay
(
settings
)
end
306
end
307
specification
.
inline
=
function
(
content
,
settings
)
308
if
handler
.
startinline
then
handler
.
startinline
(
settings
)
end
309
parser
(
content
,
settings
)
310
if
handler
.
stopinline
then
handler
.
stopinline
(
settings
)
end
311
end
312
specification
.
direct
=
parser
313
end
314
elseif
isparser
then
315
specification
.
display
=
function
(
content
,
settings
)
316
lpegmatch
(
start
*
displayparser
*
stop
,
content
,
1
,
settings
)
317
end
318
specification
.
inline
=
function
(
content
,
settings
)
319
lpegmatch
(
start
*
inlineparser
*
stop
,
content
,
1
,
settings
)
320
end
321
specification
.
direct
=
function
(
content
,
settings
)
322
lpegmatch
(
parser
,
content
,
1
,
settings
)
323
end
324
elseif
parser
then
325
specification
.
display
=
parser
326
specification
.
inline
=
parser
327
specification
.
direct
=
parser
328
end
329
return
specification
330
end
331 332
function
visualizers
.
getspecification
(
name
)
333
return
specifications
[
lower
(
name
)
]
334
end
335 336
local
escapepatterns
=
allocate
(
)
337
visualizers
.
escapepatterns
=
escapepatterns
338 339
local
function
texmethod
(
s
)
340
context
.
bgroup
(
)
341
context
(
s
)
342
context
.
egroup
(
)
343
end
344 345
local
function
texcommand
(
s
)
346
context
[
s
]
(
)
347
end
348 349
local
function
defaultmethod
(
s
,
settings
)
350
lpegmatch
(
getvisualizer
(
"
default
"
)
,
lower
(
s
)
,
1
,
settings
)
351
end
352 353
-- we can consider using a nested instead
354 355
local
space_pattern
=
patterns
.
space
^
0
356
local
name_pattern
=
R
(
"
az
"
,
"
AZ
"
)
^
1
357 358
-- the hack is needed in order to retain newlines when an escape happens at the
359
-- at the begin of a line; it also ensures proper line numbering; a bit messy
360 361
local
function
hack
(
pattern
)
362
return
Cs
(
pattern
*
Cc
(
signal
)
)
363
end
364 365
local
split_processor
=
typesetters
.
processors
.
split
366
local
apply_processor
=
typesetters
.
processors
.
apply
367 368
-- todo: { before = b, after = a, processor = p }, ...
369 370
function
visualizers
.
registerescapepattern
(
name
,
befores
,
afters
,
normalmethod
,
escapemethod
,
processors
)
371
local
escapepattern
=
escapepatterns
[
name
]
372
if
not
escapepattern
then
373
if
type
(
befores
)
~
=
"
table
"
then
befores
=
{
befores
}
end
374
if
type
(
afters
)
~
=
"
table
"
then
afters
=
{
afters
}
end
375
if
type
(
processors
)
~
=
"
table
"
then
processors
=
{
processors
}
end
376
for
i
=
1
,
#
befores
do
377
local
before
=
befores
[
i
]
378
local
after
=
afters
[
i
]
379
local
processor
=
processors
[
i
]
380
if
trace_visualize
then
381
report_visualizers
(
"
registering escape pattern, name %a, index %a, before %a, after %a, processor %a
"
,
382
name
,
i
,
before
,
after
,
processor
or
"
default
"
)
383
end
384
before
=
P
(
before
)
*
space_pattern
385
after
=
space_pattern
*
P
(
after
)
386
local
action
387
if
processor
then
388
action
=
function
(
s
)
apply_processor
(
processor
,
s
)
end
389
else
390
action
=
escapemethod
or
texmethod
391
end
392
local
ep
=
(
before
/
"
"
)
*
(
(
1
-
after
)
^
0
/
action
)
*
(
after
/
"
"
)
393
if
escapepattern
then
394
escapepattern
=
escapepattern
+
ep
395
else
396
escapepattern
=
ep
397
end
398
end
399
escapepattern
=
(
400
escapepattern
401
+
hack
(
(
1
-
escapepattern
)
^
1
)
/
(
normalmethod
or
defaultmethod
)
402
)
^
0
403
escapepatterns
[
name
]
=
escapepattern
404
end
405
return
escapepattern
406
end
407 408
function
visualizers
.
registerescapeline
(
name
,
befores
,
normalmethod
,
escapemethod
,
processors
)
409
local
escapepattern
=
escapepatterns
[
name
]
410
if
not
escapepattern
then
411
if
type
(
befores
)
~
=
"
table
"
then
befores
=
{
befores
}
end
412
if
type
(
processors
)
~
=
"
table
"
then
processors
=
{
processors
}
end
413
for
i
=
1
,
#
befores
do
414
local
before
=
befores
[
i
]
415
local
processor
=
processors
[
i
]
416
if
trace_visualize
then
417
report_visualizers
(
"
registering escape line pattern, name %a, before %a, after <<newline>>
"
,
name
,
before
)
418
end
419
before
=
P
(
before
)
*
space_pattern
420
after
=
space_pattern
*
P
(
"
\n
"
)
421
local
action
422
if
processor
then
423
action
=
function
(
s
)
apply_processor
(
processor
,
s
)
end
424
else
425
action
=
escapemethod
or
texmethod
426
end
427
local
ep
=
(
before
/
"
"
)
*
(
(
1
-
after
)
^
0
/
action
)
*
(
space_pattern
/
"
"
)
428
if
escapepattern
then
429
escapepattern
=
escapepattern
+
ep
430
else
431
escapepattern
=
ep
432
end
433
end
434
escapepattern
=
(
435
escapepattern
436
+
hack
(
(
1
-
escapepattern
)
^
1
)
/
(
normalmethod
or
defaultmethod
)
437
)
^
0
438
escapepatterns
[
name
]
=
escapepattern
439
end
440
return
escapepattern
441
end
442 443
function
visualizers
.
registerescapecommand
(
name
,
token
,
normalmethod
,
escapecommand
,
processor
)
444
local
escapepattern
=
escapepatterns
[
name
]
445
if
not
escapepattern
then
446
if
trace_visualize
then
447
report_visualizers
(
"
registering escape token, name %a, token %a
"
,
name
,
token
)
448
end
449
token
=
P
(
token
)
450
local
notoken
=
hack
(
(
1
-
token
)
^
1
)
451
local
cstoken
=
Cs
(
name_pattern
*
(
space_pattern
/
"
"
)
)
452
escapepattern
=
(
453
(
token
/
"
"
)
454
*
(
cstoken
/
(
escapecommand
or
texcommand
)
)
455
+
(
notoken
/
(
normalmethod
or
defaultmethod
)
)
456
)
^
0
457
escapepatterns
[
name
]
=
escapepattern
458
end
459
return
escapepattern
460
end
461 462
local
escapedvisualizers
=
{
}
463
local
f_escapedvisualizer
=
formatters
[
"
%s : %s
"
]
464 465
local
function
visualize
(
content
,
settings
)
-- maybe also method in settings
466
if
content
and
content
~
=
"
"
then
467
local
method
=
lower
(
settings
.
method
or
"
default
"
)
468
local
m
=
specifications
[
method
]
or
specifications
.
default
469
local
e
=
settings
.
escape
470
if
e
and
e
~
=
"
"
and
not
m
.
handler
.
noescape
then
471
local
newname
=
f_escapedvisualizer
(
method
,
e
)
472
local
newspec
=
specifications
[
newname
]
473
if
newspec
then
474
m
=
newspec
475
else
476
local
starts
,
stops
,
processors
=
{
}
,
{
}
,
{
}
477
if
e
=
=
v_yes
then
478
starts
[
1
]
=
"
/BTEX
"
479
stops
[
1
]
=
"
/ETEX
"
480
else
481
local
s
=
settings_to_array
(
e
,
true
)
482
for
i
=
1
,
#
s
do
483
local
si
=
s
[
i
]
484
local
processor
,
pattern
=
split_processor
(
si
)
485
si
=
processor
and
pattern
or
si
486
local
start
,
stop
=
match
(
si
,
"
^(.-),(.-)$
"
)
487
if
start
then
488
local
n
=
#
starts
+
1
489
starts
[
n
]
=
start
490
stops
[
n
]
=
stop
or
"
"
491
processors
[
n
]
=
processor
492
end
493
end
494
end
495
local
oldm
=
m
496
local
oldparser
=
oldm
.
direct
497
local
newhandler
=
oldm
.
handler
498
local
newparser
=
oldm
.
parser
-- nil
499
if
starts
[
1
]
and
stops
[
1
]
~
=
"
"
then
500
newparser
=
visualizers
.
registerescapepattern
(
newname
,
starts
,
stops
,
oldparser
,
nil
,
processors
)
501
elseif
starts
[
1
]
then
502
newparser
=
visualizers
.
registerescapeline
(
newname
,
starts
,
oldparser
,
nil
,
processors
)
503
else
-- for old times sake: /em
504
newparser
=
visualizers
.
registerescapecommand
(
newname
,
e
,
oldparser
,
nil
,
processors
)
505
end
506
m
=
visualizers
.
register
(
newname
,
{
507
parser
=
newparser
,
508
handler
=
newhandler
,
509
}
)
510
end
511
else
512
m
=
specifications
[
method
]
or
specifications
.
default
513
end
514
local
nature
=
settings
.
nature
or
"
display
"
515
local
n
=
m
and
m
[
nature
]
516
if
n
then
517
if
trace_visualize
then
518
report_visualizers
(
"
visualize using method %a and nature %a
"
,
method
,
nature
)
519
end
520
n
(
content
,
settings
)
521
else
522
if
trace_visualize
then
523
report_visualizers
(
"
visualize using method %a
"
,
method
)
524
end
525
ctx_fallback
(
content
,
1
,
settings
)
526
end
527
end
528
end
529 530
visualizers
.
visualize
=
visualize
531
visualizers
.
getvisualizer
=
getvisualizer
532 533
local
fallbacks
=
{
}
table
.
setmetatableindex
(
fallbacks
,
function
(
t
,
k
)
local
v
=
{
nature
=
k
}
t
[
k
]
=
v
return
v
end
)
534 535
local
function
checkedsettings
(
settings
,
nature
)
536
if
not
settings
then
537
-- let's avoid dummy tables as much as possible
538
return
fallbacks
[
nature
]
539
else
540
if
not
settings
.
nature
then
541
settings
.
nature
=
nature
542
end
543
return
settings
544
end
545
end
546 547
function
visualizers
.
visualizestring
(
content
,
settings
)
548
visualize
(
content
,
checkedsettings
(
settings
,
"
inline
"
)
)
549
end
550 551
function
visualizers
.
visualizefile
(
name
,
settings
)
552
visualize
(
resolvers
.
loadtexfile
(
name
)
,
checkedsettings
(
settings
,
"
display
"
)
)
553
end
554 555
function
visualizers
.
visualizebuffer
(
name
,
settings
)
556
visualize
(
buffers
.
getcontent
(
name
)
,
checkedsettings
(
settings
,
"
display
"
)
)
557
end
558 559
-- --
560 561
local
space
=
C
(
patterns
.
space
)
*
CargOne
/
f_space
562
local
newline
=
C
(
patterns
.
newline
)
*
CargOne
/
f_newline
563
local
emptyline
=
C
(
patterns
.
emptyline
)
*
CargOne
/
f_emptyline
564
local
beginline
=
C
(
patterns
.
beginline
)
*
CargOne
/
f_beginline
565
local
anything
=
C
(
patterns
.
somecontent
)
*
CargOne
/
f_default
566 567
----- verbosed = (space + newline * (emptyline^0) * beginline + anything)^0
568
local
verbosed
=
(
space
+
newline
*
(
emptyline
^
0
)
*
beginline
+
newline
*
emptyline
+
newline
+
anything
)
^
0
569 570
local
function
write
(
s
,
settings
)
-- bad name
571
lpegmatch
(
verbosed
,
s
,
1
,
settings
or
false
)
572
end
573 574
visualizers
.
write
=
write
575
visualizers
.
writenewline
=
f_newline
576
visualizers
.
writeemptyline
=
f_emptyline
577
visualizers
.
writespace
=
f_space
578
visualizers
.
writedefault
=
f_default
579 580
function
visualizers
.
writeargument
(
...
)
581
context
(
"
{
"
)
-- If we didn't have tracing then we could
582
write
(
...
)
-- use a faster print to tex variant for the
583
context
(
"
}
"
)
-- { } tokens as they always have ctxcatcodes.
584
end
585 586
-- helpers
587 588
local
function
realign
(
lines
,
strip
)
-- "yes", <number>
589
local
n
590
if
strip
=
=
v_yes
then
591
n
=
0xFFFF
592
for
i
=
1
,
#
lines
do
593
local
spaces
=
find
(
lines
[
i
]
,
"
%S
"
)
-- can be lpeg
594
if
not
spaces
then
595
-- empty line
596
elseif
spaces
=
=
0
then
597
n
=
0
598
break
599
elseif
spaces
<
n
then
600
n
=
spaces
601
end
602
end
603
n
=
n
-
1
604
else
605
n
=
tonumber
(
strip
)
606
end
607
if
n
and
n
>
0
then
608
local
copy
=
{
}
609
for
i
=
1
,
#
lines
do
610
copy
[
i
]
=
sub
(
lines
[
i
]
,
n
+
1
)
611
end
612
return
copy
613
end
614
return
lines
615
end
616 617
local
onlyspaces
=
S
(
"
\t\f\n\r
"
)
^
0
*
P
(
-1
)
618 619
local
function
getstrip
(
lines
,
first
,
last
)
620
if
not
first
then
621
first
=
1
622
end
623
if
not
last
then
624
last
=
#
lines
625
end
626
for
i
=
first
,
last
do
627
local
li
=
lines
[
i
]
628
if
#
li
=
=
0
or
lpegmatch
(
onlyspaces
,
li
)
then
629
first
=
first
+
1
630
else
631
break
632
end
633
end
634
for
i
=
last
,
first
,
-1
do
635
local
li
=
lines
[
i
]
636
if
#
li
=
=
0
or
lpegmatch
(
onlyspaces
,
li
)
then
637
last
=
last
-
1
638
else
639
break
640
end
641
end
642
return
first
,
last
,
last
-
first
+
1
643
end
644 645
-- we look for text (todo):
646
--
647
-- "foo" : start after line with "foo"
648
-- "=" : ignore first blob
649
-- "=foo" : start at "foo"
650
-- "!foo" : maybe a not "foo"
651 652
-- % - # lines start a comment
653 654
local
comment
=
"
^[%%%-#]
"
655 656
local
function
getrange
(
lines
,
first
,
last
,
range
)
-- 1,3 1,+3 fromhere,tothere
657
local
noflines
=
#
lines
658
local
first
=
first
or
1
659
local
last
=
last
or
noflines
660
if
last
<
0
then
661
last
=
noflines
+
last
662
end
663
local
what
=
settings_to_array
(
range
)
-- maybe also n:m
664
local
r_first
=
what
[
1
]
665
local
r_last
=
what
[
2
]
666
local
f
=
tonumber
(
r_first
)
667
local
l
=
tonumber
(
r_last
)
668
if
r_first
then
669
if
f
then
670
if
f
>
first
then
671
first
=
f
672
end
673
elseif
r_first
=
=
"
=
"
then
674
for
i
=
first
,
last
do
675
if
find
(
lines
[
i
]
,
comment
)
then
676
first
=
i
+
1
677
else
678
break
679
end
680
end
681
elseif
r_first
~
=
"
"
then
682
local
exact
,
r_first
=
match
(
r_first
,
"
^([=]?)(.*)
"
)
683
for
i
=
first
,
last
do
684
if
find
(
lines
[
i
]
,
r_first
)
then
685
if
exact
=
=
"
=
"
then
686
first
=
i
687
else
688
first
=
i
+
1
689
end
690
break
691
else
692
first
=
i
693
end
694
end
695
end
696
end
697
if
r_last
then
698
if
l
then
699
if
l
<
0
then
700
l
=
noflines
+
l
701
end
702
if
find
(
r_last
,
"
^[%+]
"
)
then
-- 1,+3
703
l
=
first
+
l
704
end
705
if
l
<
last
then
706
last
=
l
707
end
708
elseif
r_first
=
=
"
=
"
then
709
for
i
=
first
,
last
do
710
if
find
(
lines
[
i
]
,
comment
)
then
711
break
712
else
713
last
=
i
714
end
715
end
716
elseif
r_last
~
=
"
"
then
717
local
exact
,
r_last
=
match
(
r_last
,
"
^([=]?)(.*)
"
)
718
for
i
=
first
,
last
do
719
if
find
(
lines
[
i
]
,
r_last
)
then
720
if
exact
=
=
"
=
"
then
721
last
=
i
722
end
723
break
724
else
725
last
=
i
726
end
727
end
728
end
729
end
730
return
first
,
last
731
end
732 733
local
tablength
=
7
734 735
local
function
dotabs
(
content
,
settings
)
736
local
tab
=
settings
.
tab
737
tab
=
tab
and
(
tab
=
=
v_yes
and
tablength
or
tonumber
(
tab
)
)
738
if
tab
then
739
return
tabtospace
(
content
,
tab
)
740
else
741
return
content
742
end
743
end
744 745
local
function
filter
(
lines
,
settings
)
-- todo: inline or display in settings
746
local
strip
=
settings
.
strip
747
-- if strip and strip == "" then
748
if
strip
~
=
v_no
and
strip
~
=
false
then
749
lines
=
realign
(
lines
,
strip
)
750
end
751
local
line
=
0
752
local
n
=
0
753
local
range
=
settings
.
range
754
local
first
,
last
,
m
=
getstrip
(
lines
)
755
if
range
then
756
first
,
last
=
getrange
(
lines
,
first
,
last
,
range
)
757
first
,
last
=
getstrip
(
lines
,
first
,
last
)
758
end
759
-- \r is \endlinechar but \n would is more generic so this choice is debatable
760
local
content
=
concat
(
lines
,
(
settings
.
nature
=
=
"
inline
"
and
"
"
)
or
"
\n
"
,
first
,
last
)
761
return
content
,
m
762
end
763 764
local
getlines
=
buffers
.
getlines
765 766
-- local decodecomment = resolvers.macros.decodecomment -- experiment
767 768
local
function
typebuffer
(
settings
)
769
local
lines
=
getlines
(
settings
.
name
)
770
if
lines
then
771
ctx_displayverbatiminitialize
(
#
lines
)
772
local
content
,
m
=
filter
(
lines
,
settings
)
773
if
content
and
content
~
=
"
"
then
774
-- content = decodecomment(content)
775
content
=
dotabs
(
content
,
settings
)
776
visualize
(
content
,
checkedsettings
(
settings
,
"
display
"
)
)
777
end
778
end
779
end
780 781
local
function
processbuffer
(
settings
)
782
local
lines
=
getlines
(
settings
.
name
)
783
if
lines
then
784
local
content
,
m
=
filter
(
lines
,
settings
)
785
if
content
and
content
~
=
"
"
then
786
content
=
dotabs
(
content
,
settings
)
787
visualize
(
content
,
checkedsettings
(
settings
,
"
direct
"
)
)
788
end
789
end
790
end
791 792
-- not really buffers but it's closely related
793 794
-- A string.gsub(str,"(\\.-) +$","%1") is faster than an lpeg when there is a
795
-- match but slower when there is no match. But anyway, we need a more clever
796
-- parser so we use lpeg.
797
--
798
-- [[\text ]] [[\text{}]] [[\foo\bar .tex]] [[\text \text ]] [[\text \\ \text ]]
799
--
800
-- needed in e.g. tabulate (manuals)
801 802
local
fences
=
S
(
[[
[{
]]
)
803
local
symbols
=
S
(
[[
!#"$%&'*()+,-./:;<=>?@[]^_`{|}~0123456789
]]
)
-- digits added but maybe split it
804
local
space
=
S
(
[[
]]
)
805
local
backslash
=
S
(
[[
\
]]
)
806
local
nospace
=
space
^
1
/
"
"
807
local
endstring
=
P
(
-1
)
808 809
local
compactors
=
{
810
[
v_all
]
=
Cs
(
(
backslash
*
(
1
-
backslash
-
space
)
^
1
*
nospace
*
(
endstring
+
fences
)
+
1
)
^
0
)
,
811
[
v_absolute
]
=
Cs
(
(
backslash
*
(
1
-
symbols
-
space
)
^
1
*
nospace
*
(
symbols
+
backslash
)
+
1
)
^
0
)
,
812
[
v_last
]
=
Cs
(
(
space
^
1
*
endstring
/
"
"
+
1
)
^
0
)
,
813
}
814 815
local
function
typestring
(
settings
)
816
local
content
=
settings
.
data
817
if
content
and
content
~
=
"
"
then
818
local
compact
=
settings
.
compact
819
local
compactor
=
compact
and
compactors
[
compact
]
820
if
compactor
then
821
content
=
lpegmatch
(
compactor
,
content
)
or
content
822
end
823
-- content = decodecomment(content)
824
-- content = dotabs(content,settings)
825
visualize
(
content
,
checkedsettings
(
settings
,
"
inline
"
)
)
826
end
827
end
828 829
local
function
typefile
(
settings
)
830
local
filename
=
settings
.
name
831
local
foundname
=
resolvers
.
findtexfile
(
filename
)
832
if
foundname
and
foundname
~
=
"
"
then
833
local
str
=
resolvers
.
loadtexfile
(
foundname
)
834
if
str
and
str
~
=
"
"
then
835
local
regime
=
settings
.
regime
836
if
regime
and
regime
~
=
"
"
then
837
str
=
regimes
.
translate
(
str
,
regime
)
838
end
839
if
str
and
str
~
=
"
"
then
840
-- content = decodecomment(content)
841
local
lines
=
splitlines
(
str
)
842
local
content
,
m
=
filter
(
lines
,
settings
)
843
if
content
and
content
~
=
"
"
then
844
content
=
dotabs
(
content
,
settings
)
845
visualize
(
content
,
checkedsettings
(
settings
,
"
display
"
)
)
846
end
847
end
848
end
849
end
850
end
851 852
implement
{
853
name
=
"
type
"
,
854
actions
=
typestring
,
855
arguments
=
{
856
{
857
{
"
data
"
}
,
858
{
"
tab
"
}
,
859
{
"
method
"
}
,
860
{
"
compact
"
}
,
861
{
"
nature
"
}
,
862
{
"
escape
"
}
,
863
}
864
}
865
}
866 867
-- implement {
868
-- name = "type_x",
869
-- actions = typestring,
870
-- arguments = {
871
-- {
872
-- { "data", "verbatim" },
873
-- { "tab" },
874
-- { "method" },
875
-- { "compact" },
876
-- { "nature" },
877
-- { "escape" },
878
-- }
879
-- }
880
-- }
881 882
-- local function typestring_y(settings)
883
-- local content = tex.toks[settings.n]
884
-- if content and content ~= "" then
885
-- local compact = settings.compact
886
-- local compactor = compact and compactors[compact]
887
-- if compactor then
888
-- content = lpegmatch(compactor,content)
889
-- end
890
-- -- content = decodecomment(content)
891
-- -- content = dotabs(content,settings)
892
-- visualize(content,checkedsettings(settings,"inline"))
893
-- end
894
-- end
895 896
-- implement {
897
-- name = "type_y",
898
-- actions = typestring_y,
899
-- arguments = {
900
-- {
901
-- { "n", "integer" },
902
-- { "tab" },
903
-- { "method" },
904
-- { "compact" },
905
-- { "nature" },
906
-- { "escape" },
907
-- }
908
-- }
909
-- }
910 911
implement
{
912
name
=
"
processbuffer
"
,
913
actions
=
processbuffer
,
914
arguments
=
{
915
{
916
{
"
name
"
}
,
917
{
"
strip
"
}
,
918
{
"
tab
"
}
,
919
{
"
method
"
}
,
920
{
"
nature
"
}
,
921
}
922
}
923
}
924 925
implement
{
926
name
=
"
typebuffer
"
,
927
actions
=
typebuffer
,
928
arguments
=
{
929
{
930
{
"
name
"
}
,
931
{
"
strip
"
}
,
932
{
"
range
"
}
,
933
{
"
regime
"
}
,
934
{
"
tab
"
}
,
935
{
"
method
"
}
,
936
{
"
escape
"
}
,
937
{
"
nature
"
}
,
938
}
939
}
940
}
941 942
implement
{
943
name
=
"
typefile
"
,
944
actions
=
typefile
,
945
arguments
=
{
946
{
947
{
"
name
"
}
,
948
{
"
strip
"
}
,
949
{
"
range
"
}
,
950
{
"
regime
"
}
,
951
{
"
tab
"
}
,
952
{
"
method
"
}
,
953
{
"
escape
"
}
,
954
{
"
nature
"
}
,
955
}
956
}
957
}
958 959
implement
{
960
name
=
"
doifelsevisualizer
"
,
961
actions
=
{
visualizers
.
getspecification
,
commands
.
doifelse
}
,
962
arguments
=
"
string
"
963
}
964 965
implement
{
966
name
=
"
loadvisualizer
"
,
967
actions
=
visualizers
.
load
,
968
arguments
=
"
string
"
969
}
970