summaryrefslogtreecommitdiff
path: root/macros/luatex/latex/pyluatex/pyluatex.lua
diff options
context:
space:
mode:
Diffstat (limited to 'macros/luatex/latex/pyluatex/pyluatex.lua')
-rw-r--r--macros/luatex/latex/pyluatex/pyluatex.lua140
1 files changed, 49 insertions, 91 deletions
diff --git a/macros/luatex/latex/pyluatex/pyluatex.lua b/macros/luatex/latex/pyluatex/pyluatex.lua
index c12faa5cc8..7ec06f8ea6 100644
--- a/macros/luatex/latex/pyluatex/pyluatex.lua
+++ b/macros/luatex/latex/pyluatex/pyluatex.lua
@@ -1,7 +1,7 @@
--[[
MIT License
-Copyright (c) 2021-2023 Tobias Enderle
+Copyright (c) 2021-2024 Tobias Enderle
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@@ -22,7 +22,7 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
--]]
-require("lualibs-util-jsn")
+require("lualibs")
local socket = require("socket")
pyluatex = pyluatex or {
@@ -31,8 +31,6 @@ pyluatex = pyluatex or {
session = "default"
}
-local dir_sep = package.config:sub(1,1)
-
-- status.filename: path to pyluatex.sty
local folder = file.pathpart(file.collapsepath(status.filename, true))
local tcp = nil
@@ -40,15 +38,13 @@ local tcp = nil
local env_end = nil
local env_lines = nil
local parent_env = nil
-local env_repl_mode = false
-local env_success = true
local last_code = nil
local last_output = nil
local function get_tex_file_folder()
- for k, v in ipairs(arg) do
- if not v:find("^%-") then
+ for _, v in ipairs(arg) do
+ if v:sub(1, 1) ~= "-" then
local path = file.collapsepath(v, true)
if lfs.isfile(path) then
return file.pathpart(path)
@@ -63,27 +59,26 @@ local function get_tex_file_folder()
return nil
end
-local function trim(s)
- return (s:gsub("^%s*(.-)%s*$", "%1"))
+local function show_err(message)
+ tex.sprint("\\PackageError{PyLuaTeX}{" .. message .. "}{}")
end
-local function err_cmd(message)
- return "\\PackageError{PyLuaTeX}{" .. message .. "}{}"
+local function not_empty(str)
+ return str ~= nil and str ~= ""
end
function pyluatex.start(executable, local_imports)
local script = file.join(folder, "pyluatex-interpreter.py")
- local is_windows = dir_sep ~= "/"
local cmd = ""
if local_imports then
local tex_file_folder = get_tex_file_folder()
if tex_file_folder ~= nil then
- cmd = " \"" .. tex_file_folder .. "\""
+ cmd = ' "' .. tex_file_folder .. '"'
end
end
- cmd = executable .. " \"" .. script .. "\"" .. cmd
- if is_windows then
+ cmd = executable .. ' "' .. script .. '"' .. cmd
+ if os.type == "windows" then
cmd = "start /B " .. cmd
else
cmd = cmd .. " &"
@@ -92,15 +87,15 @@ function pyluatex.start(executable, local_imports)
local port = f:read("*l")
f:close()
- function err(message)
- tex.sprint(err_cmd("Python backend could not be started (" .. message .. ")"))
+ local function err(message)
+ show_err("Python backend could not be started (" .. message .. ")")
end
if port == nil then
err("executable: " .. executable)
return
end
- port = trim(port)
+ port = port:fullstrip()
if port:match("^%d+$") == nil then
err("invalid TCP port: " .. port)
return
@@ -121,26 +116,6 @@ local function request(data)
return utilities.json.tolua(output)
end
-local function log_input(code)
- texio.write_nl("PyLuaTeX input for session \"" .. pyluatex.session .. "\": " .. code)
-end
-
-local function log_output(code)
- texio.write_nl("PyLuaTeX output: " .. code)
-end
-
-local function split_lines(str)
- if str:sub(-1) ~= "\n" then
- str = str .. "\n"
- end
-
- local t = {}
- for s in str:gmatch("(.-)\r?\n") do
- table.insert(t, s)
- end
- return t
-end
-
function pyluatex.execute(code, auto_print, write, repl_mode, store)
local full_code
if auto_print then
@@ -149,77 +124,62 @@ function pyluatex.execute(code, auto_print, write, repl_mode, store)
full_code = code
end
- if pyluatex.verbose then log_input(full_code) end
-
- local resp = request(
- {
- session = pyluatex.session,
- code = full_code,
- repl_mode = repl_mode,
- ignore_errors = pyluatex.ignore_errors
- }
- )
- local output_lines = split_lines(resp.output)
+ local resp = request({
+ session = pyluatex.session,
+ code = full_code,
+ repl_mode = repl_mode,
+ ignore_errors = pyluatex.ignore_errors
+ })
+ local code_lines = code:splitlines()
+ local output_lines = resp.output:splitlines()
if store then
- last_code = split_lines(code)
+ last_code = code_lines
last_output = output_lines
end
- if resp.success or pyluatex.ignore_errors then
- if pyluatex.verbose or not resp.success then log_output(resp.output) end
+ if pyluatex.verbose or not resp.success then
+ texio.write_nl('PyLuaTeX input for session "' .. pyluatex.session ..
+ '": ' .. full_code)
+ texio.write_nl("PyLuaTeX output: " .. resp.output)
+ end
- if write then
- tex.print(output_lines)
- end
+ if resp.success or pyluatex.ignore_errors then
+ if write then tex.print(output_lines) end
else
- if not pyluatex.verbose then log_input(full_code) end
- log_output(resp.output)
- if write then
- tex.sprint(err_cmd("Python error (see above)"))
- end
+ show_err("Python error (see above)")
end
- if resp.log_msg ~= "" then texio.write(resp.log_msg) end
-
- return resp.success
+ if not_empty(resp.log_msg) then texio.write(resp.log_msg) end
end
-function pyluatex.print_env()
- if last_output ~= nil and (env_success or pyluatex.ignore_errors) then
- tex.print(last_output)
- end
+function pyluatex.execute_env(write, repl_mode)
+ local code = table.concat(env_lines, "\n")
+ pyluatex.execute(code, false, write, repl_mode, true)
end
local function record_line(line)
- local s, e = line:find(env_end, 1, true)
+ local s = line:find(env_end)
if s ~= nil then
luatexbase.remove_from_callback("process_input_buffer", "pyluatex_record_line")
- local code_in_line = line:sub(1, s - 1)
- if trim(code_in_line):len() > 0 then
+ local code = line:sub(1, s - 1)
+ if code:strip():len() > 0 then
-- only include this line if it contains non-whitespace characters
- table.insert(env_lines, code_in_line)
- end
- local code = table.concat(env_lines, "\n")
- env_success = pyluatex.execute(code, false, false, env_repl_mode, true)
- if env_success or pyluatex.ignore_errors then
- return line:sub(s)
- else
- return env_end .. err_cmd("Python error (see above)") .. line:sub(e + 1)
+ table.insert(env_lines, code)
end
+ return line:sub(s)
else
table.insert(env_lines, line)
return ""
end
end
-function pyluatex.record_env(name, repl_mode)
+function pyluatex.record_env(name)
if parent_env ~= nil then
name = parent_env
parent_env = nil
end
- env_end = "\\end{" .. name .. "}"
+ env_end = "\\end%s*{" .. name:escapedpattern() .. "}"
env_lines = {}
- env_repl_mode = repl_mode
luatexbase.add_to_callback("process_input_buffer", record_line, "pyluatex_record_line")
end
@@ -236,13 +196,13 @@ function pyluatex.run_file(path, write, repl_mode)
f:close()
-- ignore trailing new line if present
if code:sub(-2) == "\r\n" then
- code = code:sub(0, -3)
+ code = code:sub(1, -3)
elseif code:sub(-1) == "\n" then
- code = code:sub(0, -2)
+ code = code:sub(1, -2)
end
pyluatex.execute(code, false, write, repl_mode, true)
else
- tex.sprint(err_cmd("File not found: " .. path))
+ show_err("File not found: " .. path)
end
end
@@ -255,26 +215,24 @@ function pyluatex.get_last_output()
end
local function parse_bool(name, value)
+ value = value:fullstrip()
if value == "true" then
return true
elseif value == "false" then
return false
else
- tex.sprint(
- err_cmd("Invalid value '" .. value .. "' for option " .. name)
- )
+ show_err('Invalid value "' .. value .. '" for option "' .. name .. '"')
end
end
function pyluatex.set_option(name, value)
- name = trim(name)
- value = trim(value)
+ name = name:fullstrip()
if name == "ignoreerrors" then
pyluatex.ignore_errors = parse_bool(name, value)
elseif name == "verbose" then
pyluatex.verbose = parse_bool(name, value)
else
- tex.sprint(err_cmd("Unknown option '" .. name .. "'"))
+ show_err('Unknown option "' .. name .. '"')
end
end