理由:我的目标是创建一个系统,通过 Lua 假装正在读取某个文件,但实际上内容来自其他地方。其他地方有一个概念叫做 VFS(虚拟文件系统),这是我借用的名字。
考虑以下 MWE(我知道它有缺陷):
% !TeX encoding = UTF-8
% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{luacode}
\begin{luacode*}
do
-- Table which contains "reader" functions for the virtual "files" given as keys
vfs = { ["ZaphodBeeblebrox"] = function() return nil end }
local function luatexbase_log(text, ...)
texio.write_nl("log", string.format(text, ...))
end
local function get_vfs_realname(name)
local pfx = "virtual." -- virtual "file" prefix
if name:find(pfx, 1, true) == 1 then
local lookup_name = name:sub(#pfx + 1, #name)
if vfs[lookup_name] ~= nil and type(vfs[lookup_name]) == "function" then
return lookup_name
end
end
return nil -- not found
end
local function hook_find_read_file(id, name)
kpse_name = kpse.find_file(name)
if kpse_name then
return kpse_name
end
local rname = get_vfs_realname(name)
if rname then
luatexbase_log([[Found VFS \input lookup: %s (id=%d)]], rname, id)
return name
end
end
local function emulate_default_open_read_file(name)
return {
["fhandle"] = assert(io.open(name,"r")),
["reader"] = function(self)
return self.fhandle:read("*l")
end,
["close"] = function(self)
self.fhandle:close()
end,
}
end
local function hook_open_read_file(name)
kpse_name = kpse.find_file(name)
if kpse_name then
return emulate_default_open_read_file(kpse_name)
end
local rname = get_vfs_realname(name)
if rname then
return { ["reader"] = vfs[rname] }
end
end
luatexbase.add_to_callback("find_read_file", hook_find_read_file, "vfs")
luatexbase.add_to_callback("open_read_file", hook_open_read_file, "vfs")
end
\end{luacode*}
\begin{document}
\input{virtual.ZaphodBeeblebrox}
bla
\end{document}
据我所知,代码运行完美。但是,有一点我不喜欢:emulate_default_open_read_file()
。
我完全编造了该函数,试图猜测 LuaLaTeX 默认做什么。
问题
- 除了我自己认为 LuaLaTeX 在“open_read_file”上默认执行的操作之外,有没有办法可以访问默认行为?这里的目标是在行为上与默认行为 100% 相同,除了处理我自己的虚拟“文件”时。
- 假设上面有这样的方法,我该如何通过默认函数检测失败并启动我的回退?或者这里唯一的方法是切换顺序,检测之前的虚拟“文件”,然后失败并恢复到默认值?
注意:我知道当前"ZaphodBeeblebrox"
reader
函数存在缺陷。它应该逐行返回数据并以 结尾以nil
表示文件结束。但我在充实这个函数之前遇到了困难。所以请耐心等待。
PS:我擅自重写了luatexbase_log
以直接texdoc ltluatex
使用该string.format()
功能,这样可以节省一些输入。 PPS:我尝试这样做是为了避免必须临时写入磁盘,并避免在使用\directlua
或\luadirect
到tex.print()
一堆 LaTeX+TikZ 代码时遇到的奇怪行为。可能与扩展有关。但将 Lua 代码的输出(手动)写入磁盘,然后在写入的文件上使用\input
,碰巧有效。这就是我在这里试图模拟的。