1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
return function(cmd)
-- as mentioned in the .sty file this allows explicit flush after each write
-- it's not easy to eliminate having to spawn 2 Python processes even with Lua https://stackoverflow.com/questions/8716527/interactive-popen-lua-call
-- if this is a child process, should write to stderr, in which case cmd will be nil
local send_content
if cmd==nil then
send_content=function(str)
io.stderr:write(str.."\n")
io.stderr:flush()
end
else
process = io.popen(cmd, "w")
send_content=function(str)
process:write(str.."\n")
process:flush()
end
end
local function_table=lua.get_functions_table()
-- https://tex.stackexchange.com/questions/632408/how-can-i-exclude-tex-macros-when-counting-a-strings-characters-in-lua/632464?noredirect=1#comment1623008_632464 this only work in Lua 5.3 or assume it's allocated sequentially
local send_content_index=#function_table+1
function_table[send_content_index]=function()
send_content(token.scan_string())
end
local close_index=#function_table+1
function_table[close_index]=function()
process:close()
end
local bgroup=token.create(0x7b, 1)
local egroup=token.create(0x7d, 2)
token.put_next(
bgroup,
token.create("ifodd"),
token.create(0x31, 12),
token.create("fi"),
egroup
)
local frozen_relax_tok=token.scan_toks(false, true)[1].tok
local null_cs_tok=0x20000000 -- \csname\endcsname
local cmdname_to_type={
left_brace="1",
right_brace="2",
math_shift="3",
tab_mark ="4",
mac_param ="6",
sup_mark ="7",
sub_mark ="8",
spacer ="A",
letter ="B",
other_char="C",
}
local function serialize(tl)
local result={}
for _, v in ipairs(tl) do
local s -- serialized result of v
local function handle_character(cat, index, char)
if index<32 then
s="^"..cat..utf8.char(index+64)
else
s=cat..char
end
end
if v.csname~=nil then
if v.active then
handle_character("D", utf8.codepoint(v.csname), v.csname)
elseif v.tok==frozen_relax_tok then
s="R"
elseif v.tok==null_cs_tok then
s="\\ "
else
local c=v.csname
s=""
for i=1, #c do
if c:byte(i)<33 then s=s.."*" end
end
s="\\"
for i=1, #c do
if c:byte(i)<33 then
s=s.." "..string.char(c:byte(i)+64)
else
s=s..c:sub(i,i)
end
end
s=s.." "
end
else
assert(cmdname_to_type[v.cmdname]~=nil)
handle_character(cmdname_to_type[v.cmdname], v.mode, utf8.char(v.mode))
end
result[#result+1]=s
end
return table.concat(result)
end
local serialize_index=#function_table+1
function_table[serialize_index]=function()
local result_token=token.get_next()
assert(result_token.csname~=nil and not result_token.active)
local tl=token.scan_toks()
--token.set_macro(-2, result_token.csname, table.concat(result))
tex.sprint{token.create "def", result_token, bgroup}
tex.sprint(-2, serialize(tl))
tex.sprint(egroup)
end
local send_balanced_index=#function_table+1
function_table[send_balanced_index]=function()
local tl=token.scan_toks()
send_content(serialize(tl))
end
tex.print(
[[\protected \luadef \_pythonimmediate_send_content:e ]] .. send_content_index ..
[[\protected \luadef \_pythonimmediate_close_write: ]] .. close_index ..
[[\protected \luadef \_pythonimmediate_tlserialize_nodot_unchecked:Nn ]] .. serialize_index ..
[[\protected \luadef \_pythonimmediate_send_balanced_tl:n ]] .. send_balanced_index ..
[[\relax]])
end
|