Mon, 20 Apr 2020 11:48:40 -0500
Support Pandoc rendering
-- -- Copyright 2007-2008 Savarese Software Research Corporation. -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.savarese.com/software/ApacheLicense-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- local ltp = require('ltp.util') local function compile_template_to_table(result, data, start_lua, end_lua) local LF, CR, EQ = 10, 13, 61 local i1, i2, i3 i3 = 1 repeat i2, i1 = data:find(start_lua, i3, true) if i2 then if i3 < i2 then table.insert(result, "table.insert(output,") table.insert(result, string.format('%q', data:sub(i3, i2 - 1))) table.insert(result, ");") end i1 = i1 + 2 i2, i3 = data:find(end_lua, i1, true) if i2 then if data:byte(i1-1) == EQ then table.insert(result, "table.insert(output,") table.insert(result, data:sub(i1, i2 - 1)) table.insert(result, ");") i3 = i3 + 1 else table.insert(result, data:sub(i1, i2 - 1)) i3 = i3 + 1 if data:byte(i3) == LF then i3 = i3 + 1 elseif data:byte(i3) == CR and data:byte(i3+1) == LF then i3 = i3 + 2 end end end elseif i3 <= #data then table.insert(result, "table.insert(output,") table.insert(result, string.format('%q', data:sub(i3))) table.insert(result, ");") end until not i2 return result end local function compile_template_as_function(data, start_lua, end_lua) local result = { "return function(output) " } table.insert(compile_template_to_table(result, data, start_lua, end_lua), "end") return table.concat(result) end local function compile_template_as_chunk(data, start_lua, end_lua) local result = { "local output = ... " } return table.concat(compile_template_to_table(result, data, start_lua, end_lua)) end local function compile_template(data, start_lua, end_lua) return table.concat(compile_template_to_table({ }, data, start_lua, end_lua)) end local function load_template(data, start_lua, end_lua) return assert(load(compile_template_as_chunk(data, start_lua, end_lua), "=(load)")) end local function execute_template(template, environment, output) setfenv(template, environment)(output) end local function basic_environment(merge_global, environment) if not environment then environment = { } end if merge_global then ltp.merge_index(environment, _G) else environment.table = table end return environment end local function load_environment(env_files, merge_global) local environment = nil if env_files and #env_files > 0 then for i = 1,#env_files,1 do local efun = assert(loadfile(env_files[i])) if i > 1 then environment = ltp.merge_table(setfenv(efun, environment)(), environment) else environment = basic_environment(merge_global, efun()) end end else environment = basic_environment(merge_global) end return environment end local function read_template(template) return ((template == "-" and io.stdin:read("*a")) or ltp.read_all(template)) end local function render_template(template_data, start_lua, end_lua, environment) local rfun = load_template(template_data, start_lua, end_lua) local output = { } execute_template(rfun, environment, output) return table.concat(output) end local function execute_env_code(env_code, environment) for i = 1,#env_code do local fun, emsg = load(env_code[i]) if fun then setfenv(fun, environment)() else error("error loading " .. env_code[i] .. "\n" .. emsg) end end end local function render(outfile, num_passes, template, merge_global, env_files, start_lua, end_lua, env_code) local data = assert(read_template(template), "error reading " .. template) local environment = load_environment(env_files, merge_global) execute_env_code(env_code, environment) if num_passes > 0 then for i = 1,num_passes do data = render_template(data, start_lua, end_lua, environment) end else -- Prevent an infinite loop by capping expansion to 100 times. num_passes = 1 repeat data = render_template(data, start_lua, end_lua, environment) num_passes = num_passes + 1 until data:find(start_lua, 1, true) == nil or num_passes >= 100 end outfile:write(data); end local function compile_as_function(outfile, template, start_lua, end_lua) local data = read_template(template) outfile:write(compile_template_as_function(data, start_lua, end_lua)) end local function compile(outfile, template, start_lua, end_lua) local data = read_template(template) outfile:write(compile_template(data, start_lua, end_lua)) end return ltp.merge_table( { compile_template_to_table = compile_template_to_table, compile_template_as_chunk = compile_template_as_chunk, compile_template_as_function = compile_template_as_function, compile_template = compile_template, load_template = load_template, execute_template = execute_template, basic_environment = basic_environment, load_environment = load_environment, render_template = render_template, execute_env_code = execute_env_code, render = render, compile_as_function = compile_as_function, compile = compile }, ltp )