Support annotations while parsing pdfTeX log

This commit is contained in:
Marcel Fabian Krüger 2021-06-01 22:29:48 +02:00
parent a782003db4
commit d6b2747171
5 changed files with 144 additions and 16 deletions

View File

@ -505,7 +505,6 @@ function nodes_to_table(head, cur_style)
local props = properties[n]
local mathml_core = props and props.mathml_core
local mathml_table = props and (props.mathml_table or mathml_core)
print(mathml_table)
if mathml_table ~= nil then
new_node, new_core = mathml_table, mathml_core
elseif id == noad_t then

94
luamml-pdf.sty Normal file
View File

@ -0,0 +1,94 @@
\ProvidesExplPackage {luamml-pdf} {2021-05-31} {0.0.1-alpha}
{MathML generation for L̶u̶a̶pdfLaTeX}
\cs_new:Npn \__luamml_pdf_showlists: {
\group_begin:
\int_set:Nn \l_tmpa_int { \tex_interactionmode:D }
\int_set:Nn \tex_interactionmode:D { 0 }
\int_set:Nn \tex_showboxdepth:D { \c_max_int }
\int_set:Nn \tex_showboxbreadth:D { \c_max_int }
\tex_showlists:D
\int_set:Nn \tex_interactionmode:D { \l_tmpa_int }
\group_end:
}
\int_new:N \g__luamml_formula_id_int
\cs_new_protected:Npn \luamml_pdf_write: {
\int_gincr:N \g__luamml_formula_id_int
\iow_log:x {
LUAMML_FORMULA_BEGIN:
\int_use:N \g__luamml_formula_id_int
}
\__luamml_pdf_showlists:
\iow_log:x {
LUAMML_FORMULA_END
}
}
\cs_new:Npn \luamml_pdf_last_formula: {
\int_use:N \g__luamml_formula_id_int
}
\cs_generate_variant:Nn \tl_to_str:n { e }
% annotate parameters
% #1 number of top level nodes to be annotated
% #2 annotation
% #3 nodes to be annotated
\int_new:N \g__luamml_annotation_id_int
\cs_new_protected:Npn \luamml_pdf_annotate:nnn #1#2#3 {
\int_gincr:N \g__luamml_annotation_id_int
\iow_shipout_x:Nx \c_log_iow {
\tl_to_str:e {
LUAMML_MARK:
\int_use:N \g__luamml_annotation_id_int
:
count = \int_eval:n {#1},
#2
}
\exp_not:N \iow_newline:
LUAMML_MARK_END
}
#3
}
% annotate parameters
% #1 annotation
% #2 nodes to be annotated
% THIS VERSION IS SIGNIFICANTLY SLOWER
\cs_new_protected:Npn \luamml_pdf_annotate:nn #1#2 {
\int_gincr:N \g__luamml_annotation_id_int
\iow_write:Nx \c_log_iow {
LUAMML_COUNT_BEGIN:
\int_use:N \g__luamml_annotation_id_int
}
\__luamml_pdf_showlists:
\iow_shipout:Nx \c_log_iow {
LUAMML_MARK:
\int_use:N \g__luamml_annotation_id_int
:
#1
}
#2
\iow_write:Nx \c_log_iow {
LUAMML_COUNT_END:
\int_use:N \g__luamml_annotation_id_int
}
\__luamml_pdf_showlists:
}
\endinput
\cs_new:Npn \__luamml_patch_package:nn #1 #2 {
\@ifpackageloaded {#1} {#2} {
\hook_gput_code:nnn {package/after/#1} {luamml} {#2}
}
}
\cs_new:Npn \__luamml_patch_package:n #1 {
\__luamml_patch_package:nn {#1} {
\RequirePackage { luamml-patches-#1 }
}
}
\RequirePackage { luamml-patches-kernel }
\__luamml_patch_package:n {amsmath}
\__luamml_patch_package:n {array}

View File

@ -2,15 +2,23 @@ local l = lpeg or require'lpeg'
local line = (1-l.P'\n')^0 * '\n'
local list_block = (l.C(l.S'\\._^/ps' * (1-l.P'\n')^0)^-1 * '\n')^0
local id = l.R'09'/tonumber
local non_final_list_block = (l.C((1-l.P'\n')^0) * '\n' - '### ')^0
local math_lists_block = l.Ct('### ' * l.Cg(l.C'display' * ' ', 'display')^-1 * 'math mode entered at line ' * l.Cg(l.R'09'^1 / tonumber, 'line') * '\n'
* list_block)^1
local generic_list_block = '### ' * line * list_block
local luamml_block = l.Ct('LUAMML_META_BEGIN\n\n'
* (math_lists_block + generic_list_block/0)^0
* (line - 'LUAMML_META_END\n')^0
* 'LUAMML_META_END\n')
local log_file = l.Ct((luamml_block + line)^0)
* non_final_list_block)^1
local generic_list_block = '### ' * (line - 'current page:') * non_final_list_block
local luamml_block = l.Cg('LUAMML_FORMULA_BEGIN:' * id * l.P'\n'^1 * l.Ct(
(math_lists_block + generic_list_block/0)^0
* (line - 'LUAMML_FORMULA_END\n')^0
* 'LUAMML_FORMULA_END\n') * l.Cc'groups')
local luamml_mark = l.Cg('LUAMML_MARK:' * id * ':' * l.Cs((1 - l.P'\n' + l.Cg('\n' * l.Cc'' - '\nLUAMML_MARK_END\n'))^0) * '\nLUAMML_MARK_END\n' * l.Cc'marks')
local function multi_table_set(t, key, value, table)
assert(t[table])[key] = value
return t
end
local log_file = l.Cf(l.Ct(l.Cg(l.Ct'', 'groups') * l.Cg(l.Ct'', 'marks')) * (luamml_block + luamml_mark + line)^0, multi_table_set)
return function(filename)
local f

View File

@ -1,3 +1,7 @@
require'pdfmml-emulate-node'
local properties = node.get_properties_table()
local l = lpeg or require'lpeg'
local hex_digit = l.R('09', 'af')
local function hex_to_int(s) return tonumber(s, 16) end
@ -22,12 +26,12 @@ local math_char = l.Ct('\\fam' * l.Cg(l.R'09'^1 / tonumber, 'fam') * ' ' * l.Cg(
local simple_noad = l.Ct(
'\\math' * l.Cg(
'ord' * l.Cc(0)
+ 'open' * l.Cc(6)
+ 'op\\limits' * l.Cc(2)
+ 'op\\nolimits' * l.Cc(3)
+ 'op' * l.Cc(1)
+ 'bin' * l.Cc(4)
+ 'rel' * l.Cc(5)
+ 'open' * l.Cc(6)
+ 'close' * l.Cc(7)
+ 'punct' * l.Cc(8)
+ 'inner' * l.Cc(9)
@ -60,6 +64,8 @@ local fraction_noad = l.Ct('\\fraction, thickness '
local mathchoice_noad = l.Ct('\\mathchoice' * l.Cg(l.Cc'choice', 'id') * -1)
local mark_whatsit = '\\write-{LUAMML_MARK:' * (l.R'09'/tonumber) * ':'
local parse_list
local function parse_kernel(lines, i, prefix)
local line = lines[i]
@ -69,11 +75,14 @@ local function parse_kernel(lines, i, prefix)
result, i = parse_list(lines, i, prefix)
return {list = result, id = 'sub_mlist'}, i
end
function parse_list(lines, i, prefix)
function parse_list(lines, i, prefix, marks)
i = i or 1
prefix = prefix or ''
local head, last
local mark_environment = {}
local current_mark, current_count, current_offset
while true do
local skip
local line = lines[i]
if not line or line:sub(1, #prefix) ~= prefix then break end
local simple = simple_noad:match(line, #prefix+1)
@ -105,6 +114,13 @@ function parse_list(lines, i, prefix)
mathchoice.prev, last.next = last, mathchoice
end
last = mathchoice
else
skip = true
local mark = mark_whatsit:match(line)
if mark then
local mark_table = assert(load('return {' .. assert(marks[mark], 'Undefined mark encountered') .. '}', nil, 't', mark_environment))()
current_mark, current_count, current_offset = mark_table, mark_table.count or 1, mark_table.offset or 1
i = i + 1
else
print(line, prefix, i)
print('unknown noad ' .. line:sub(#prefix+1))
@ -112,7 +128,18 @@ function parse_list(lines, i, prefix)
end
end
end
end
if not head then head = last end
if not skip and current_mark then
current_count = current_count - 1
current_offset = current_offset - 1
if current_offset == 0 then
properties[current_mark.nucleus and last.nucleus or last] = {mathml_core = current_mark.core}
else
properties[last] = {mathml_core = false}
end
if current_count == 0 then current_mark = nil end
end
end
return head, i
end

View File

@ -17,9 +17,9 @@ end
local math_lists = assert(parse_log(arg[1]))
local out_stream = arg[2] and arg[2] ~= '-' and assert(io.open(arg[2], 'w')) or io.stdout
for i, block in ipairs(math_lists) do
for i, block in ipairs(math_lists.groups) do
block = block[1]
local parsed = parse_showlists(block)
local parsed = parse_showlists(block, nil, nil, math_lists.marks)
local style = block.display and 0 or 2
out_stream:write(
to_xml(convert.make_root(convert.process(parsed, style), style))