Created
July 7, 2020 23:23
-
-
Save xziyue/bee7635d3612cfe92cb5a62ff419cbb2 to your computer and use it in GitHub Desktop.
Mimicking file system input in LuaTeX
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
\RequirePackage{luacode, luatexbase} | |
\begin{luacode*} | |
TeXFileBuffer = {content={}, finished=false} | |
function TeXFileBuffer:new() | |
o = {} | |
setmetatable(o, self) | |
self.__index = self | |
return o | |
end | |
function TeXFileBuffer:clear() | |
while #self.content ~= 0 do rawset(self.content, #self.content, nil) end | |
end | |
function TeXFileBuffer:content_to_string() | |
return table.concat(self.content, "") | |
end | |
function TeXFileBuffer:use() | |
tex.write(self:content_to_string()) | |
end | |
function TeXFileBuffer:append(data) | |
table.insert(self.content, data) | |
end | |
function TeXFileBuffer:append_carriage_return(data) | |
self:append("\r") | |
end | |
function _tex_buffer_remove_callback(name, description) | |
for k, v in pairs(luatexbase.callback_descriptions(name)) do | |
if v == description then | |
texio.write("\nsafely removing callback " .. name .. " : " .. description) | |
luatexbase.remove_from_callback(name, description) | |
end | |
end | |
end | |
function tex_buffer_remove_callback() | |
_tex_buffer_remove_callback("find_read_file", "tex_file_buffer_find") | |
_tex_buffer_remove_callback("open_read_file", "tex_file_buffer_read") | |
end | |
function tex_file_buffer_reader(env) | |
local ret = nil | |
if not env["finished"] then | |
ret = env["content"] | |
env["finished"] = true | |
-- remove callback immediately | |
tex_buffer_remove_callback() | |
end | |
return ret | |
end | |
function tex_file_buffer_find(id_number, asked_name) | |
-- arguments and return value doesn't matter | |
texio.write("\nTeXFileBuffer tries to find ".. asked_name .. " id=" .. id_number) | |
return asked_name | |
end | |
function TeXFileBuffer:register_callback() | |
tex_file_buffer_read = function (filename) | |
local env = {} | |
texio.write("\nTeXFileBuffer opens ".. filename) | |
env["finished"] = false | |
env["content"] = self:content_to_string() | |
env["reader"] = tex_file_buffer_reader | |
return env | |
end | |
-- register callback | |
luatexbase.add_to_callback("find_read_file", tex_file_buffer_find, "tex_file_buffer_find") | |
luatexbase.add_to_callback("open_read_file", tex_file_buffer_read, "tex_file_buffer_read") | |
end | |
-- create a TeXFilebuffer instance | |
tex_file_buffer = TeXFileBuffer:new() | |
\end{luacode*} | |
\makeatletter | |
\newcommand{\TFBInputAsFile}{ | |
\directlua{tex_file_buffer:register_callback()} | |
% read some random file, which automatically removes the callback | |
% \input will do an file existance check before actually reading it. | |
% therefore, if using LaTeX's input, `random-file` will be opned twice | |
% here, I am using TeX's \@@input primitive instead | |
\@@input randomfile | |
} | |
\makeatother | |
\newcommand{\TFBAppend}[1]{ | |
\directlua{tex_file_buffer:append("\luaescapestring{\unexpanded{#1}}")} | |
} | |
\newcommand{\TFBAppendCR}{ | |
\directlua{tex_file_buffer:append_carriage_return()} | |
} | |
\newcommand{\TFBClear}{ | |
\directlua{tex_file_buffer:clear()} | |
} | |
\newcommand{\TFBUse}{ | |
\directlua{tex_file_buffer:use()} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Using something like the following, inspired and modified from this question:
Should allow you to get rid of the need for adding/removing the callbacks all the time.
make_vfs_file()
takes a string and returns anenv
withenv["content"]
andenv["reader"]
, whereas the content is captured this way inenv
. The reader is generic, taking theenv
in as its first argument, checking ifenv.content
is nil and returning its value if it isn't. Then it setsenv.content=nil
to make sure that it doesn't return it a second time around.Still not very robust, depending on the packages you use (because of what
\directlua
does under the hood), but this should allow you to use "virtual" input with:PS: Haven't tested the code. Rather typed it here into GitHub (twice, because my browser had a hiccup).