local M = {}
local filter = require "make4ht-filter"
local mkutils = require "mkutils"
local log = logging.new "staticsite"
-- get the published file name
local function get_slug(settings)
local published_name = mkutils.remove_extension(settings.tex_file) .. ".published"
local config = get_filter_settings "staticsite"
local file_pattern = config.file_pattern or "%Y-%m-%d-${input}"
local time = os.time()
-- we must save the published date, so the subsequent compilations at different days
-- use the same name
if mkutils.file_exists(published_name) then
local f = io.open(published_name, "r")
local readtime = f:read("*line")
time = tonumber(readtime)
log:info("Already pubslished", os.date("%Y-%m-%d %H:%M", time))
f:close()
else
-- escape
-- slug must contain the unescaped input name
local f = io.open(published_name, "w")
log:info("Publishing article", os.date("%Y-%m-%d %H:%M", time))
f:write(time)
f:close()
end
-- set the updated and publishing times
local updated
-- the updated time will be set only when it is more than one day from the published time
local newtime = os.time()
if (newtime - time) > (24 * 3600) then updated = newtime end
filter_settings "staticsite" {
header = {
time = time,
updated = updated
}
}
-- make the output file name in the format YYYY-MM-DD-old-filename.html
local slug = os.date(file_pattern,time) % settings
return slug
end
-- it is necessary to set correct -jobname in latex_par parameters field
-- in order to the get correct HTML file name
local function update_jobname(slug, latex_par)
local latex_par = latex_par or ""
if latex_par:match("%-jobname") then
local firstchar=latex_par:match("%-jobname=.")
local replace_pattern="%-jobname=[^%s]+"
if firstchar == "'" or firstchar=='"' then
replace_pattern = "%-jobname=".. firstchar .."[^%"..firstchar.."]+"
end
return latex_par:gsub(replace_pattern, "-jobname=".. slug)
else
return latex_par .. "-jobname="..slug
end
end
-- execute the function passed as parameter only once, when the file matching
-- starts
local function insert_filter(make, pattern, fn)
local insert_executed = false
table.insert(make.matches, 1, {
pattern=pattern,
params = make.params or {},
command = function()
if not insert_executed then
fn()
end
insert_executed = true
end
})
end
local function remove_maketitle(make)
-- use DOM filter to remove \maketitle block
local domfilter = require "make4ht-domfilter"
local process = domfilter({
function(dom)
local maketitles = dom:query_selector(".maketitle")
for _, el in ipairs(maketitles) do
log:debug("removing maketitle")
el:remove_node()
end
return dom
end
}, "staticsite")
make:match("html$", process)
end
local function copy_files(filename, par)
local function prepare_path(dir, subdir)
local f = filename
if par.builddir then
f = f:gsub("^" .. par.builddir .. "/", "")
end
local path = dir .. "/" .. subdir .. "/" .. f
return path:gsub("//", "/")
end
-- get extension settings
local site_settings = get_filter_settings "staticsite"
local site_root = site_settings.site_root or par.outdir
if site_root == "" then site_root = "./" end
local map = site_settings.map or {}
-- default path without subdir, will be used if the file is not matched
-- by any pattern in the map
local path = prepare_path(site_root, "")
for pattern, destination in pairs(map) do
if filename:match(pattern) then
path = prepare_path(site_root, destination)
break
end
end
-- it is possible to use string extrapolation in path, for example for slug
mkutils.copy(filename, path % par)
end
function M.modify_build(make)
-- it is necessary to insert the filters for YAML header and file copying as last matches
-- we use an bogus match which will be executed only once as the very first one to insert
-- the filters
-- I should make filter from this
local process = filter({
"staticsite"
}, "staticsite")
-- detect if we should remove maketitle
local site_settings = get_filter_settings "staticsite"
-- \maketitle is removed by default, set `remove_maketitle=false` setting to disable that
if site_settings.remove_maketitle ~= false then
remove_maketitle(make)
end
local settings = make.params
-- get the published file name
local slug = get_slug(settings)
for _, cmd in ipairs(make.build_seq) do
-- all commands must use the published file name
cmd.params.input = slug
cmd.params.latex_par = update_jobname(slug, cmd.params.latex_par)
end
local quotepattern = '(['..("%^$().[]*+-?"):gsub("(.)", "%%%1")..'])'
local mainfile = string.gsub(slug, quotepattern, "%%%1")
-- run the following code once in the first match on the first file
insert_filter(make, ".*", function()
-- for _, match in ipairs(make.matches) do
-- match.params.outdir = outdir
-- print(match.pattern, match.params.outdir)
-- end
local params = make.params
params.slug = slug
make:match("html?$", process, params)
make:match(".*", copy_files, params)
end)