summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/scripts
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2024-01-12 21:45:17 +0000
committerKarl Berry <karl@freefriends.org>2024-01-12 21:45:17 +0000
commit92923b59b9d97aed633e13ae96acde1946ee7af5 (patch)
tree2555be7ab687a7b516f6d2dd1036160ee70553fe /Master/texmf-dist/scripts
parent8aeda3e1019bc7b0493c228b2c9487b0f3636964 (diff)
lua-placeholders (12jan24)
git-svn-id: svn://tug.org/texlive/trunk@69404 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/scripts')
-rw-r--r--Master/texmf-dist/scripts/lua-placeholders/lua-placeholders-common.lua35
-rw-r--r--Master/texmf-dist/scripts/lua-placeholders/lua-placeholders-namespace.lua94
-rw-r--r--Master/texmf-dist/scripts/lua-placeholders/lua-placeholders-parser.lua88
-rw-r--r--Master/texmf-dist/scripts/lua-placeholders/lua-placeholders-types.lua273
-rw-r--r--Master/texmf-dist/scripts/lua-placeholders/lua-placeholders.lua217
5 files changed, 707 insertions, 0 deletions
diff --git a/Master/texmf-dist/scripts/lua-placeholders/lua-placeholders-common.lua b/Master/texmf-dist/scripts/lua-placeholders/lua-placeholders-common.lua
new file mode 100644
index 00000000000..e68a5484e84
--- /dev/null
+++ b/Master/texmf-dist/scripts/lua-placeholders/lua-placeholders-common.lua
@@ -0,0 +1,35 @@
+-- lua-placeholders-common.lua
+-- Copyright 2024 E. Nijenhuis
+--
+-- This work may be distributed and/or modified under the
+-- conditions of the LaTeX Project Public License, either version 1.3c
+-- of this license or (at your option) any later version.
+-- The latest version of this license is in
+-- http://www.latex-project.org/lppl.txt
+-- and version 1.3c or later is part of all distributions of LaTeX
+-- version 2005/12/01 or later.
+--
+-- This work has the LPPL maintenance status ‘maintained’.
+--
+-- The Current Maintainer of this work is E. Nijenhuis.
+--
+-- This work consists of the files lua-placeholders.sty
+-- lua-placeholders-manual.pdf lua-placeholders.lua
+-- lua-placeholders-common.lua lua-placeholders-namespace.lua
+-- lua-placeholders-parser.lua and lua-placeholders-types.lua
+
+function table.copy(t)
+ local u = { }
+ for k, v in pairs(t) do
+ u[k] = v
+ end
+ return setmetatable(u, getmetatable(t))
+end
+
+lua_placeholders_toks = {
+ new_bool = token.create('provideboolean'),
+ set_bool = token.create('setboolean'),
+ list_conj = token.create('paramlistconjunction'),
+ placeholder_format = token.create('paramplaceholder'),
+ unknown_format = token.create('paramnotfound')
+}
diff --git a/Master/texmf-dist/scripts/lua-placeholders/lua-placeholders-namespace.lua b/Master/texmf-dist/scripts/lua-placeholders/lua-placeholders-namespace.lua
new file mode 100644
index 00000000000..fb84447a251
--- /dev/null
+++ b/Master/texmf-dist/scripts/lua-placeholders/lua-placeholders-namespace.lua
@@ -0,0 +1,94 @@
+-- lua-placeholders-namespace.lua
+-- Copyright 2024 E. Nijenhuis
+--
+-- This work may be distributed and/or modified under the
+-- conditions of the LaTeX Project Public License, either version 1.3c
+-- of this license or (at your option) any later version.
+-- The latest version of this license is in
+-- http://www.latex-project.org/lppl.txt
+-- and version 1.3c or later is part of all distributions of LaTeX
+-- version 2005/12/01 or later.
+--
+-- This work has the LPPL maintenance status ‘maintained’.
+--
+-- The Current Maintainer of this work is E. Nijenhuis.
+--
+-- This work consists of the files lua-placeholders.sty
+-- lua-placeholders-manual.pdf lua-placeholders.lua
+-- lua-placeholders-common.lua lua-placeholders-namespace.lua
+-- lua-placeholders-parser.lua and lua-placeholders-types.lua
+
+require('lua-placeholders-types')
+
+local namespace = {
+ strict = false,
+ recipe_file = nil,
+ recipe_loaded = false,
+ payload_file = nil,
+ payload_loaded = false
+}
+
+function namespace.parse_filename(path)
+ local abs_path = kpse.find_file(path)
+ local _, _, name = abs_path:find('/?%w*/*(%w+)%.%w+')
+ return name, abs_path
+end
+
+function namespace:new(_o)
+ local o = {
+ recipe_file = _o.recipe_file,
+ payload_file = _o.payload_file,
+ strict = _o.strict,
+ values = {}
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+end
+
+function namespace:load_recipe(params)
+ for key, opts in pairs(params) do
+ local param = base_param.define(key, opts)
+ if param then
+ self.values[key] = param
+ end
+ end
+ self.recipe_loaded = true
+end
+
+function namespace:load_payload(values)
+ if self.recipe_loaded then
+ if values then
+ for key, value in pairs(values) do
+ if self.values[key] then
+ local param = self.values[key]
+ param:load(key, value)
+ else
+ texio.write_nl('Warning: passed an unknown key ' .. key)
+ end
+ texio.write_nl('Key' .. key)
+ end
+ else
+ texio.write_nl('Warning: Payload file was empty')
+ end
+ self.payload_loaded = true
+ end
+end
+
+function namespace:param(key)
+ if not self.recipe_loaded then
+ tex.error('Error: Recipe was not loaded yet...')
+ return nil
+ end
+ if not self.payload_loaded then
+ if self.strict then
+ tex.error('Error: Payload was not loaded yet...')
+ return nil
+ else
+ texio.write_nl('Warning: Payload was not loaded yet...')
+ end
+ end
+ return self.values[key]
+end
+
+return namespace
diff --git a/Master/texmf-dist/scripts/lua-placeholders/lua-placeholders-parser.lua b/Master/texmf-dist/scripts/lua-placeholders/lua-placeholders-parser.lua
new file mode 100644
index 00000000000..1fa43227a48
--- /dev/null
+++ b/Master/texmf-dist/scripts/lua-placeholders/lua-placeholders-parser.lua
@@ -0,0 +1,88 @@
+-- lua-placeholders-parser.lua
+-- Copyright 2024 E. Nijenhuis
+--
+-- This work may be distributed and/or modified under the
+-- conditions of the LaTeX Project Public License, either version 1.3c
+-- of this license or (at your option) any later version.
+-- The latest version of this license is in
+-- http://www.latex-project.org/lppl.txt
+-- and version 1.3c or later is part of all distributions of LaTeX
+-- version 2005/12/01 or later.
+--
+-- This work has the LPPL maintenance status ‘maintained’.
+--
+-- The Current Maintainer of this work is E. Nijenhuis.
+--
+-- This work consists of the files lua-placeholders.sty
+-- lua-placeholders-manual.pdf lua-placeholders.lua
+-- lua-placeholders-common.lua lua-placeholders-namespace.lua
+-- lua-placeholders-parser.lua and lua-placeholders-types.lua
+
+local LUA_VERSION = string.sub(_VERSION, 5, -1)
+
+yaml_supported = false
+
+-- Check if LUA_PATH is set
+local current_path = os.getenv('LUA_PATH')
+if current_path then
+ texio.write_nl('Info: LUA path setup up correctly. Great job!')
+else
+ -- Set the LUA_PATH and LUA_CPATH using 'luarocks -lua-version <LuaLaTeX version> path'
+ texio.write_nl('Warning: No LUA_PATH set. Looking for LuaRocks installation...')
+ local handle = io.popen('luarocks --lua-version ' .. LUA_VERSION .. ' path')
+ if handle then
+ local buffer = handle:read('*a')
+ if handle:close() then
+ texio.write_nl('Info: luarocks command executed successfully')
+ local lua_path, lua_search_count = string.gsub(buffer, ".*LUA_PATH='([^']*)'.*", "%1")
+ local lua_cpath, clua_search_count = string.gsub(buffer, ".*LUA_CPATH='([^']*)'.*", "%1")
+ if lua_search_count > 0 then
+ texio.write_nl('Info: Setting LUA_PATH from LuaRocks', lua_path)
+ package.path = lua_path
+ end
+ if clua_search_count > 0 then
+ texio.write_nl('Info: Setting LUA_CPATH from LuaRocks', lua_cpath)
+ package.cpath = lua_cpath
+ end
+ else
+ texio.write_nl('Error: couldn\'t find LuaRocks installation')
+ texio.write_nl("Info: LUA PATH:\n\t" .. string.gsub(package.path, ';', '\n\t') .. '\n\n')
+ end
+ else
+ tex.error('Error: could not open a shell. Is shell-escape turned on?')
+ end
+end
+texio.write_nl('\n')
+
+-- For falling back to JSON
+require('lualibs')
+
+-- Require YAML configuration files
+-- Make sure to have the apt package lua-yaml installed
+local status, yaml = pcall(require, 'lyaml')
+if status then
+ yaml_supported = true
+else
+ texio.write_nl('Warning: No YAML support.')
+ texio.write_nl(yaml)
+ texio.write_nl('Info: Falling back to JSON.')
+end
+
+return function(filename)
+ local _, _, ext = string.match(filename, "(.-)([^\\]-([^\\%.]+))$")
+ local file = io.open(filename, "rb")
+ if not file then
+ error('File ' .. filename .. ' doesn\'t exist...')
+ end
+ local raw = file:read "*a"
+ file:close()
+ if ext == 'json' then
+ return utilities.json.tolua(raw)
+ else
+ if yaml_supported then
+ return yaml.load(raw)
+ else
+ tex.error('Error: no YAML support!')
+ end
+ end
+end
diff --git a/Master/texmf-dist/scripts/lua-placeholders/lua-placeholders-types.lua b/Master/texmf-dist/scripts/lua-placeholders/lua-placeholders-types.lua
new file mode 100644
index 00000000000..faa637c8f78
--- /dev/null
+++ b/Master/texmf-dist/scripts/lua-placeholders/lua-placeholders-types.lua
@@ -0,0 +1,273 @@
+-- lua-placeholders-types.lua
+-- Copyright 2024 E. Nijenhuis
+--
+-- This work may be distributed and/or modified under the
+-- conditions of the LaTeX Project Public License, either version 1.3c
+-- of this license or (at your option) any later version.
+-- The latest version of this license is in
+-- http://www.latex-project.org/lppl.txt
+-- and version 1.3c or later is part of all distributions of LaTeX
+-- version 2005/12/01 or later.
+--
+-- This work has the LPPL maintenance status ‘maintained’.
+--
+-- The Current Maintainer of this work is E. Nijenhuis.
+--
+-- This work consists of the files lua-placeholders.sty
+-- lua-placeholders-manual.pdf lua-placeholders.lua
+-- lua-placeholders-common.lua lua-placeholders-namespace.lua
+-- lua-placeholders-parser.lua and lua-placeholders-types.lua
+
+require('lua-placeholders-common')
+
+function table.copy(t)
+ local u = { }
+ for k, v in pairs(t) do
+ u[k] = v
+ end
+ return setmetatable(u, getmetatable(t))
+end
+
+base_param = {}
+function base_param:new(o)
+ o = o or {}
+ setmetatable(o, self)
+ self.__index = self
+ return o
+end
+
+function base_param:is_set()
+ return self and ((self.values or self.fields or self.value) ~= nil)
+end
+
+function base_param:val()
+ return self.value or self.values or self.default
+end
+
+function base_param:to_upper()
+ local val = self:val()
+ if type(val) == 'string' then
+ return val:upper()
+ elseif type(self.placeholder) == 'string' then
+ return '[' .. self.placeholder:upper() .. ']'
+ end
+end
+
+function base_param:print_val()
+ local value = self:val()
+ if value ~= nil then
+ tex.write(value)
+ else
+ tex.sprint(lua_placeholders_toks.placeholder_format, '{', self.placeholder or self.key, '}')
+ end
+end
+
+bool_param = base_param:new{
+ type = 'bool'
+}
+
+function bool_param:new(key, _o)
+ local o = {
+ key = key,
+ default = _o.default
+ }
+ setmetatable(o, self)
+ self.__index = self
+ tex.sprint(lua_placeholders_toks.new_bool, '{', o.key, '}')
+ return o
+end
+
+function bool_param:val()
+ local value
+ if self.value ~= nil then
+ value = tostring(self.value)
+ elseif self.default ~= nil then
+ value = tostring(self.default)
+ else
+ value = 'false'
+ end
+ return value
+end
+
+function bool_param:set_bool(key)
+ tex.sprint(lua_placeholders_toks.set_bool, '{', key, '}{', self:val(), '}')
+end
+
+str_param = base_param:new{
+ type = 'string'
+}
+
+function str_param:new(key, _o)
+ local o = {
+ key = key,
+ placeholder = _o.placeholder
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+end
+
+number_param = base_param:new{
+ type = 'number'
+}
+
+function number_param:new(key, _o)
+ local o = {
+ key = key,
+ placeholder = _o.placeholder,
+ default = _o.default
+ }
+ setmetatable(o, self)
+ self.__index = self
+ return o
+end
+
+function number_param:val()
+ if self.value or self.default then
+ return tex.number(self.value or self.default)
+ end
+end
+
+function number_param:print_num()
+ local val = self:val()
+ if val then
+ tex.print('\\numprint{' .. val .. '}')
+ else
+ tex.sprint(lua_placeholders_toks.placeholder_format, '{', self.placeholder or self.key, '}')
+ end
+end
+
+list_param = base_param:new{
+ type = 'list'
+}
+
+function list_param:new(key, _o)
+ local o = {
+ key = key,
+ item_type = base_param.define('list_item', { type = (_o["item type"] or 'string') }),
+ default = {}
+ }
+ if _o.default then
+ for _, default_val in ipairs(_o.default) do
+ local v = table.copy(o.item_type)
+ v:load('list_item', default_val)
+ table.insert(o.default, v)
+ end
+ end
+ setmetatable(o, self)
+ self.__index = self
+ return o
+end
+
+function list_param:val()
+ return self.values or self.default or {}
+end
+
+function list_param:print_val()
+ local list = self:val()
+ if #list > 0 then
+ if not self.values then
+ tex.sprint(lua_placeholders_toks.placeholder_format, '{')
+ end
+ tex.sprint(list[1]:val())
+ for i = 2, #list do
+ tex.sprint(lua_placeholders_toks.list_conj, list[i]:val())
+ end
+ if not self.values then
+ tex.sprint('}')
+ end
+ end
+end
+
+object_param = base_param:new{
+ type = 'object'
+}
+
+function object_param:new(key, _o)
+ local o = {
+ key = key,
+ fields = {},
+ default = _o.default
+ }
+ for _key, field in pairs(_o.fields) do
+ o.fields[_key] = base_param.define(_key, field)
+ end
+ setmetatable(o, self)
+ self.__index = self
+ return o
+end
+
+table_param = base_param:new{
+ type = 'table'
+}
+
+function table_param:new(key, _o)
+ local o = {
+ key = key,
+ columns = {}
+ }
+ for col_key, col in pairs(_o.columns) do
+ o.columns[col_key] = base_param.define(col_key, col)
+ end
+ setmetatable(o, self)
+ self.__index = self
+ return o
+end
+
+function base_param.define(key, o)
+ if o.type then
+ if o.type == 'bool' then
+ return bool_param:new(key, o)
+ elseif o.type == 'string' then
+ return str_param:new(key, o)
+ elseif o.type == 'number' then
+ return number_param:new(key, o)
+ elseif o.type == 'list' then
+ return list_param:new(key, o)
+ elseif o.type == 'object' then
+ return object_param:new(key, o)
+ elseif o.type == 'table' then
+ return table_param:new(key, o)
+ else
+ texio.write_nl('Warning: no such parameter type ' .. o.type)
+ end
+ else
+ error('ERROR: parameter must have a "type" field')
+ end
+end
+
+function base_param:load(key, value)
+ if self.type == 'list' then
+ self.values = {}
+ for _, val in ipairs(value) do
+ local param = table.copy(self.item_type)
+ param:load('list-item', val)
+ table.insert(self.values, param)
+ end
+ elseif self.type == 'table' then
+ self.values = {}
+ for _, row_vals in ipairs(value) do
+ local row = {}
+ for col_key, col in pairs(self.columns) do
+ local cell = table.copy(col)
+ cell:load(col.key, row_vals[col_key])
+ row[col_key] = cell
+ end
+ table.insert(self.values, row)
+ end
+ elseif self.type == 'object' then
+ for field_key, field in pairs(self.fields) do
+ local field_val = value[field_key]
+ if field_val then
+ field:load(field_key, field_val)
+ else
+ texio.write_nl('Warning: Passed unknown field to object', field_key)
+ end
+ end
+ else
+ self.value = value
+ end
+ if self.type == 'bool' then
+ self:set_bool(key)
+ end
+end
diff --git a/Master/texmf-dist/scripts/lua-placeholders/lua-placeholders.lua b/Master/texmf-dist/scripts/lua-placeholders/lua-placeholders.lua
new file mode 100644
index 00000000000..255b4d1f26a
--- /dev/null
+++ b/Master/texmf-dist/scripts/lua-placeholders/lua-placeholders.lua
@@ -0,0 +1,217 @@
+-- lua-placeholders.lua
+-- Copyright 2024 E. Nijenhuis
+--
+-- This work may be distributed and/or modified under the
+-- conditions of the LaTeX Project Public License, either version 1.3c
+-- of this license or (at your option) any later version.
+-- The latest version of this license is in
+-- http://www.latex-project.org/lppl.txt
+-- and version 1.3c or later is part of all distributions of LaTeX
+-- version 2005/12/01 or later.
+--
+-- This work has the LPPL maintenance status ‘maintained’.
+--
+-- The Current Maintainer of this work is E. Nijenhuis.
+--
+-- This work consists of the files lua-placeholders.sty
+-- lua-placeholders-manual.pdf lua-placeholders.lua
+-- lua-placeholders-common.lua lua-placeholders-namespace.lua
+-- lua-placeholders-parser.lua and lua-placeholders-types.lua
+
+if not modules then
+ modules = {}
+end
+
+modules.lua_placeholders = {
+ version = "0.1.0",
+ date = "2024/01/12",
+ comment = 'Extended LaTeX Parameter Interface — for specifying and inserting document parameters',
+ author = 'Erik Nijenhuis',
+ license = 'free'
+}
+
+local api = {
+ namespaces = {},
+ parameters = {},
+ strict = false,
+ toks = {
+ is_set_true = token.create('has@param@true'),
+ is_set_false = token.create('has@param@false'),
+ }
+}
+local lua_placeholders = {}
+local lua_placeholders_mt = {
+ __index = api,
+ __newindex = function()
+ tex.error('Cannot override or set actions for this module...')
+ end
+}
+
+setmetatable(lua_placeholders, lua_placeholders_mt)
+
+local lua_placeholders_namespace = require('lua-placeholders-namespace')
+local load_resource = require('lua-placeholders-parser')
+
+local function get_param(key, namespace)
+ namespace = namespace or tex.jobname
+ local _namespace = api.namespaces[namespace]
+ return _namespace and _namespace:param(key)
+end
+
+function api.set_strict()
+ api.strict = true
+end
+
+function api.recipe(path, namespace_name)
+ if namespace_name == '' then
+ namespace_name = nil
+ end
+ local filename, abs_path = lua_placeholders_namespace.parse_filename(path)
+ local raw_recipe = load_resource(abs_path)
+ local name = namespace_name or raw_recipe.namespace or filename
+ local namespace = api.namespaces[name] or lua_placeholders_namespace:new { recipe_file = abs_path, strict = api.strict }
+ if not api.namespaces[name] then
+ api.namespaces[name] = namespace
+ end
+ if raw_recipe.namespace then
+ namespace:load_recipe(raw_recipe.parameters)
+ else
+ namespace:load_recipe(raw_recipe)
+ end
+ tex.print('\\UseOneTimeHook{namespace/' .. name .. '}')
+ if namespace.payload_file and not namespace.payload_loaded then
+ local raw_payload = load_resource(namespace.payload_file)
+ if raw_payload.namespace then
+ namespace:load_payload(raw_payload.parameters)
+ else
+ namespace:load_payload(raw_payload)
+ end
+ tex.print('\\UseOneTimeHook{namespace/' .. name .. '/loaded}')
+ end
+end
+
+function api.payload(path, namespace_name)
+ if namespace_name == '' then
+ namespace_name = nil
+ end
+ local filename, abs_path = lua_placeholders_namespace.parse_filename(path)
+ local raw_payload = load_resource(abs_path)
+ local name = namespace_name or raw_payload.namespace or filename
+ local namespace = api.namespaces[name] or lua_placeholders_namespace:new { payload_file = abs_path, strict = api.strict }
+ if not api.namespaces[name] then
+ api.namespaces[name] = namespace
+ end
+ if namespace.recipe_loaded then
+ if raw_payload.namespace then
+ namespace:load_payload(raw_payload.parameters)
+ else
+ namespace:load_payload(raw_payload)
+ end
+ tex.print('\\UseOneTimeHook{namespace/' .. name .. '/loaded}')
+ end
+end
+
+function api.param_object(key, namespace)
+ return get_param(key, namespace)
+end
+
+function api.param(key, namespace)
+ local param = get_param(key, namespace)
+ if param then
+ param:print_val()
+ elseif api.strict then
+ tex.error('Error: Parameter not set "' .. key .. '" in namespace "' .. namespace .. '".')
+ else
+ tex.sprint(lua_placeholders_toks.unknown_format, '{', key, '}')
+ end
+end
+
+function api.handle_param_is_set(key, namespace)
+ local param = get_param(key, namespace)
+ if param and param:is_set() then
+ tex.sprint(token.create('has@param@true'))
+ else
+ tex.sprint(token.create('has@param@false'))
+ end
+end
+
+function api.field(object_key, field, namespace)
+ local param = get_param(object_key, namespace)
+ if param then
+ local object = param.fields or param.default or {}
+ local f = object[field]
+ if f then
+ f:print_val()
+ else
+ tex.sprint(lua_placeholders_toks.unknown_format, '{', field, '}')
+ end
+ else
+ tex.error('No such object', object_key)
+ end
+end
+
+function api.with_object(object_key, namespace)
+ local object = get_param(object_key, namespace)
+ for key, param in pairs(object.fields) do
+ local val = param:val()
+ if val then
+ token.set_macro(key, param:val() .. '\\xspace')
+ else
+ token.set_macro(key, '\\paramplaceholder{' .. (param.placeholder or key) .. '}\\xspace')
+ end
+ end
+end
+
+function api.for_item(list_key, namespace, csname)
+ local param = get_param(list_key, namespace)
+ local list = param:val()
+ if #list > 0 then
+ if token.is_defined(csname) then
+ local tok = token.create(csname)
+ for _, item in ipairs(list) do
+ if param.values then
+ tex.sprint(tok, '{', item:val(), '}')
+ else
+ tex.sprint(tok, '{', lua_placeholders_toks.placeholder_format, '{', item:val(), '}}')
+ end
+ end
+ else
+ tex.error('No such command ', csname or 'nil')
+ end
+ end
+end
+
+function api.with_rows(key, namespace, csname)
+ local param = get_param(key, namespace)
+ if token.is_defined(csname) then
+ local row_content = token.get_macro(csname)
+ if param then
+ if param.values or api.strict then
+ if #param.values > 0 then
+ for _, row in ipairs(param.values) do
+ local format = row_content
+ for col_key, cell in pairs(row) do
+ format = format:gsub('\\' .. col_key, cell:val())
+ end
+ tex.print(format)
+ end
+ end
+ elseif param.columns then
+ texio.write_nl("Warning: no values set for " .. param.key)
+ local format = row_content
+ for col_key, col in pairs(param.columns) do
+ format = format:gsub('\\' .. col_key, '{\\paramplaceholder{' .. (col.placeholder or col_key) .. '}}')
+ end
+ tex.print(format)
+ else
+ tex.error('No values either columns available')
+ end
+ else
+ tex.error('Error: no such parameter')
+ end
+ else
+ tex.error('Error: no such command: ', csname or 'nil')
+ end
+end
+
+return lua_placeholders