Adapt to new LuaMetaTeX versions and allow CB use
This commit is contained in:
parent
7c162a0cf0
commit
3c2fba9a9f
@ -1,6 +1,16 @@
|
|||||||
|
local scan_int = token.scan_integer
|
||||||
|
local scan_token = token.scan_token
|
||||||
|
local scan_keyword = token.scan_keyword
|
||||||
|
local scan_string = token.scan_string
|
||||||
|
local scan_word = token.scan_word
|
||||||
|
local scan_dimen = token.scan_dimen
|
||||||
|
local scan_box = token.scan_box
|
||||||
|
token.scan_list = scan_box -- They are equal if no parameter is present
|
||||||
|
|
||||||
local pdf = pdf
|
local pdf = pdf
|
||||||
local pdfvariable = pdf.variable
|
local pdfvariable = pdf.variable
|
||||||
|
|
||||||
|
local callbacks = require'luametalatex-callbacks'
|
||||||
local writer = require'luametalatex-nodewriter'
|
local writer = require'luametalatex-nodewriter'
|
||||||
local newpdf = require'luametalatex-pdf'
|
local newpdf = require'luametalatex-pdf'
|
||||||
local nametree = require'luametalatex-pdf-nametree'
|
local nametree = require'luametalatex-pdf-nametree'
|
||||||
@ -36,7 +46,6 @@ local colorstacks = {{
|
|||||||
default = "0 g 0 G",
|
default = "0 g 0 G",
|
||||||
page_stack = {"0 g 0 G"},
|
page_stack = {"0 g 0 G"},
|
||||||
}}
|
}}
|
||||||
token.scan_list = token.scan_box -- They are equal if no parameter is present
|
|
||||||
local spacer_cmd = token.command_id'spacer'
|
local spacer_cmd = token.command_id'spacer'
|
||||||
local function get_pfile()
|
local function get_pfile()
|
||||||
if not pfile then
|
if not pfile then
|
||||||
@ -71,7 +80,7 @@ token.luacmd("shipout", function()
|
|||||||
local total_voffset, total_hoffset = tex.voffset + pdfvariable.vorigin, tex.hoffset + pdfvariable.horigin
|
local total_voffset, total_hoffset = tex.voffset + pdfvariable.vorigin, tex.hoffset + pdfvariable.horigin
|
||||||
local voff = node.new'kern'
|
local voff = node.new'kern'
|
||||||
voff.kern = total_voffset
|
voff.kern = total_voffset
|
||||||
voff.next = token.scan_list()
|
voff.next = scan_box()
|
||||||
voff.next.shift = total_hoffset
|
voff.next.shift = total_hoffset
|
||||||
local list = node.direct.tonode(node.direct.vpack(node.direct.todirect(voff)))
|
local list = node.direct.tonode(node.direct.vpack(node.direct.todirect(voff)))
|
||||||
local pageheight, pagewidth = tex.pageheight, tex.pagewidth
|
local pageheight, pagewidth = tex.pageheight, tex.pagewidth
|
||||||
@ -87,7 +96,7 @@ token.luacmd("shipout", function()
|
|||||||
pfile:indirect(page, string.format([[<</Type/Page/Parent %i 0 R/Contents %i 0 R/MediaBox[0 %i %i %i]/Resources%s%s%s%s>>]], parent, content, -math.ceil(to_bp(list.depth)), math.ceil(to_bp(list.width)), math.ceil(to_bp(list.height)), resources(pdfvariable.pageresources .. pdf.pageresources), annots, pdfvariable.pageattr, pdf.pageattributes))
|
pfile:indirect(page, string.format([[<</Type/Page/Parent %i 0 R/Contents %i 0 R/MediaBox[0 %i %i %i]/Resources%s%s%s%s>>]], parent, content, -math.ceil(to_bp(list.depth)), math.ceil(to_bp(list.width)), math.ceil(to_bp(list.height)), resources(pdfvariable.pageresources .. pdf.pageresources), annots, pdfvariable.pageattr, pdf.pageattributes))
|
||||||
node.flush_list(list)
|
node.flush_list(list)
|
||||||
token.put_next(reset_deadcycles)
|
token.put_next(reset_deadcycles)
|
||||||
token.scan_token()
|
scan_token()
|
||||||
end, 'force', 'protected')
|
end, 'force', 'protected')
|
||||||
|
|
||||||
local infodir = ""
|
local infodir = ""
|
||||||
@ -153,7 +162,10 @@ local function nodefont_newindex(t, k, v)
|
|||||||
return rawset(t, k, v)
|
return rawset(t, k, v)
|
||||||
end
|
end
|
||||||
|
|
||||||
callback.register("stop_run", function()
|
function callbacks.stop_run()
|
||||||
|
local user_callback = callbacks.stop_run
|
||||||
|
if user_callback then user_callback() end
|
||||||
|
|
||||||
if not pfile then
|
if not pfile then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@ -234,19 +246,21 @@ callback.register("stop_run", function()
|
|||||||
texio.write_nl(" " .. table.concat(nodestat, ', '))
|
texio.write_nl(" " .. table.concat(nodestat, ', '))
|
||||||
texio.write_nl(string.format("Output written on %s (%d pages, %d bytes).", pdfname, pages, size))
|
texio.write_nl(string.format("Output written on %s (%d pages, %d bytes).", pdfname, pages, size))
|
||||||
texio.write_nl(string.format("Transcript written on %s.\n", status.log_name))
|
texio.write_nl(string.format("Transcript written on %s.\n", status.log_name))
|
||||||
end, "Finish PDF file")
|
end
|
||||||
|
callbacks.__freeze('stop_run', true)
|
||||||
|
|
||||||
token.luacmd("pdfvariable", function()
|
token.luacmd("pdfvariable", function()
|
||||||
for _, n in ipairs(pdf.variable_names) do
|
for _, n in ipairs(pdf.variable_names) do
|
||||||
if token.scan_keyword(n) then
|
if scan_keyword(n) then
|
||||||
return token.put_next(token.create('pdfvariable ' .. n))
|
return token.put_next(token.create('pdfvariable ' .. n))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- The following error message gobbles the next word as a side effect.
|
-- The following error message gobbles the next word as a side effect.
|
||||||
-- This is intentional to make error-recovery easier.
|
-- This is intentional to make error-recovery easier.
|
||||||
--[[
|
--[[
|
||||||
error(string.format("Unknown PDF variable %s", token.scan_word()))
|
error(string.format("Unknown PDF variable %s", scan_word()))
|
||||||
]] -- Delay the error to ensure luatex85.sty compatibility
|
]] -- Delay the error to ensure luatex85.sty compatibility
|
||||||
texio.write_nl(string.format("Unknown PDF variable %s", token.scan_word()))
|
texio.write_nl(string.format("Unknown PDF variable %s", scan_word()))
|
||||||
tex.sprint"\\unexpanded{\\undefinedpdfvariable}"
|
tex.sprint"\\unexpanded{\\undefinedpdfvariable}"
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@ -534,7 +548,7 @@ local colorstack_whatsit = declare_whatsit('pdf_colorstack', function(prop, p, n
|
|||||||
pdf.write(colorstack.mode, stack[#stack], x, y, p)
|
pdf.write(colorstack.mode, stack[#stack], x, y, p)
|
||||||
end)
|
end)
|
||||||
local function write_colorstack()
|
local function write_colorstack()
|
||||||
local idx = token.scan_int()
|
local idx = scan_int()
|
||||||
local colorstack = colorstacks[idx + 1]
|
local colorstack = colorstacks[idx + 1]
|
||||||
if not colorstack then
|
if not colorstack then
|
||||||
tex.error('Undefined colorstack', {"The requested colorstack is not initialized. \z
|
tex.error('Undefined colorstack', {"The requested colorstack is not initialized. \z
|
||||||
@ -542,10 +556,10 @@ local function write_colorstack()
|
|||||||
that you specified the wrong index. I will continue with colorstack 0."})
|
that you specified the wrong index. I will continue with colorstack 0."})
|
||||||
colorstack = colorstacks[1]
|
colorstack = colorstacks[1]
|
||||||
end
|
end
|
||||||
local action = token.scan_keyword'pop' and 'pop'
|
local action = scan_keyword'pop' and 'pop'
|
||||||
or token.scan_keyword'set' and 'set'
|
or scan_keyword'set' and 'set'
|
||||||
or token.scan_keyword'current' and 'current'
|
or scan_keyword'current' and 'current'
|
||||||
or token.scan_keyword'push' and 'push'
|
or scan_keyword'push' and 'push'
|
||||||
if not action then
|
if not action then
|
||||||
tex.error('Missing action specifier for colorstack', {
|
tex.error('Missing action specifier for colorstack', {
|
||||||
"I don't know what you want to do with this colorstack. I would have expected pop/set/current or push here. \z
|
"I don't know what you want to do with this colorstack. I would have expected pop/set/current or push here. \z
|
||||||
@ -554,7 +568,7 @@ local function write_colorstack()
|
|||||||
end
|
end
|
||||||
local text
|
local text
|
||||||
if action == "push" or "set" then
|
if action == "push" or "set" then
|
||||||
text = token.scan_string()
|
text = scan_string()
|
||||||
-- text = token.to_string(token.scan_tokenlist()) -- Attention! This should never be executed in an expand-only context
|
-- text = token.to_string(token.scan_tokenlist()) -- Attention! This should never be executed in an expand-only context
|
||||||
end
|
end
|
||||||
local whatsit = node.new(whatsit_id, colorstack_whatsit)
|
local whatsit = node.new(whatsit_id, colorstack_whatsit)
|
||||||
@ -568,97 +582,103 @@ end
|
|||||||
local function scan_action()
|
local function scan_action()
|
||||||
local action_type
|
local action_type
|
||||||
|
|
||||||
if token.scan_keyword'user' then
|
if scan_keyword'user' then
|
||||||
return {action_type = 3, data = token.scan_string()}
|
return {action_type = 3, data = scan_string()}
|
||||||
elseif token.scan_keyword'thread' then
|
elseif scan_keyword'thread' then
|
||||||
error[[FIXME: Unsupported]] -- TODO
|
error[[FIXME: Unsupported]] -- TODO
|
||||||
elseif token.scan_keyword'goto' then
|
elseif scan_keyword'goto' then
|
||||||
action_type = 1
|
action_type = 1
|
||||||
else
|
else
|
||||||
error[[Unsupported action]]
|
error[[Unsupported action]]
|
||||||
end
|
end
|
||||||
local action = {
|
local action = {
|
||||||
action_type = action_type,
|
action_type = action_type,
|
||||||
file = token.scan_keyword'file' and token.scan_string(),
|
file = scan_keyword'file' and scan_string(),
|
||||||
}
|
}
|
||||||
if token.scan_keyword'page' then
|
if scan_keyword'page' then
|
||||||
assert(action_type == 1)
|
assert(action_type == 1)
|
||||||
action_type = 0
|
action_type = 0
|
||||||
local page = token.scan_int()
|
action.action_type = 0
|
||||||
|
local page = scan_int()
|
||||||
if page <= 0 then
|
if page <= 0 then
|
||||||
error[[page must be positive in action specification]]
|
error[[page must be positive in action specification]]
|
||||||
end
|
end
|
||||||
action.page = page
|
action.page = page
|
||||||
action.tokens = token.scan_string()
|
action.tokens = scan_string()
|
||||||
elseif token.scan_keyword'num' then
|
elseif scan_keyword'num' then
|
||||||
if action.file and action_type == 1 then
|
if action.file and action_type == 1 then
|
||||||
error[[num style GoTo actions must be internal]]
|
error[[num style GoTo actions must be internal]]
|
||||||
end
|
end
|
||||||
action.id = token.scan_int()
|
action.id = scan_int()
|
||||||
if action.id <= 0 then
|
if action.id <= 0 then
|
||||||
error[[id must be positive]]
|
error[[id must be positive]]
|
||||||
end
|
end
|
||||||
elseif token.scan_keyword'name' then
|
elseif scan_keyword'name' then
|
||||||
action.id = token.scan_string()
|
action.id = scan_string()
|
||||||
else
|
else
|
||||||
error[[Unsupported id type]]
|
error[[Unsupported id type]]
|
||||||
end
|
end
|
||||||
action.new_window = token.scan_keyword'newwindow' and 1
|
action.new_window = scan_keyword'newwindow' and 1
|
||||||
or token.scan_keyword'nonewwindow' and 2
|
or scan_keyword'nonewwindow' and 2
|
||||||
if action.new_window and not action.file then
|
if action.new_window and not action.file then
|
||||||
error[[newwindow is only supported for external files]]
|
error[[newwindow is only supported for external files]]
|
||||||
end
|
end
|
||||||
return action
|
return action
|
||||||
end
|
end
|
||||||
local function scan_literal_mode()
|
local function scan_literal_mode()
|
||||||
return token.scan_keyword"direct" and "direct"
|
return scan_keyword"direct" and "direct"
|
||||||
or token.scan_keyword"page" and "page"
|
or scan_keyword"page" and "page"
|
||||||
or token.scan_keyword"text" and "text"
|
or scan_keyword"text" and "text"
|
||||||
or token.scan_keyword"direct" and "direct"
|
or scan_keyword"direct" and "direct"
|
||||||
or token.scan_keyword"raw" and "raw"
|
or scan_keyword"raw" and "raw"
|
||||||
or "origin"
|
or "origin"
|
||||||
end
|
end
|
||||||
local function maybe_gobble_cmd(cmd)
|
local function maybe_gobble_cmd(cmd)
|
||||||
local t = token.scan_token()
|
local t = scan_token()
|
||||||
if t.command ~= cmd then
|
if t.command ~= cmd then
|
||||||
token.put_next(t)
|
token.put_next(t)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
token.luacmd("pdffeedback", function()
|
token.luacmd("pdffeedback", function()
|
||||||
if token.scan_keyword"colorstackinit" then
|
if scan_keyword"colorstackinit" then
|
||||||
local page = token.scan_keyword'page'
|
local page = scan_keyword'page'
|
||||||
or (token.scan_keyword'nopage' and false) -- If you want to pass "page" as mode
|
or (scan_keyword'nopage' and false) -- If you want to pass "page" as mode
|
||||||
local mode = scan_literal_mode()
|
local mode = scan_literal_mode()
|
||||||
local default = token.scan_string()
|
local default = scan_string()
|
||||||
tex.sprint(tostring(pdf.newcolorstack(default, mode, page)))
|
tex.sprint(tostring(pdf.newcolorstack(default, mode, page)))
|
||||||
elseif token.scan_keyword"creationdate" then
|
elseif scan_keyword"creationdate" then
|
||||||
tex.sprint(creationdate)
|
tex.sprint(creationdate)
|
||||||
elseif token.scan_keyword"lastannot" then
|
elseif scan_keyword"lastannot" then
|
||||||
tex.sprint(tostring(lastannot))
|
tex.sprint(tostring(lastannot))
|
||||||
elseif token.scan_keyword"lastobj" then
|
elseif scan_keyword"lastobj" then
|
||||||
tex.sprint(tostring(lastobj))
|
tex.sprint(tostring(lastobj))
|
||||||
else
|
else
|
||||||
-- The following error message gobbles the next word as a side effect.
|
-- The following error message gobbles the next word as a side effect.
|
||||||
-- This is intentional to make error-recovery easier.
|
-- This is intentional to make error-recovery easier.
|
||||||
error(string.format("Unknown PDF feedback %s", token.scan_word()))
|
error(string.format("Unknown PDF feedback %s", scan_word()))
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
token.luacmd("pdfextension", function(_, imm)
|
token.luacmd("pdfextension", function(_, immediate)
|
||||||
if token.scan_keyword"colorstack" then
|
if immediate == "value" then return end
|
||||||
|
if immediate and immediate & 0x7 ~= 0 then
|
||||||
|
immediate = immediate & 0x8
|
||||||
|
tex.error("Unexpected prefix", "You used \\pdfextension with a prefix that doesn't belong there. I will ignore it for now.")
|
||||||
|
end
|
||||||
|
if scan_keyword"colorstack" then
|
||||||
write_colorstack()
|
write_colorstack()
|
||||||
elseif token.scan_keyword"literal" then
|
elseif scan_keyword"literal" then
|
||||||
local mode = scan_literal_mode()
|
local mode = scan_literal_mode()
|
||||||
local literal = token.scan_string()
|
local literal = scan_string()
|
||||||
local whatsit = node.new(whatsit_id, literal_whatsit)
|
local whatsit = node.new(whatsit_id, literal_whatsit)
|
||||||
node.setproperty(whatsit, {
|
node.setproperty(whatsit, {
|
||||||
mode = mode,
|
mode = mode,
|
||||||
data = literal,
|
data = literal,
|
||||||
})
|
})
|
||||||
node.write(whatsit)
|
node.write(whatsit)
|
||||||
elseif token.scan_keyword"startlink" then
|
elseif scan_keyword"startlink" then
|
||||||
local pfile = get_pfile()
|
local pfile = get_pfile()
|
||||||
local whatsit = node.new(whatsit_id, start_link_whatsit)
|
local whatsit = node.new(whatsit_id, start_link_whatsit)
|
||||||
local attr = token.scan_keyword'attr' and token.scan_string() or ''
|
local attr = scan_keyword'attr' and scan_string() or ''
|
||||||
local action = scan_action()
|
local action = scan_action()
|
||||||
local objnum = pfile:getobj()
|
local objnum = pfile:getobj()
|
||||||
lastannot = num
|
lastannot = num
|
||||||
@ -668,27 +688,27 @@ token.luacmd("pdfextension", function(_, imm)
|
|||||||
objnum = objnum,
|
objnum = objnum,
|
||||||
})
|
})
|
||||||
node.write(whatsit)
|
node.write(whatsit)
|
||||||
elseif token.scan_keyword"endlink" then
|
elseif scan_keyword"endlink" then
|
||||||
local whatsit = node.new(whatsit_id, end_link_whatsit)
|
local whatsit = node.new(whatsit_id, end_link_whatsit)
|
||||||
node.write(whatsit)
|
node.write(whatsit)
|
||||||
elseif token.scan_keyword"save" then
|
elseif scan_keyword"save" then
|
||||||
local whatsit = node.new(whatsit_id, save_whatsit)
|
local whatsit = node.new(whatsit_id, save_whatsit)
|
||||||
node.write(whatsit)
|
node.write(whatsit)
|
||||||
elseif token.scan_keyword"setmatrix" then
|
elseif scan_keyword"setmatrix" then
|
||||||
local matrix = token.scan_string()
|
local matrix = scan_string()
|
||||||
local whatsit = node.new(whatsit_id, setmatrix_whatsit)
|
local whatsit = node.new(whatsit_id, setmatrix_whatsit)
|
||||||
node.setproperty(whatsit, {
|
node.setproperty(whatsit, {
|
||||||
data = matrix,
|
data = matrix,
|
||||||
})
|
})
|
||||||
node.write(whatsit)
|
node.write(whatsit)
|
||||||
elseif token.scan_keyword"restore" then
|
elseif scan_keyword"restore" then
|
||||||
local whatsit = node.new(whatsit_id, restore_whatsit)
|
local whatsit = node.new(whatsit_id, restore_whatsit)
|
||||||
node.write(whatsit)
|
node.write(whatsit)
|
||||||
elseif token.scan_keyword"info" then
|
elseif scan_keyword"info" then
|
||||||
infodir = infodir .. token.scan_string()
|
infodir = infodir .. scan_string()
|
||||||
elseif token.scan_keyword"catalog" then
|
elseif scan_keyword"catalog" then
|
||||||
catalogdir = catalogdir .. ' ' .. token.scan_string()
|
catalogdir = catalogdir .. ' ' .. scan_string()
|
||||||
if token.scan_keyword'openaction' then
|
if scan_keyword'openaction' then
|
||||||
if catalog_openaction then
|
if catalog_openaction then
|
||||||
tex.error("Duplicate openaction", {"Only one use of \\pdfextension catalog is allowed to \z
|
tex.error("Duplicate openaction", {"Only one use of \\pdfextension catalog is allowed to \z
|
||||||
have an openaction."})
|
have an openaction."})
|
||||||
@ -697,19 +717,19 @@ token.luacmd("pdfextension", function(_, imm)
|
|||||||
catalog_openaction = get_action_attr(get_pfile(), action)
|
catalog_openaction = get_action_attr(get_pfile(), action)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif token.scan_keyword"names" then
|
elseif scan_keyword"names" then
|
||||||
namesdir = namesdir .. ' ' .. token.scan_string()
|
namesdir = namesdir .. ' ' .. scan_string()
|
||||||
elseif token.scan_keyword"obj" then
|
elseif scan_keyword"obj" then
|
||||||
local pfile = get_pfile()
|
local pfile = get_pfile()
|
||||||
if token.scan_keyword"reserveobjnum" then
|
if scan_keyword"reserveobjnum" then
|
||||||
lastobj = pfile:getobj()
|
lastobj = pfile:getobj()
|
||||||
else
|
else
|
||||||
local num = token.scan_keyword'useobjnum' and token.scan_int() or pfile:getobj()
|
local num = scan_keyword'useobjnum' and scan_int() or pfile:getobj()
|
||||||
lastobj = num
|
lastobj = num
|
||||||
local attr = token.scan_keyword'stream' and (token.scan_keyword'attr' and token.scan_string() or '')
|
local attr = scan_keyword'stream' and (scan_keyword'attr' and scan_string() or '')
|
||||||
local isfile = token.scan_keyword'file'
|
local isfile = scan_keyword'file'
|
||||||
local content = token.scan_string()
|
local content = scan_string()
|
||||||
if imm == 'immediate' then
|
if immediate == 8 then
|
||||||
if attr then
|
if attr then
|
||||||
pfile:stream(num, attr, content, isfile)
|
pfile:stream(num, attr, content, isfile)
|
||||||
else
|
else
|
||||||
@ -723,43 +743,43 @@ token.luacmd("pdfextension", function(_, imm)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif token.scan_keyword"refobj" then
|
elseif scan_keyword"refobj" then
|
||||||
local num = token.scan_int()
|
local num = scan_int()
|
||||||
local whatsit = node.new(whatsit_id, refobj_whatsit)
|
local whatsit = node.new(whatsit_id, refobj_whatsit)
|
||||||
node.setproperty(whatsit, {
|
node.setproperty(whatsit, {
|
||||||
obj = num,
|
obj = num,
|
||||||
})
|
})
|
||||||
node.write(whatsit)
|
node.write(whatsit)
|
||||||
elseif token.scan_keyword"outline" then
|
elseif scan_keyword"outline" then
|
||||||
local pfile = get_pfile()
|
local pfile = get_pfile()
|
||||||
local attr = token.scan_keyword'attr' and token.scan_string() or ''
|
local attr = scan_keyword'attr' and scan_string() or ''
|
||||||
local action
|
local action
|
||||||
if token.scan_keyword"useobjnum" then
|
if scan_keyword"useobjnum" then
|
||||||
action = token.scan_int()
|
action = scan_int()
|
||||||
else
|
else
|
||||||
local actionobj = scan_action()
|
local actionobj = scan_action()
|
||||||
action = pfile:indirect(nil, get_action_attr(pfile, actionobj))
|
action = pfile:indirect(nil, get_action_attr(pfile, actionobj))
|
||||||
end
|
end
|
||||||
local outline = get_outline()
|
local outline = get_outline()
|
||||||
if token.scan_keyword'level' then
|
if scan_keyword'level' then
|
||||||
local level = token.scan_int()
|
local level = scan_int()
|
||||||
local open = token.scan_keyword'open'
|
local open = scan_keyword'open'
|
||||||
local title = token.scan_string()
|
local title = scan_string()
|
||||||
outline:add(pdf_text(title), action, level, open, attr)
|
outline:add(pdf_text(title), action, level, open, attr)
|
||||||
else
|
else
|
||||||
local count = token.scan_keyword'count' and token.scan_int() or 0
|
local count = scan_keyword'count' and scan_int() or 0
|
||||||
local title = token.scan_string()
|
local title = scan_string()
|
||||||
outline:add_legacy(pdf_text(title), action, count, attr)
|
outline:add_legacy(pdf_text(title), action, count, attr)
|
||||||
end
|
end
|
||||||
elseif token.scan_keyword"dest" then
|
elseif scan_keyword"dest" then
|
||||||
local id
|
local id
|
||||||
if token.scan_keyword'num' then
|
if scan_keyword'num' then
|
||||||
id = token.scan_int()
|
id = scan_int()
|
||||||
if id <= 0 then
|
if id <= 0 then
|
||||||
error[[id must be positive]]
|
error[[id must be positive]]
|
||||||
end
|
end
|
||||||
elseif token.scan_keyword'name' then
|
elseif scan_keyword'name' then
|
||||||
id = token.scan_string()
|
id = scan_string()
|
||||||
else
|
else
|
||||||
error[[Unsupported id type]]
|
error[[Unsupported id type]]
|
||||||
end
|
end
|
||||||
@ -768,54 +788,54 @@ token.luacmd("pdfextension", function(_, imm)
|
|||||||
dest_id = id,
|
dest_id = id,
|
||||||
}
|
}
|
||||||
node.setproperty(whatsit, prop)
|
node.setproperty(whatsit, prop)
|
||||||
if token.scan_keyword'xyz' then
|
if scan_keyword'xyz' then
|
||||||
prop.dest_type = 'xyz'
|
prop.dest_type = 'xyz'
|
||||||
prop.xyz_zoom = token.scan_keyword'zoom' and token.scan_int()
|
prop.xyz_zoom = scan_keyword'zoom' and scan_int()
|
||||||
maybe_gobble_cmd(spacer_cmd)
|
maybe_gobble_cmd(spacer_cmd)
|
||||||
elseif token.scan_keyword'fitr' then
|
elseif scan_keyword'fitr' then
|
||||||
prop.dest_type = 'fitr'
|
prop.dest_type = 'fitr'
|
||||||
maybe_gobble_cmd(spacer_cmd)
|
maybe_gobble_cmd(spacer_cmd)
|
||||||
while true do
|
while true do
|
||||||
if token.scan_keyword'width' then
|
if scan_keyword'width' then
|
||||||
prop.width = token.scan_dimen()
|
prop.width = scan_dimen()
|
||||||
elseif token.scan_keyword'height' then
|
elseif scan_keyword'height' then
|
||||||
prop.height = token.scan_dimen()
|
prop.height = scan_dimen()
|
||||||
elseif token.scan_keyword'depth' then
|
elseif scan_keyword'depth' then
|
||||||
prop.depth = token.scan_dimen()
|
prop.depth = scan_dimen()
|
||||||
else
|
else
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif token.scan_keyword'fitbh' then
|
elseif scan_keyword'fitbh' then
|
||||||
prop.dest_type = 'fitbh'
|
prop.dest_type = 'fitbh'
|
||||||
maybe_gobble_cmd(spacer_cmd)
|
maybe_gobble_cmd(spacer_cmd)
|
||||||
elseif token.scan_keyword'fitbv' then
|
elseif scan_keyword'fitbv' then
|
||||||
prop.dest_type = 'fitbv'
|
prop.dest_type = 'fitbv'
|
||||||
maybe_gobble_cmd(spacer_cmd)
|
maybe_gobble_cmd(spacer_cmd)
|
||||||
elseif token.scan_keyword'fitb' then
|
elseif scan_keyword'fitb' then
|
||||||
prop.dest_type = 'fitb'
|
prop.dest_type = 'fitb'
|
||||||
maybe_gobble_cmd(spacer_cmd)
|
maybe_gobble_cmd(spacer_cmd)
|
||||||
elseif token.scan_keyword'fith' then
|
elseif scan_keyword'fith' then
|
||||||
prop.dest_type = 'fith'
|
prop.dest_type = 'fith'
|
||||||
maybe_gobble_cmd(spacer_cmd)
|
maybe_gobble_cmd(spacer_cmd)
|
||||||
elseif token.scan_keyword'fitv' then
|
elseif scan_keyword'fitv' then
|
||||||
prop.dest_type = 'fitv'
|
prop.dest_type = 'fitv'
|
||||||
maybe_gobble_cmd(spacer_cmd)
|
maybe_gobble_cmd(spacer_cmd)
|
||||||
elseif token.scan_keyword'fit' then
|
elseif scan_keyword'fit' then
|
||||||
prop.dest_type = 'fit'
|
prop.dest_type = 'fit'
|
||||||
maybe_gobble_cmd(spacer_cmd)
|
maybe_gobble_cmd(spacer_cmd)
|
||||||
else
|
else
|
||||||
error[[Unsupported dest type]]
|
error[[Unsupported dest type]]
|
||||||
end
|
end
|
||||||
node.write(whatsit)
|
node.write(whatsit)
|
||||||
elseif token.scan_keyword'mapline' then
|
elseif scan_keyword'mapline' then
|
||||||
fontmap.mapline(token.scan_string())
|
fontmap.mapline(scan_string())
|
||||||
else
|
else
|
||||||
-- The following error message gobbles the next word as a side effect.
|
-- The following error message gobbles the next word as a side effect.
|
||||||
-- This is intentional to make error-recovery easier.
|
-- This is intentional to make error-recovery easier.
|
||||||
error(string.format("Unknown PDF extension %s", token.scan_word()))
|
error(string.format("Unknown PDF extension %s", scan_word()))
|
||||||
end
|
end
|
||||||
end, "protected")
|
end, "value")
|
||||||
local imglib = require'luametalatex-pdf-image'
|
local imglib = require'luametalatex-pdf-image'
|
||||||
local imglib_node = imglib.node
|
local imglib_node = imglib.node
|
||||||
local imglib_write = imglib.write
|
local imglib_write = imglib.write
|
||||||
@ -832,19 +852,25 @@ local lastimage = -1
|
|||||||
local lastimagepages = -1
|
local lastimagepages = -1
|
||||||
|
|
||||||
-- These are very minimal right now but LaTeX isn't using the scaling etc. stuff anyway.
|
-- These are very minimal right now but LaTeX isn't using the scaling etc. stuff anyway.
|
||||||
token.luacmd("saveimageresource", function(imm)
|
token.luacmd("saveimageresource", function(_, immediate)
|
||||||
local attr = token.scan_keyword'attr' and token.scan_string() or nil
|
if immediate == "value" then return end
|
||||||
local page = token.scan_keyword'page' and token.scan_int() or nil
|
if immediate and immediate & 0x7 ~= 0 then
|
||||||
local userpassword = token.scan_keyword'userpassword' and token.scan_string() or nil
|
print(immediate)
|
||||||
local ownerpassword = token.scan_keyword'ownerpassword' and token.scan_string() or nil
|
immediate = immediate & 0x8
|
||||||
-- local colorspace = token.scan_keyword'colorspace' and token.scan_int() or nil -- Doesn't make sense for PDF
|
tex.error("Unexpected prefix", "You used \\saveimageresource with a prefix that doesn't belong there. I will ignore it for now.")
|
||||||
local pagebox = token.scan_keyword'mediabox' and 'media'
|
end
|
||||||
or token.scan_keyword'cropbox' and 'crop'
|
local attr = scan_keyword'attr' and scan_string() or nil
|
||||||
or token.scan_keyword'bleedbox' and 'bleed'
|
local page = scan_keyword'page' and scan_int() or nil
|
||||||
or token.scan_keyword'trimbox' and 'trim'
|
local userpassword = scan_keyword'userpassword' and scan_string() or nil
|
||||||
or token.scan_keyword'artbox' and 'art'
|
local ownerpassword = scan_keyword'ownerpassword' and scan_string() or nil
|
||||||
|
-- local colorspace = scan_keyword'colorspace' and scan_int() or nil -- Doesn't make sense for PDF
|
||||||
|
local pagebox = scan_keyword'mediabox' and 'media'
|
||||||
|
or scan_keyword'cropbox' and 'crop'
|
||||||
|
or scan_keyword'bleedbox' and 'bleed'
|
||||||
|
or scan_keyword'trimbox' and 'trim'
|
||||||
|
or scan_keyword'artbox' and 'art'
|
||||||
or nil
|
or nil
|
||||||
local filename = token.scan_string()
|
local filename = scan_string()
|
||||||
local img = imglib.scan{
|
local img = imglib.scan{
|
||||||
attr = attr,
|
attr = attr,
|
||||||
page = page,
|
page = page,
|
||||||
@ -856,14 +882,14 @@ token.luacmd("saveimageresource", function(imm)
|
|||||||
local pfile = get_pfile()
|
local pfile = get_pfile()
|
||||||
lastimage = imglib.get_num(pfile, img)
|
lastimage = imglib.get_num(pfile, img)
|
||||||
lastimagepages = img.pages or 1
|
lastimagepages = img.pages or 1
|
||||||
if imm == 'immediate' then
|
if immediate == 8 then
|
||||||
imglib_immediatewrite(pfile, img)
|
imglib_immediatewrite(pfile, img)
|
||||||
end
|
end
|
||||||
end, "protected")
|
end, "value")
|
||||||
|
|
||||||
token.luacmd("useimageresource", function()
|
token.luacmd("useimageresource", function()
|
||||||
local pfile = get_pfile()
|
local pfile = get_pfile()
|
||||||
local img = assert(imglib.from_num(token.scan_int()))
|
local img = assert(imglib.from_num(scan_int()))
|
||||||
imglib_write(pfile, img)
|
imglib_write(pfile, img)
|
||||||
end, "protected")
|
end, "protected")
|
||||||
|
|
||||||
@ -875,11 +901,11 @@ local integer_code = value_values.integer
|
|||||||
|
|
||||||
token.luacmd("lastsavedimageresourceindex", function()
|
token.luacmd("lastsavedimageresourceindex", function()
|
||||||
return integer_code, lastimage
|
return integer_code, lastimage
|
||||||
end, "protected", "value")
|
end, "value")
|
||||||
|
|
||||||
token.luacmd("lastsavedimageresourcepages", function()
|
token.luacmd("lastsavedimageresourcepages", function()
|
||||||
return integer_code, lastimagepages
|
return integer_code, lastimagepages
|
||||||
end, "protected", "value")
|
end, "value")
|
||||||
|
|
||||||
local savedbox = require'luametalatex-pdf-savedbox'
|
local savedbox = require'luametalatex-pdf-savedbox'
|
||||||
local savedbox_save = savedbox.save
|
local savedbox_save = savedbox.save
|
||||||
@ -890,7 +916,7 @@ function tex.saveboxresource(n, attr, resources, immediate, type, margin, pfile)
|
|||||||
error[[Invalid argument to saveboxresource]]
|
error[[Invalid argument to saveboxresource]]
|
||||||
end
|
end
|
||||||
token.put_next(token.create'box', token.new(n, token.command_id'char_given'))
|
token.put_next(token.create'box', token.new(n, token.command_id'char_given'))
|
||||||
n = token.scan_list()
|
n = scan_box()
|
||||||
end
|
end
|
||||||
margin = margin or pdfvariable.xformmargin
|
margin = margin or pdfvariable.xformmargin
|
||||||
return savedbox_save(pfile or get_pfile(), n, attr, resources, immediate, type, margin, fontdirs, usedglyphs)
|
return savedbox_save(pfile or get_pfile(), n, attr, resources, immediate, type, margin, fontdirs, usedglyphs)
|
||||||
@ -899,41 +925,46 @@ tex.useboxresource = savedbox.use
|
|||||||
|
|
||||||
local lastbox = -1
|
local lastbox = -1
|
||||||
|
|
||||||
token.luacmd("saveboxresource", function(imm)
|
token.luacmd("saveboxresource", function(_, immediate)
|
||||||
local type
|
if immediate == "value" then return end
|
||||||
if token.scan_keyword'type' then
|
if immediate and immediate & 0x7 ~= 0 then
|
||||||
texio.write_nl('XForm type attribute ignored')
|
immediate = immediate & 0x8
|
||||||
type = token.scan_int()
|
tex.error("Unexpected prefix", "You used \\saveboxresource with a prefix that doesn't belong there. I will ignore it for now.")
|
||||||
end
|
end
|
||||||
local attr = token.scan_keyword'attr' and token.scan_string() or nil
|
local type
|
||||||
local resources = token.scan_keyword'resources' and token.scan_string() or nil
|
if scan_keyword'type' then
|
||||||
local margin = token.scan_keyword'margin' and token.scan_dimen() or nil
|
texio.write_nl('XForm type attribute ignored')
|
||||||
local box = token.scan_int()
|
type = scan_int()
|
||||||
|
end
|
||||||
|
local attr = scan_keyword'attr' and scan_string() or nil
|
||||||
|
local resources = scan_keyword'resources' and scan_string() or nil
|
||||||
|
local margin = scan_keyword'margin' and scan_dimen() or nil
|
||||||
|
local box = scan_int()
|
||||||
|
|
||||||
local index = tex.saveboxresource(box, attr, resources, imm == 'immediate', type, margin)
|
local index = tex.saveboxresource(box, attr, resources, immediate == 8, type, margin)
|
||||||
lastbox = index
|
lastbox = index
|
||||||
end, "protected")
|
end, "value")
|
||||||
|
|
||||||
token.luacmd("useboxresource", function()
|
token.luacmd("useboxresource", function()
|
||||||
local width, height, depth
|
local width, height, depth
|
||||||
while true do
|
while true do
|
||||||
if token.scan_keyword'width' then
|
if scan_keyword'width' then
|
||||||
width = token.scan_dimen()
|
width = scan_dimen()
|
||||||
elseif token.scan_keyword'height' then
|
elseif scan_keyword'height' then
|
||||||
height = token.scan_dimen()
|
height = scan_dimen()
|
||||||
elseif token.scan_keyword'depth' then
|
elseif scan_keyword'depth' then
|
||||||
depth = token.scan_dimen()
|
depth = scan_dimen()
|
||||||
else
|
else
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local index = token.scan_int()
|
local index = scan_int()
|
||||||
node.write((tex.useboxresource(index, width, height, depth)))
|
node.write((tex.useboxresource(index, width, height, depth)))
|
||||||
end, "protected")
|
end, "protected")
|
||||||
|
|
||||||
token.luacmd("lastsavedboxresourceindex", function()
|
token.luacmd("lastsavedboxresourceindex", function()
|
||||||
return integer_code, lastbox
|
return integer_code, lastbox
|
||||||
end, "protected", "value")
|
end, "value")
|
||||||
|
|
||||||
local saved_pos_x, saved_pos_y = -1, -1
|
local saved_pos_x, saved_pos_y = -1, -1
|
||||||
local save_pos_whatsit = declare_whatsit('save_pos', function(_, _, _, x, y)
|
local save_pos_whatsit = declare_whatsit('save_pos', function(_, _, _, x, y)
|
||||||
@ -945,11 +976,11 @@ end, "protected")
|
|||||||
|
|
||||||
token.luacmd("lastxpos", function()
|
token.luacmd("lastxpos", function()
|
||||||
return integer_code, (saved_pos_x+.5)//1
|
return integer_code, (saved_pos_x+.5)//1
|
||||||
end, "protected", "value")
|
end, "value")
|
||||||
|
|
||||||
token.luacmd("lastypos", function()
|
token.luacmd("lastypos", function()
|
||||||
return integer_code, (saved_pos_y+.5)//1
|
return integer_code, (saved_pos_y+.5)//1
|
||||||
end, "protected", "value")
|
end, "value")
|
||||||
|
|
||||||
local function pdf_register_funcs(name)
|
local function pdf_register_funcs(name)
|
||||||
pdf[name] = ""
|
pdf[name] = ""
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
-- Two callbacks are defined in other files: pre_dump in lateinit and find_fmt_file in init
|
-- Three callbacks are defined in other files: stop_run in back-pdf, pre_dump in lateinit, and find_fmt_file in init
|
||||||
|
|
||||||
local read_tfm = font.read_tfm
|
local read_tfm = font.read_tfm
|
||||||
local font_define = font.define
|
local font_define = font.define
|
||||||
local callback_register = callback.register
|
local callbacks = require'luametalatex-callbacks'
|
||||||
|
|
||||||
if status.ini_version then
|
if status.ini_version then
|
||||||
callback_register('define_font', function(name, size)
|
function callbacks.define_font(name, size)
|
||||||
local f = read_tfm(name, size)
|
local f = read_tfm(name, size)
|
||||||
if not f then return end
|
if not f then return end
|
||||||
local id = font_define(f)
|
local id = font_define(f)
|
||||||
lua.prepared_code[#lua.prepared_code+1] = string.format("assert(%i == font.define(font.read_tfm(%q, %i)))", id, name, size)
|
lua.prepared_code[#lua.prepared_code+1] = string.format("assert(%i == font.define(font.read_tfm(%q, %i)))", id, name, size)
|
||||||
return id
|
return id
|
||||||
end)
|
end
|
||||||
else
|
else
|
||||||
callback_register('define_font', function(name, size)
|
function callbacks.define_font(name, size)
|
||||||
local f = read_tfm(name, size)
|
local f = read_tfm(name, size)
|
||||||
if not f then
|
if not f then
|
||||||
tex.error(string.format("Font %q not found", name), "The requested font could't be loaded.\n\z
|
tex.error(string.format("Font %q not found", name), "The requested font could't be loaded.\n\z
|
||||||
@ -22,40 +22,94 @@ else
|
|||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
return font.define(f)
|
return font.define(f)
|
||||||
end)
|
end
|
||||||
|
end
|
||||||
|
callbacks.__freeze'define_font'
|
||||||
|
|
||||||
|
function callbacks.find_log_file(name) return name end
|
||||||
|
callbacks.__freeze'find_log_file'
|
||||||
|
|
||||||
|
-- find_data_file is not an engine callback in luametatex, so we don't __freeze it
|
||||||
|
if status.ini_version then
|
||||||
|
function unhook_expl()
|
||||||
|
callbacks.find_data_file = nil
|
||||||
|
end
|
||||||
|
function callbacks.find_data_file(name)
|
||||||
|
if name == 'ltexpl.ltx' then
|
||||||
|
name = 'luametalatex-ltexpl-hook'
|
||||||
|
end
|
||||||
|
return kpse.find_file(name, 'tex', true)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
callback_register('find_log_file', function(name) return name end)
|
|
||||||
do
|
|
||||||
local function normal_find_data_file(name)
|
local function normal_find_data_file(name)
|
||||||
return kpse.find_file(name, 'tex', true)
|
return kpse.find_file(name, 'tex', true)
|
||||||
end
|
end
|
||||||
if status.ini_version then
|
function callbacks.open_data_file(name)
|
||||||
function unhook_expl()
|
local find_callback = callbacks.find_data_file
|
||||||
callback_register('find_data_file', normal_find_data_file)
|
local path
|
||||||
end
|
if find_callback then
|
||||||
callback_register('find_data_file', function(name)
|
path = find_callback(name)
|
||||||
if name == 'ltexpl.ltx' then
|
|
||||||
name = 'luametalatex-ltexpl-hook'
|
|
||||||
end
|
|
||||||
return normal_find_data_file(name)
|
|
||||||
end)
|
|
||||||
else
|
else
|
||||||
callback_register('find_data_file', normal_find_data_file)
|
path = kpse.find_file(name, 'tex', true)
|
||||||
end
|
end
|
||||||
end
|
if not path then return end
|
||||||
callback_register('open_data_file', function(name)
|
|
||||||
local f = io.open(name, 'r')
|
local open_callback = callbacks.open_data_file
|
||||||
return setmetatable({
|
if open_callback then
|
||||||
|
return open_callback(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
local f = io.open(path, 'r')
|
||||||
|
return f and setmetatable({
|
||||||
reader = function()
|
reader = function()
|
||||||
local line = f:read()
|
local line = f:read()
|
||||||
return line
|
return line
|
||||||
end,
|
end,
|
||||||
close = function()error[[1]] return f:close() end,
|
close = function() f:close() f = nil end,
|
||||||
}, {
|
}, {
|
||||||
__gc = function()f:close()end,
|
__gc = function() if f then f:close() end end,
|
||||||
})
|
})
|
||||||
end)
|
end
|
||||||
callback_register('handle_error_hook', function()
|
callbacks.__freeze('open_data_file', true)
|
||||||
|
|
||||||
|
local do_terminal_input do
|
||||||
|
local function terminal_open_data_file()
|
||||||
|
local old = callbacks.open_data_file
|
||||||
|
return function()
|
||||||
|
callbacks.open_data_file = old
|
||||||
|
return {
|
||||||
|
reader = function()
|
||||||
|
texio.write_nl('term', '* ')
|
||||||
|
local line = io.stdin:read()
|
||||||
|
return line
|
||||||
|
end,
|
||||||
|
close = function() end,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function do_terminal_input()
|
||||||
|
local old_find = callbacks.find_data_file
|
||||||
|
function callbacks.find_data_file(name)
|
||||||
|
callbacks.find_data_file = old_find
|
||||||
|
return name
|
||||||
|
end
|
||||||
|
callbacks.open_data_file = terminal_open_data_file()
|
||||||
|
token.put_next(token.create'expandafter', token.create'relax', token.create'input', 'TERMINAL ')
|
||||||
|
token.skip_next_expanded()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function callbacks.intercept_tex_error(mode, eof)
|
||||||
|
-- if eof then
|
||||||
|
-- print'EOF'
|
||||||
|
-- tex.runtoks(function()token.put_next(token.create'tracingall')end)
|
||||||
|
-- do_terminal_input()
|
||||||
|
-- tex.runtoks(token.skip_next)
|
||||||
|
-- return 3
|
||||||
|
-- end
|
||||||
|
texio.write'.'
|
||||||
|
tex.show_context()
|
||||||
|
if mode ~= 3 then return mode end
|
||||||
repeat
|
repeat
|
||||||
texio.write_nl'? '
|
texio.write_nl'? '
|
||||||
local line = io.read()
|
local line = io.read()
|
||||||
@ -85,4 +139,5 @@ callback_register('handle_error_hook', function()
|
|||||||
end
|
end
|
||||||
until false
|
until false
|
||||||
return 3
|
return 3
|
||||||
end)
|
end
|
||||||
|
callbacks.__freeze'intercept_tex_error'
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
|
local scan_dimen = token.scan_dimen
|
||||||
|
local scan_int = token.scan_integer
|
||||||
|
local scan_keyword = token.scan_keyword
|
||||||
|
|
||||||
local value_values = token.values'value'
|
local value_values = token.values'value'
|
||||||
for i=0,#value_values do
|
for i=0, #value_values do
|
||||||
value_values[value_values[i]] = i
|
value_values[value_values[i]] = i
|
||||||
end
|
end
|
||||||
local count_code = value_values.integer
|
local count_code = value_values.integer
|
||||||
@ -30,10 +34,10 @@ local function tex_variable(value, scanner, name, default)
|
|||||||
if scanning == 'value' then
|
if scanning == 'value' then
|
||||||
return value, tex_variables[name]
|
return value, tex_variables[name]
|
||||||
else
|
else
|
||||||
token.scan_keyword'='
|
scan_keyword'='
|
||||||
return set_local(tex_variables, name, scanner(), scanning == 'global')
|
return set_local(tex_variables, name, scanner(), scanning and scanning & 4 == 4)
|
||||||
end
|
end
|
||||||
end, 'global', 'protected', 'value')
|
end, 'global', 'value')
|
||||||
if status.ini_version then
|
if status.ini_version then
|
||||||
tex_variables[name] = default
|
tex_variables[name] = default
|
||||||
end
|
end
|
||||||
@ -99,14 +103,14 @@ local function pdf_variable(value, scanner, name, default, force_default)
|
|||||||
if scanning == 'value' then
|
if scanning == 'value' then
|
||||||
return value, real_pdf_variables[name]
|
return value, real_pdf_variables[name]
|
||||||
elseif force_default then
|
elseif force_default then
|
||||||
token.scan_keyword'='
|
scan_keyword'='
|
||||||
local new = scanner()
|
local new = scanner()
|
||||||
if new ~= default then
|
if new ~= default then
|
||||||
texio.write_nl('term and log', string.format("Unsupported PDF variable: \z
|
texio.write_nl('term and log', string.format("Unsupported PDF variable: \z
|
||||||
%q is not supported and fixed to %i, but you tried to set it to %i", name, default, new))
|
%q is not supported and fixed to %i, but you tried to set it to %i", name, default, new))
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
token.scan_keyword'='
|
scan_keyword'='
|
||||||
return set_local(real_pdf_variables, name, scanner(), scanning == 'global')
|
return set_local(real_pdf_variables, name, scanner(), scanning == 'global')
|
||||||
end
|
end
|
||||||
end, 'global', 'protected', 'value')
|
end, 'global', 'protected', 'value')
|
||||||
@ -115,43 +119,43 @@ local function pdf_variable(value, scanner, name, default, force_default)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
tex_variable(count_code, token.scan_int, 'suppressfontnotfounderror', 0)
|
tex_variable(count_code, scan_int, 'suppressfontnotfounderror', 0)
|
||||||
tex_variable(count_code, token.scan_int, 'outputmode', 1) -- The "traditional" default would be 0,
|
tex_variable(count_code, scan_int, 'outputmode', 1) -- The "traditional" default would be 0,
|
||||||
-- but we do not actually support that.
|
-- but we do not actually support that.
|
||||||
tex_variable(dimen_code, token.scan_dimen, 'pageheight', 0)
|
tex_variable(dimen_code, scan_dimen, 'pageheight', 0)
|
||||||
tex_variable(dimen_code, token.scan_dimen, 'pagewidth', 0)
|
tex_variable(dimen_code, scan_dimen, 'pagewidth', 0)
|
||||||
|
|
||||||
tex_variable(count_code, token.scan_int, 'bodydirection', 0)
|
tex_variable(count_code, scan_int, 'bodydirection', 0)
|
||||||
tex_variable(count_code, token.scan_int, 'pagedirection', 0)
|
tex_variable(count_code, scan_int, 'pagedirection', 0)
|
||||||
|
|
||||||
pdf_variable(dimen_code, token.scan_dimen, 'horigin', tex.sp'1in')
|
pdf_variable(dimen_code, scan_dimen, 'horigin', tex.sp'1in')
|
||||||
pdf_variable(dimen_code, token.scan_dimen, 'vorigin', tex.sp'1in')
|
pdf_variable(dimen_code, scan_dimen, 'vorigin', tex.sp'1in')
|
||||||
pdf_variable(dimen_code, token.scan_dimen, 'linkmargin', tex.sp'0pt')
|
pdf_variable(dimen_code, scan_dimen, 'linkmargin', tex.sp'0pt')
|
||||||
pdf_variable(dimen_code, token.scan_dimen, 'destmargin', tex.sp'0pt')
|
pdf_variable(dimen_code, scan_dimen, 'destmargin', tex.sp'0pt')
|
||||||
pdf_variable(dimen_code, token.scan_dimen, 'xformmargin', tex.sp'0pt')
|
pdf_variable(dimen_code, scan_dimen, 'xformmargin', tex.sp'0pt')
|
||||||
pdf_variable(dimen_code, token.scan_dimen, 'threadmargin', tex.sp'0pt', true) -- We don't support threads, so this isn't doing anything
|
pdf_variable(dimen_code, scan_dimen, 'threadmargin', tex.sp'0pt', true) -- We don't support threads, so this isn't doing anything
|
||||||
pdf_variable(count_code, token.scan_int, 'majorversion', 1)
|
pdf_variable(count_code, scan_int, 'majorversion', 1)
|
||||||
pdf_variable(count_code, token.scan_int, 'minorversion', 7)
|
pdf_variable(count_code, scan_int, 'minorversion', 7)
|
||||||
pdf_variable(count_code, token.scan_int, 'compresslevel', 9)
|
pdf_variable(count_code, scan_int, 'compresslevel', 9)
|
||||||
pdf_variable(count_code, token.scan_int, 'objcompresslevel', 3)
|
pdf_variable(count_code, scan_int, 'objcompresslevel', 3)
|
||||||
|
|
||||||
pdf_variable(count_code, token.scan_int, 'decimaldigits', 4, true) -- Will probably stay fixed, but should be more consistent
|
pdf_variable(count_code, scan_int, 'decimaldigits', 4, true) -- Will probably stay fixed, but should be more consistent
|
||||||
pdf_variable(count_code, token.scan_int, 'gentounicode', 0, true) -- We expect the fontloader to generade tounicode tables. Might change at some point
|
pdf_variable(count_code, scan_int, 'gentounicode', 0, true) -- We expect the fontloader to generade tounicode tables. Might change at some point
|
||||||
-- These two are ignored, but that is consistent with pdfTeX as long as imageapplygamma is 0:
|
-- These two are ignored, but that is consistent with pdfTeX as long as imageapplygamma is 0:
|
||||||
pdf_variable(count_code, token.scan_int, 'gamma', 1000)
|
pdf_variable(count_code, scan_int, 'gamma', 1000)
|
||||||
pdf_variable(count_code, token.scan_int, 'imagegamma', 1000)
|
pdf_variable(count_code, scan_int, 'imagegamma', 1000)
|
||||||
pdf_variable(count_code, token.scan_int, 'imageapplygamma', 0, true)
|
pdf_variable(count_code, scan_int, 'imageapplygamma', 0, true)
|
||||||
pdf_variable(count_code, token.scan_int, 'imagehicolor', 1, true) -- We don't consider ancient PDF versions, no no reason to strip images
|
pdf_variable(count_code, scan_int, 'imagehicolor', 1, true) -- We don't consider ancient PDF versions, no no reason to strip images
|
||||||
pdf_variable(count_code, token.scan_int, 'imageaddfilename', 0, true) -- Could be added, but I never saw a reason for this anyway.
|
pdf_variable(count_code, scan_int, 'imageaddfilename', 0, true) -- Could be added, but I never saw a reason for this anyway.
|
||||||
pdf_variable(count_code, token.scan_int, 'inclusionerrorlevel', -1, true) -- FIXME: At least a warning should be supported
|
pdf_variable(count_code, scan_int, 'inclusionerrorlevel', -1, true) -- FIXME: At least a warning should be supported
|
||||||
pdf_variable(count_code, token.scan_int, 'inclusioncopyfonts', 0, true) -- Would be fragile and restrict our ability to use "creative" font constructs
|
pdf_variable(count_code, scan_int, 'inclusioncopyfonts', 0, true) -- Would be fragile and restrict our ability to use "creative" font constructs
|
||||||
pdf_variable(count_code, token.scan_int, 'uniqueresname', 0, true) -- I add this if you show me a usecase
|
pdf_variable(count_code, scan_int, 'uniqueresname', 0, true) -- I add this if you show me a usecase
|
||||||
pdf_variable(count_code, token.scan_int, 'pagebox', 2, true) -- TODO (1: media, 2: crop, 3: bleed, 4: trim, 5: art
|
pdf_variable(count_code, scan_int, 'pagebox', 2, true) -- TODO (1: media, 2: crop, 3: bleed, 4: trim, 5: art
|
||||||
pdf_variable(count_code, token.scan_int, 'forcepagebox', 0, true) -- Considered obsolete even in pdfTeX
|
pdf_variable(count_code, scan_int, 'forcepagebox', 0, true) -- Considered obsolete even in pdfTeX
|
||||||
pdf_variable(count_code, token.scan_int, 'imageresolution', 72, true) -- TODO Also 0 should be the same as 72 ?!?!?!?
|
pdf_variable(count_code, scan_int, 'imageresolution', 72, true) -- TODO Also 0 should be the same as 72 ?!?!?!?
|
||||||
|
|
||||||
pdf_variable(count_code, token.scan_int, 'pkresolution', 1200) -- Original default is 72, but that's crazy
|
pdf_variable(count_code, scan_int, 'pkresolution', 1200) -- Original default is 72, but that's crazy
|
||||||
pdf_variable(count_code, token.scan_int, 'pkfixeddpi', 0) -- TODO: Implemented, but even when set to one, font sharing doesn't adapt yet.
|
pdf_variable(count_code, scan_int, 'pkfixeddpi', 0) -- TODO: Implemented, but even when set to one, font sharing doesn't adapt yet.
|
||||||
-- Changing that is complicated because it has to be known pretty early.
|
-- Changing that is complicated because it has to be known pretty early.
|
||||||
pdf_toks('pkmode', '')
|
pdf_toks('pkmode', '')
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ first = first .. later
|
|||||||
|
|
||||||
local list = {}
|
local list = {}
|
||||||
|
|
||||||
return function(t)
|
return true and function(t) return '' end or function(t)
|
||||||
local length = #t
|
local length = #t
|
||||||
local tmpl = first
|
local tmpl = first
|
||||||
for i, mod in ipairs(t) do
|
for i, mod in ipairs(t) do
|
||||||
|
@ -1,24 +1,69 @@
|
|||||||
-- Now overwrite the callback functionality. Our system is based on the ssumption there there are
|
-- Now overwrite the callback functionality. Our system is based on the ssumption there there are
|
||||||
-- no unknown callback names, just callbacks very unlikely to ever be called. That doesn't lead to
|
-- no unknown callback names, just callbacks very unlikely to ever be called. That doesn't lead to
|
||||||
-- good error checking, but we expect this to be overwritten by LaTeX anyway.
|
-- good error checking, but we expect this to be overwritten by LaTeX anyway.
|
||||||
|
--
|
||||||
|
-- There are four callback types on this level:
|
||||||
|
-- 1. luametalatex defined callbacks. They are not real engine callbacks, the code using them is
|
||||||
|
-- responsible for their potential non-existance.
|
||||||
|
-- 2. Engine callbacks not defined by us. They are simply passed on to the engine. All engine
|
||||||
|
-- callbacks are set to this by default.
|
||||||
|
-- 3. Engine callbacks with a provided default. There is a luametalatex implementation, but it
|
||||||
|
-- can be overwritten by the user. If the user disabled their implementation, so provided
|
||||||
|
-- default is restored.
|
||||||
|
-- 4. Engine callbacks with mandatory code. The luametalatex implementation can not be overwitten
|
||||||
|
-- by the user, but a luametalatex-defined callback is added with the same name.
|
||||||
|
--
|
||||||
|
-- A callback has type 1 or type 4 if is_user_callback is true. If it has type 4, is_user_callback
|
||||||
|
-- has to be set manually and in addition, an implementation if the system callback is registered.
|
||||||
|
--
|
||||||
|
-- A callback has type 3, if is_user_callback is false and system_callbacks is defined.
|
||||||
|
|
||||||
|
local callback_known = callback.known
|
||||||
local callback_find = callback.find
|
local callback_find = callback.find
|
||||||
local callback_register = callback.register
|
local callback_register = callback.register
|
||||||
local rawset = rawset
|
local rawset = rawset
|
||||||
local callbacks = setmetatable({}, {
|
local system_callbacks = {}
|
||||||
|
local is_user_callback = setmetatable({}, {
|
||||||
|
__index = function(t, name)
|
||||||
|
local is_user = not callback_known(name)
|
||||||
|
t[name] = is_user
|
||||||
|
return is_user
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
local callbacks = setmetatable({
|
||||||
|
__freeze = function(name, fixed)
|
||||||
|
-- Convert from type 2 to type 3 or 4. This function will be deleted before user code runs.
|
||||||
|
assert(not is_user_callback[name], 'Not a system callback')
|
||||||
|
assert(not system_callbacks[name], 'Already frozen')
|
||||||
|
is_user_callback[name] = fixed and true or false
|
||||||
|
system_callbacks[name] = callback_find(name)
|
||||||
|
assert(system_callbacks[name], 'Attempt to freeze undefined callback')
|
||||||
|
end,
|
||||||
|
}, {
|
||||||
__index = function(cbs, name)
|
__index = function(cbs, name)
|
||||||
|
if is_user_callback[name] then
|
||||||
|
-- Avoid repetitive lookups
|
||||||
|
rawset(cbs, name, false)
|
||||||
|
return false
|
||||||
|
end
|
||||||
return callback_find(name)
|
return callback_find(name)
|
||||||
end,
|
end,
|
||||||
__newindex = function(cbs, name, new)
|
__newindex = function(cbs, name, new)
|
||||||
return callback_register(name, new) or rawset(cbs, name, new)
|
if is_user_callback[name] then
|
||||||
|
-- Avoid repetitive lookups
|
||||||
|
rawset(cbs, name, new or false)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
return callback_register(name, new or system_callbacks[name])
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
function callback.register(name, new)
|
function callback.register(name, new)
|
||||||
callbacks[name] = new
|
callbacks[name] = new
|
||||||
end
|
end
|
||||||
function callback.find(name)
|
-- The and ... or construction makes sure that even in raw mode, non-engine callbacks are found
|
||||||
return callbacks[name]
|
function callback.find(name, raw)
|
||||||
|
return raw and callback_find(name) or callbacks[name]
|
||||||
end
|
end
|
||||||
|
|
||||||
return callbacks
|
return callbacks
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
local scan_int = token.scan_integer
|
||||||
|
local scan_keyword = token.scan_keyword
|
||||||
|
|
||||||
-- local names = {}
|
-- local names = {}
|
||||||
local setters = {
|
local setters = {
|
||||||
}
|
}
|
||||||
@ -14,19 +17,18 @@ function tex.getpardir() return tex.pardirection end
|
|||||||
local integer_code = value_values.integer
|
local integer_code = value_values.integer
|
||||||
local function set_xdir(id, scanning)
|
local function set_xdir(id, scanning)
|
||||||
if scanning == 'value' then
|
if scanning == 'value' then
|
||||||
print(scanning)
|
|
||||||
return integer_code, getters[id]()
|
return integer_code, getters[id]()
|
||||||
end
|
end
|
||||||
-- local global = scanning == 'global'
|
-- local global = scanning == 'global'
|
||||||
local value
|
local value
|
||||||
if token.scan_keyword'tlt' then
|
if scan_keyword'tlt' then
|
||||||
value = 0
|
value = 0
|
||||||
elseif token.scan_keyword'trt' then
|
elseif scan_keyword'trt' then
|
||||||
value = 1
|
value = 1
|
||||||
else
|
else
|
||||||
value = token.scan_int()
|
value = scan_int()
|
||||||
end
|
end
|
||||||
setters[id](value)
|
setters[id](value, scanning)
|
||||||
end
|
end
|
||||||
return function(name)
|
return function(name)
|
||||||
local getter = tex["get" .. name]
|
local getter = tex["get" .. name]
|
||||||
|
@ -1,3 +1,12 @@
|
|||||||
|
local scan_int = token.scan_integer
|
||||||
|
local scan_token = token.scan_token
|
||||||
|
local scan_tokenlist = token.scan_tokenlist
|
||||||
|
local scan_keyword = token.scan_keyword
|
||||||
|
local scan_csname = token.scan_csname
|
||||||
|
local set_macro = token.set_macro
|
||||||
|
|
||||||
|
local callback_find = callback.find
|
||||||
|
|
||||||
local lua_call_cmd = token.command_id'lua_call'
|
local lua_call_cmd = token.command_id'lua_call'
|
||||||
local properties = node.direct.get_properties_table()
|
local properties = node.direct.get_properties_table()
|
||||||
node.direct.properties = properties
|
node.direct.properties = properties
|
||||||
@ -20,7 +29,7 @@ local function scan_filename()
|
|||||||
local quoted = false
|
local quoted = false
|
||||||
local tok, cmd
|
local tok, cmd
|
||||||
repeat
|
repeat
|
||||||
tok = token.scan_token()
|
tok = scan_token()
|
||||||
cmd = tok.command
|
cmd = tok.command
|
||||||
until cmd ~= spacer_cmd and cmd ~= relax_cmd
|
until cmd ~= spacer_cmd and cmd ~= relax_cmd
|
||||||
while (tok.command <= 12 and tok.command > 0 and tok.command ~= 9 and tok.index <= token.biggest_char()
|
while (tok.command <= 12 and tok.command > 0 and tok.command ~= 9 and tok.index <= token.biggest_char()
|
||||||
@ -31,39 +40,68 @@ local function scan_filename()
|
|||||||
else
|
else
|
||||||
name[#name+1] = tok.index
|
name[#name+1] = tok.index
|
||||||
end
|
end
|
||||||
tok = token.scan_token()
|
tok = scan_token()
|
||||||
end
|
end
|
||||||
return utf8.char(table.unpack(name))
|
return utf8.char(table.unpack(name))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- These are chosen to coincide with ltluatex's default catcodetables.
|
||||||
|
-- In expl-hook, we check that the values are as expected.
|
||||||
|
local initex_catcodetable = 1
|
||||||
|
local string_catcodetable = 2
|
||||||
|
if status.ini_version then
|
||||||
|
tex.runtoks(function()tex.sprint[[\initcatcodetable 1\initcatcodetable 2]]end)
|
||||||
|
local setcatcode = tex.setcatcode
|
||||||
|
for i=0,127 do
|
||||||
|
setcatcode('global', 2, i, 12)
|
||||||
|
end
|
||||||
|
setcatcode('global', 2, 32, 10)
|
||||||
|
end
|
||||||
|
|
||||||
local l = lpeg or require'lpeg'
|
local l = lpeg or require'lpeg'
|
||||||
local add_file_extension = l.Cs((1-('.' * (1-l.S'./\\')^0) * -1)^0 * (l.P(1)^1+l.Cc'.tex'))
|
local add_file_extension = l.Cs((1-('.' * (1-l.S'./\\')^0) * -1)^0 * (l.P(1)^1+l.Cc'.tex'))
|
||||||
local ofiles = {}
|
local ofiles, ifiles = {}, {}
|
||||||
local function do_openout(p)
|
local function do_openout(p)
|
||||||
if ofiles[p.file] then
|
if ofiles[p.file] then
|
||||||
error[[Existing file]]
|
ofiles[p.file]:close()
|
||||||
else
|
end
|
||||||
local msg
|
local msg
|
||||||
ofiles[p.file], msg = io.open(add_file_extension:match(p.name), 'w')
|
ofiles[p.file], msg = io.open(add_file_extension:match(p.name), 'w')
|
||||||
if not ofiles[p.file] then
|
if not ofiles[p.file] then
|
||||||
error(msg)
|
error(msg)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local open_whatsit = new_whatsit('open', do_openout)
|
local open_whatsit = new_whatsit('open', do_openout)
|
||||||
token.luacmd("openout", function(_, immediate) -- \openout
|
token.luacmd("openout", function(_, immediate) -- \openout
|
||||||
local file = token.scan_int()
|
if immediate == "value" then return end
|
||||||
token.scan_keyword'='
|
if immediate and immediate & 0x7 ~= 0 then
|
||||||
|
immediate = immediate & 0x8
|
||||||
|
tex.error("Unexpected prefix", "You used \\openout with a prefix that doesn't belong there. I will ignore it for now.")
|
||||||
|
end
|
||||||
|
local file = scan_int()
|
||||||
|
scan_keyword'='
|
||||||
local name = scan_filename()
|
local name = scan_filename()
|
||||||
local props = {file = file, name = name}
|
local props = {file = file, name = name}
|
||||||
if immediate == "immediate" then
|
if immediate and immediate == 8 then
|
||||||
do_openout(props)
|
do_openout(props)
|
||||||
else
|
else
|
||||||
local whatsit = node.direct.new(whatsit_id, open_whatsit)
|
local whatsit = node.direct.new(whatsit_id, open_whatsit)
|
||||||
properties[whatsit] = props
|
properties[whatsit] = props
|
||||||
node.direct.write(whatsit)
|
node.direct.write(whatsit)
|
||||||
end
|
end
|
||||||
end, "protected")
|
end, "value")
|
||||||
|
token.luacmd("openin", function(_, prefix)
|
||||||
|
if prefix == "value" then return end
|
||||||
|
local file = scan_int()
|
||||||
|
scan_keyword'='
|
||||||
|
local name = scan_filename()
|
||||||
|
if ifiles[file] then
|
||||||
|
ifiles[file]:close()
|
||||||
|
end
|
||||||
|
local msg
|
||||||
|
ifiles[file] = callback_find('open_data_file', true)(name) -- raw to pick up our wrapper which handles defaults and finding the file
|
||||||
|
end, "value")
|
||||||
|
|
||||||
local function do_closeout(p)
|
local function do_closeout(p)
|
||||||
if ofiles[p.file] then
|
if ofiles[p.file] then
|
||||||
ofiles[p.file]:close()
|
ofiles[p.file]:close()
|
||||||
@ -72,16 +110,30 @@ local function do_closeout(p)
|
|||||||
end
|
end
|
||||||
local close_whatsit = new_whatsit('close', do_closeout)
|
local close_whatsit = new_whatsit('close', do_closeout)
|
||||||
token.luacmd("closeout", function(_, immediate) -- \closeout
|
token.luacmd("closeout", function(_, immediate) -- \closeout
|
||||||
local file = token.scan_int()
|
if immediate == "value" then return end
|
||||||
|
if immediate and immediate & 0x7 ~= 0 then
|
||||||
|
immediate = immediate & 0x8
|
||||||
|
tex.error("Unexpected prefix", "You used \\closeout with a prefix that doesn't belong there. I will ignore it for now.")
|
||||||
|
end
|
||||||
|
local file = scan_int()
|
||||||
local props = {file = file}
|
local props = {file = file}
|
||||||
if immediate == "immediate" then
|
if immediate == 8 then
|
||||||
do_closeout(props)
|
do_closeout(props)
|
||||||
else
|
else
|
||||||
local whatsit = node.direct.new(whatsit_id, close_whatsit)
|
local whatsit = node.direct.new(whatsit_id, close_whatsit)
|
||||||
properties[whatsit] = props
|
properties[whatsit] = props
|
||||||
node.direct.write(whatsit)
|
node.direct.write(whatsit)
|
||||||
end
|
end
|
||||||
end, "protected")
|
end, "value")
|
||||||
|
token.luacmd("closein", function(_, prefix)
|
||||||
|
if prefix == "value" then return end
|
||||||
|
local file = scan_int()
|
||||||
|
if ifiles[file] then
|
||||||
|
ifiles[file]:close()
|
||||||
|
ifiles[file] = nil
|
||||||
|
end
|
||||||
|
end, "value")
|
||||||
|
|
||||||
local function do_write(p)
|
local function do_write(p)
|
||||||
local content = token.to_string(p.data) .. '\n'
|
local content = token.to_string(p.data) .. '\n'
|
||||||
local file = ofiles[p.file]
|
local file = ofiles[p.file]
|
||||||
@ -93,17 +145,127 @@ local function do_write(p)
|
|||||||
end
|
end
|
||||||
local write_whatsit = new_whatsit('write', do_write)
|
local write_whatsit = new_whatsit('write', do_write)
|
||||||
token.luacmd("write", function(_, immediate) -- \write
|
token.luacmd("write", function(_, immediate) -- \write
|
||||||
local file = token.scan_int()
|
if immediate == "value" then return end
|
||||||
local content = token.scan_tokenlist()
|
if immediate and immediate & 0x7 ~= 0 then
|
||||||
|
immediate = immediate & 0x8
|
||||||
|
tex.error("Unexpected prefix", "You used \\write with a prefix that doesn't belong there. I will ignore it for now.")
|
||||||
|
end
|
||||||
|
local file = scan_int()
|
||||||
|
local content = scan_tokenlist()
|
||||||
local props = {file = file, data = content}
|
local props = {file = file, data = content}
|
||||||
if immediate == "immediate" then
|
if immediate == 8 then
|
||||||
do_write(props)
|
do_write(props)
|
||||||
else
|
else
|
||||||
local whatsit = node.direct.new(whatsit_id, write_whatsit)
|
local whatsit = node.direct.new(whatsit_id, write_whatsit)
|
||||||
properties[whatsit] = props
|
properties[whatsit] = props
|
||||||
node.direct.write(whatsit)
|
node.direct.write(whatsit)
|
||||||
end
|
end
|
||||||
end, "protected")
|
end, "value")
|
||||||
|
|
||||||
|
local undefined_tok = token.new(0, token.command_id'undefined_cs')
|
||||||
|
local prefix_cmd = token.command_id'prefix'
|
||||||
|
local function prefix_to_tokens(prefix)
|
||||||
|
if not prefix then return end
|
||||||
|
for i=2, 0, -1 do
|
||||||
|
if prefix & (1<<i) ~= 0 then
|
||||||
|
token.put_next(token.new(i, prefix_cmd))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local expand_after = token.primitive_tokens.expandafter
|
||||||
|
local input_tok = token.primitive_tokens.input
|
||||||
|
local endlocalcontrol = token.primitive_tokens.endlocalcontrol
|
||||||
|
local afterassignment = token.primitive_tokens.afterassignment
|
||||||
|
local lbrace = token.new(0, 1)
|
||||||
|
local rbrace = token.new(0, 2)
|
||||||
|
token.luacmd("read", function(_, prefix)
|
||||||
|
if immediate == "value" then return end
|
||||||
|
local id = scan_int()
|
||||||
|
if not scan_keyword'to' then
|
||||||
|
tex.error("Missing `to' inserted", "You should have said `\\read<number> to \\cs'.\nI'm going to look for the \\cs now.")
|
||||||
|
end
|
||||||
|
local macro = scan_csname(true)
|
||||||
|
local file = ifiles[id]
|
||||||
|
local line
|
||||||
|
if file then
|
||||||
|
line = file:reader()
|
||||||
|
if not line then
|
||||||
|
file:close()
|
||||||
|
ifiles[id] = nil
|
||||||
|
end
|
||||||
|
else
|
||||||
|
error[[FIXME: Ask the user for input]]
|
||||||
|
end
|
||||||
|
local endlocal
|
||||||
|
tex.runtoks(function()
|
||||||
|
endlocal = token.scan_next()
|
||||||
|
tex.sprint(endlocal)
|
||||||
|
tex.print(line and line ~= "" and line or " ")
|
||||||
|
tex.print(endlocal)
|
||||||
|
end)
|
||||||
|
local tokens = {}
|
||||||
|
local balance = 0
|
||||||
|
while true do
|
||||||
|
local tok = token.scan_next()
|
||||||
|
if tok == endlocal then break end
|
||||||
|
if tok.command == 1 then
|
||||||
|
balance = balance + 1
|
||||||
|
elseif tok.command == 2 then
|
||||||
|
balance = balance - 1
|
||||||
|
end
|
||||||
|
tokens[#tokens+1] = tok
|
||||||
|
end
|
||||||
|
if balance ~= 0 then error[[FIXME: Read additional input lines]] end
|
||||||
|
tex.runtoks(function()
|
||||||
|
tokens[#tokens+1] = rbrace
|
||||||
|
token.put_next(tokens)
|
||||||
|
token.put_next(token.primitive_tokens.def, token.create(macro), lbrace)
|
||||||
|
prefix_to_tokens(prefix)
|
||||||
|
end)
|
||||||
|
end, "value")
|
||||||
|
|
||||||
|
token.luacmd("readline", function(_, prefix)
|
||||||
|
if immediate == "value" then return end
|
||||||
|
local id = scan_int()
|
||||||
|
if not scan_keyword'to' then
|
||||||
|
tex.error("Missing `to' inserted", "You should have said `\\read<number> to \\cs'.\nI'm going to look for the \\cs now.")
|
||||||
|
end
|
||||||
|
local macro = scan_csname(true)
|
||||||
|
local file = ifiles[id]
|
||||||
|
local line
|
||||||
|
if file then
|
||||||
|
line = file:reader()
|
||||||
|
if not line then
|
||||||
|
file:close()
|
||||||
|
ifiles[id] = nil
|
||||||
|
end
|
||||||
|
else
|
||||||
|
error[[FIXME: Ask the user for input]]
|
||||||
|
end
|
||||||
|
line = line and line:match"^(.*[^ ])[ ]*$"
|
||||||
|
local endlinechar = tex.endlinechar
|
||||||
|
if endlinechar >= 0 and endlinechar < 0x80 then
|
||||||
|
line = (line or '') .. string.char(endlinechar)
|
||||||
|
end
|
||||||
|
set_macro(string_catcodetable, macro, line or '', prefix)
|
||||||
|
end, "value")
|
||||||
|
|
||||||
|
local integer_code, boolean_code do
|
||||||
|
local value_values = token.values'value'
|
||||||
|
for i=0,#value_values do
|
||||||
|
if value_values[i] == "integer" then
|
||||||
|
integer_code = i
|
||||||
|
elseif value_values[i] == "boolean" then
|
||||||
|
boolean_code = i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
token.luacmd("ifeof", function(_)
|
||||||
|
local id = scan_int()
|
||||||
|
return boolean_code, not ifiles[id]
|
||||||
|
end, "condition")
|
||||||
|
|
||||||
local late_lua_whatsit = new_whatsit('late_lua', function(p, pfile, n, x, y)
|
local late_lua_whatsit = new_whatsit('late_lua', function(p, pfile, n, x, y)
|
||||||
local code = p.data
|
local code = p.data
|
||||||
if not code then
|
if not code then
|
||||||
@ -116,8 +278,8 @@ local late_lua_whatsit = new_whatsit('late_lua', function(p, pfile, n, x, y)
|
|||||||
end
|
end
|
||||||
return pdf._latelua(pfile, x, y, code)
|
return pdf._latelua(pfile, x, y, code)
|
||||||
end)
|
end)
|
||||||
token.luacmd("latelua", function(_) -- \latelua
|
token.luacmd("latelua", function() -- \latelua
|
||||||
local content = token.scan_tokenlist()
|
local content = scan_tokenlist()
|
||||||
local props = {token = content}
|
local props = {token = content}
|
||||||
local whatsit = node.direct.new(whatsit_id, late_lua_whatsit)
|
local whatsit = node.direct.new(whatsit_id, late_lua_whatsit)
|
||||||
properties[whatsit] = props
|
properties[whatsit] = props
|
||||||
@ -125,35 +287,21 @@ token.luacmd("latelua", function(_) -- \latelua
|
|||||||
end, "protected")
|
end, "protected")
|
||||||
|
|
||||||
local functions = lua.get_functions_table()
|
local functions = lua.get_functions_table()
|
||||||
token.luacmd("immediate", function() -- \immediate
|
|
||||||
local next_tok = token.scan_token()
|
|
||||||
if next_tok.command ~= lua_call_cmd then
|
|
||||||
return token.put_next(next_tok)
|
|
||||||
end
|
|
||||||
local function_id = next_tok.index
|
|
||||||
return functions[function_id](function_id, 'immediate')
|
|
||||||
end, "protected")
|
|
||||||
|
|
||||||
require'luametalatex-baseregisters'
|
require'luametalatex-baseregisters'
|
||||||
require'luametalatex-back-pdf'
|
require'luametalatex-back-pdf'
|
||||||
require'luametalatex-node-luaotfload'
|
require'luametalatex-node-luaotfload'
|
||||||
|
|
||||||
local integer_code do
|
|
||||||
local value_values = token.values'value'
|
|
||||||
for i=0,#value_values do
|
|
||||||
if value_values[i] == "integer" then
|
|
||||||
integer_code = i
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
token.luacmd("Umathcodenum", function(_, scanning)
|
token.luacmd("Umathcodenum", function(_, scanning)
|
||||||
if scanning then
|
if scanning then
|
||||||
local class, family, char = tex.getmathcodes (token.scan_int())
|
local class, family, char = tex.getmathcodes (scan_int())
|
||||||
return integer_code, char | (class | family << 3) << 21
|
return integer_code, char | (class | family << 3) << 21
|
||||||
else
|
else
|
||||||
local char = token.scan_int()
|
local char = scan_int()
|
||||||
local mathcode = token.scan_int()
|
local mathcode = scan_int()
|
||||||
tex.setmathcodes(char, (mathcode >> 21) & 7, mathcode >> 24, mathcode & 0x1FFFFF)
|
tex.setmathcodes(char, (mathcode >> 21) & 7, mathcode >> 24, mathcode & 0x1FFFFF)
|
||||||
end
|
end
|
||||||
end, "force", "global", "value")
|
end, "force", "global", "value")
|
||||||
|
|
||||||
|
-- This is effectivly the last line before we hand over to normal TeX.
|
||||||
|
require'luametalatex-callbacks'.__freeze = nil
|
||||||
|
@ -2,7 +2,7 @@ font.read_tfm = require'luametalatex-font-tfm'
|
|||||||
local read_vf = require'luametalatex-font-vf'
|
local read_vf = require'luametalatex-font-vf'
|
||||||
font.read_vf = read_vf
|
font.read_vf = read_vf
|
||||||
local fontmap = require'luametalatex-pdf-font-map'.fontmap
|
local fontmap = require'luametalatex-pdf-font-map'.fontmap
|
||||||
local callback_find = callback.find
|
local callbacks = require'luametalatex-callbacks'
|
||||||
|
|
||||||
local old_font_define = font.define
|
local old_font_define = font.define
|
||||||
local old_addcharacters = font.addcharacters
|
local old_addcharacters = font.addcharacters
|
||||||
@ -78,7 +78,7 @@ function font.define(f)
|
|||||||
if f.fonts then
|
if f.fonts then
|
||||||
for i, f in next, f.fonts do
|
for i, f in next, f.fonts do
|
||||||
if not f.id then
|
if not f.id then
|
||||||
f.id = assert(callback_find'define_font'(f.name, f.size or -1000))
|
f.id = assert(callbacks.define_font(f.name, f.size or -1000))
|
||||||
elseif f.id == 0 then
|
elseif f.id == 0 then
|
||||||
f.id = id
|
f.id = id
|
||||||
end
|
end
|
||||||
@ -96,7 +96,7 @@ function font.addcharacters(fid, newdir)
|
|||||||
fonts_map = {}
|
fonts_map = {}
|
||||||
for i,f in next, newdir.fonts do
|
for i,f in next, newdir.fonts do
|
||||||
if not f.id then
|
if not f.id then
|
||||||
f.id = assert(callback_find'define_font'(f.name, f.size or -1000))
|
f.id = assert(callback.define_font(f.name, f.size or -1000))
|
||||||
elseif f.id == 0 then
|
elseif f.id == 0 then
|
||||||
f.id = fid
|
f.id = fid
|
||||||
end
|
end
|
||||||
|
@ -14,6 +14,7 @@ pdf = {
|
|||||||
}
|
}
|
||||||
require'luametalatex-font-resolve' -- Replace font.define. Must be loaded before callbacks
|
require'luametalatex-font-resolve' -- Replace font.define. Must be loaded before callbacks
|
||||||
require'luametalatex-basecallbacks'
|
require'luametalatex-basecallbacks'
|
||||||
|
local callbacks = require'luametalatex-callbacks'
|
||||||
|
|
||||||
local primitives = {}
|
local primitives = {}
|
||||||
do
|
do
|
||||||
@ -54,6 +55,7 @@ local undefined_cmd = token.command_id'undefined_cs'
|
|||||||
local lua_call_cmd = token.command_id'lua_call'
|
local lua_call_cmd = token.command_id'lua_call'
|
||||||
local lua_value_cmd = token.command_id'lua_value'
|
local lua_value_cmd = token.command_id'lua_value'
|
||||||
local lua_expandable_call_cmd = token.command_id'lua_expandable_call'
|
local lua_expandable_call_cmd = token.command_id'lua_expandable_call'
|
||||||
|
local if_test_cmd = token.command_id'if_test'
|
||||||
function token.luacmd(name, func, ...)
|
function token.luacmd(name, func, ...)
|
||||||
local idx
|
local idx
|
||||||
local tok = token.create(name)
|
local tok = token.create(name)
|
||||||
@ -64,6 +66,8 @@ function token.luacmd(name, func, ...)
|
|||||||
idx = tok.index
|
idx = tok.index
|
||||||
elseif cmd == lua_expandable_call_cmd then
|
elseif cmd == lua_expandable_call_cmd then
|
||||||
idx = tok.index
|
idx = tok.index
|
||||||
|
elseif cmd == if_test_cmd and tok.index > 48 then
|
||||||
|
idx = tok.index - 48
|
||||||
elseif ... == 'force' then
|
elseif ... == 'force' then
|
||||||
idx = new_luafunction(name)
|
idx = new_luafunction(name)
|
||||||
set_lua(name, idx, select(2, ...))
|
set_lua(name, idx, select(2, ...))
|
||||||
@ -82,7 +86,10 @@ end
|
|||||||
|
|
||||||
if initex then
|
if initex then
|
||||||
local build_bytecode = nil -- To be filled
|
local build_bytecode = nil -- To be filled
|
||||||
callback.register('pre_dump', function()
|
function callbacks.pre_dump()
|
||||||
|
local user_callback = callbacks.pre_dump
|
||||||
|
if user_callback then user_callback() end
|
||||||
|
|
||||||
local prepared = lua.prepared_code
|
local prepared = lua.prepared_code
|
||||||
prepared[1] = string.format("fixupluafunctions(%i)", predefined_luafunctions)
|
prepared[1] = string.format("fixupluafunctions(%i)", predefined_luafunctions)
|
||||||
for i=0,0 do -- maybeFIXME: In practise only one language is preloaded in LuaTeX anyway
|
for i=0,0 do -- maybeFIXME: In practise only one language is preloaded in LuaTeX anyway
|
||||||
@ -121,7 +128,8 @@ if initex then
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
lua.bytecode[tex.count[262]+1] = build_bytecode(table.concat(prepared, '\n'))
|
lua.bytecode[tex.count[262]+1] = build_bytecode(table.concat(prepared, '\n'))
|
||||||
end)
|
end
|
||||||
|
callbacks.__freeze('pre_dump', true)
|
||||||
return function(f)
|
return function(f)
|
||||||
build_bytecode = f
|
build_bytecode = f
|
||||||
return require'luametalatex-firstcode'
|
return require'luametalatex-firstcode'
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
\directlua{unhook_expl()}
|
\directlua{unhook_expl()}
|
||||||
% See baseregisters for list of toks pdfvariables
|
% See baseregisters for list of toks pdfvariables
|
||||||
\directlua{initialize_pdf_toks()}
|
\directlua{initialize_pdf_toks()}
|
||||||
|
% We hardcode the ids of two catcodetables. If they ever change in the format, abort.
|
||||||
|
\if 0\ifnum1=\catcodetable@initex\else\expandafter1\fi\ifnum2=\catcodetable@string\else\expandafter1\fi 0\else
|
||||||
|
\errmessage{Inconsistent catcodetable identifiers}
|
||||||
|
\fi
|
||||||
\ifx\@tfor\undefined
|
\ifx\@tfor\undefined
|
||||||
\def\@tfor#1\do#2{}
|
\def\@tfor#1\do#2{}
|
||||||
\fi
|
\fi
|
||||||
|
@ -24,10 +24,10 @@
|
|||||||
\noexpand\luametalatex@@everyjobandnow{\noexpand\directlua{!
|
\noexpand\luametalatex@@everyjobandnow{\noexpand\directlua{!
|
||||||
lua.get_functions_table()[\the\luametalatex@@expandglyphsinfont] = function()
|
lua.get_functions_table()[\the\luametalatex@@expandglyphsinfont] = function()
|
||||||
token.put_next(token.create'fontid')
|
token.put_next(token.create'fontid')
|
||||||
local font = token.scan_int()
|
local font = token.scan_integer()
|
||||||
local stretch = token.scan_int()
|
local stretch = token.scan_integer()
|
||||||
local shrink = token.scan_int()
|
local shrink = token.scan_integer()
|
||||||
local step = token.scan_int()
|
local step = token.scan_integer()
|
||||||
token.set_macro('pickup@font@@hook@luametalatex@microtype@' .. font, string.format("{}{%i}{%i}{%i}", stretch, shrink, step), "global")
|
token.set_macro('pickup@font@@hook@luametalatex@microtype@' .. font, string.format("{}{%i}{%i}{%i}", stretch, shrink, step), "global")
|
||||||
end
|
end
|
||||||
}}
|
}}
|
||||||
|
@ -10,6 +10,7 @@ local assigned = {}
|
|||||||
local delayed = {}
|
local delayed = {}
|
||||||
local compress = xzip.compress
|
local compress = xzip.compress
|
||||||
local pdfvariable = pdf.variable
|
local pdfvariable = pdf.variable
|
||||||
|
local digest = sha2.digest256
|
||||||
-- slightly tricky interface: No/nil return means that the objects content
|
-- slightly tricky interface: No/nil return means that the objects content
|
||||||
-- isn't known yet, while false indicates a delayed object.
|
-- isn't known yet, while false indicates a delayed object.
|
||||||
local function written(pdf, num)
|
local function written(pdf, num)
|
||||||
|
Loading…
Reference in New Issue
Block a user