summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/scripts/make4ht/extensions/staticsite.lua
blob: fcb6c09e17d47f4b8e02e6cf7572695a496cd993 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
local M = {}
local filter = require "make4ht-filter"
local mkutils = require "mkutils"

-- 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)
    print("Already pubslished", slug)
    f:close()
  else
    -- escape 
    -- slug must contain the unescaped input name
    local f = io.open(published_name, "w")
    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 = {},
    command = function()
      if not insert_executed  then
        fn()
      end
      insert_executed = true
    end
  })
end


local function copy_files(filename, par)
  local function prepare_path(dir, subdir)
    local path = dir .. "/" .. subdir .. "/" .. filename
    return path:gsub("//", "/")
  end
  -- get extension settings
  local site_settings = get_filter_settings "staticsite"
  local site_root = site_settings.site_root
  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"
  }
  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
    -- make the YAML header only for the main HTML file
    make:match(mainfile .. ".html", process)
    make:match(".*", copy_files, {slug=slug})
  end)

  return make
end

return M