-- 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:raw_val() return self.value or self.values or self.default end function base_param:val() return self:raw_val() 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.sprint(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:raw_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, default = _o.default } setmetatable(o, self) self.__index = self return o end function str_param:val() local value = self:raw_val() if value then local formatted, _ = string.gsub(value, '\n', ' ') return formatted end 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:raw_val() if self.value ~= nil or self.default ~= nil then return self.value or self.default end end function number_param:val() local val = self:raw_val() if val ~= nil then if token.is_defined('numprint') then return '\\numprint{' .. val .. '}' else texio.write_nl([[Warning: package 'numprint' not loaded. Outputting numbers as is.]]) return val end end end function number_param:print_num() texio.write_nl('Warning: number_param:print_num is deprecated. Use number_param:print_val instead') self:print_val() 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