handlers/render.lua

Mon, 31 Mar 2025 16:19:17 -0500

author
Tuomo Valkonen <tuomov@iki.fi>
date
Mon, 31 Mar 2025 16:19:17 -0500
changeset 47
242ea28b8cad
parent 46
86950ef7dbcb
permissions
-rwxr-xr-x

bib insertion plugin

--@module handlers.render

local handlers_render = {}

local ltp = require('ltp.template')
local markdown = require('markdown')
local config = require('config')
local path = require('mypath')
local filecache = require('filecache')
local log = require('log')
local dependency = require('dependency')
local pandoc = require('pandoc')
local markdown_it = require('markdown_it')
local err = require('err')

--
-- Phase 1: load & markup
--

function handlers_render.phase1(file, env)
    local f = io.open(path.join(env.paths.src, file), 'r')
    local data = nil
    local in_meta = false
    local linenum = 1
    local meta = {}

    for l in f:lines() do
        if (linenum == 1 or in_meta) and string.match(l, config.meta_marker) then
            in_meta = not in_meta
        elseif in_meta then
            local key, val = string.match(l, "%s*([^:]*)%s*:%s*(.*)%s*")
            if key and val then
                -- very primitive quoting, primarily as a hack to
                -- not need converting my files that much from Webgen.
                local val_unq = string.match(val, '^"(.*)"$')
                meta[key] = val_unq or val
            else
                err.file_pos(file, linenum, "meta data syntax error: " .. l)
            end
        else
            if data then
                data = data .. "\n" .. l
            else
                data = l
            end
        end
        linenum = linenum + 1
    end

    log.log("Load " .. file .. "\n")

    f:close()

    local destination
    if meta.destination then
        destination = path.join(path.dirname(file), meta.destination)
    else
        -- If the file has two extensions, then only remove last extension.
        -- Otherwise replace extension with .html.
        destination = path.rmext(file)
        base = path.rmext(destination)
        if base == destination then
            destination = destination .. ".html"
        end
    end

    local deps = nil
    if meta.dependencies then
        deps = {}
        for s in string.gmatch(meta.dependencies, "[^%s,]+") do
            table.insert(deps, s)
        end
        meta.dependencies = nil
    end

    local page = {
        data = data,
        meta = meta,
        destination = destination,
        dependencies = deps,
        file = file,
    }

    env.pages[file] = page
end

function handlers_render.process_lua(template, env)
    env = table.join(env, { env = env }) -- TODO: should use __index
    --return ltp.render(nil, 1, template, env, {}, "<%", "%>", {})
    return ltp.render_template(template, "<%", "%>",
        ltp.merge_index(env, _G))
end

function handlers_render.env_for(file, env, path_prefix)
    local newenv = table.copy(env)

    newenv.source_file = file
    newenv.base_url = path.to_root(file)
    newenv.path_prefix = (path_prefix or "")
    newenv.page = env.pages[file]

    return newenv
end

function handlers_render.render(file, env, path_prefix, renderer)
    local data = env.pages[file].data
    if data then
        local newenv = handlers_render.env_for(file, env, path_prefix)
        local data2 = handlers_render.process_lua(data, newenv)
        meta = env.pages[file].meta
        if renderer == "markdown-it" then
            return markdown_it.markdown(data2, env)
        elseif renderer == "pandoc" then
            return pandoc.pandoc(data2)
        elseif renderer == "lua-markdown" then
            return markdown(data2)
        elseif renderer == "none" then
            return data2
        else
            error('Unknown renderer')
        end
    end
end

function handlers_render.phase2(file, env)
    local page = env.pages[file]
    local src = path.join(env.paths.src, file)
    local dst = path.join(env.paths.dst, page.destination)
    local tmpl = path.join(env.paths.tmpl,
        page.meta.template or "page.template")
    renderer = page.meta.renderer or "markdown-it"

    local build = page.meta.always_build
    if not build then
        local deps = { src, tmpl }
        if page.dependencies then
            for _, v in ipairs(page.dependencies) do
                table.insert(deps, v)
            end
        end
        if renderer == "markdown-it" then
            markdown_it.add_deps(deps, env)
        end
        build = dependency.simple_update_check(dst, deps)
    end

    if build then
        log.log("Render " .. file .. "\n")
        local content = handlers_render.render(file, env, page.meta, renderer)
        local page_template = filecache.get(tmpl)

        local newenv = table.join({ content = content }, handlers_render.env_for(file, env))
        local data2 = handlers_render.process_lua(page_template, newenv)

        log.log("Write " .. page.destination .. "\n")
        local f = io.openX(dst, "w")
        f:write(data2)
    end
end

return handlers_render

mercurial