From 97106ae9313f56715ee9a7dd39d708158c1bedb9 Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Mon, 4 Nov 2019 03:00:32 +0000 Subject: CTAN sync 201911040300 --- support/make4ht/extensions/common_domfilters.lua | 36 --- support/make4ht/extensions/common_filters.lua | 26 -- support/make4ht/extensions/dvisvgm_hashes.lua | 269 --------------------- support/make4ht/extensions/join_colors.lua | 16 -- support/make4ht/extensions/latexmk_build.lua | 31 --- .../extensions/make4ht-ext-common_domfilters.lua | 36 +++ .../extensions/make4ht-ext-common_filters.lua | 26 ++ .../extensions/make4ht-ext-dvisvgm_hashes.lua | 269 +++++++++++++++++++++ .../make4ht/extensions/make4ht-ext-join_colors.lua | 16 ++ .../extensions/make4ht-ext-latexmk_build.lua | 31 +++ .../make4ht/extensions/make4ht-ext-mathjaxnode.lua | 16 ++ .../make4ht/extensions/make4ht-ext-odttemplate.lua | 16 ++ .../extensions/make4ht-ext-preprocess_input.lua | 108 +++++++++ .../make4ht/extensions/make4ht-ext-staticsite.lua | 136 +++++++++++ support/make4ht/extensions/make4ht-ext-tidy.lua | 58 +++++ support/make4ht/extensions/mathjaxnode.lua | 16 -- support/make4ht/extensions/odttemplate.lua | 16 -- support/make4ht/extensions/preprocess_input.lua | 108 --------- support/make4ht/extensions/staticsite.lua | 136 ----------- support/make4ht/extensions/tidy.lua | 58 ----- 20 files changed, 712 insertions(+), 712 deletions(-) delete mode 100644 support/make4ht/extensions/common_domfilters.lua delete mode 100644 support/make4ht/extensions/common_filters.lua delete mode 100644 support/make4ht/extensions/dvisvgm_hashes.lua delete mode 100644 support/make4ht/extensions/join_colors.lua delete mode 100644 support/make4ht/extensions/latexmk_build.lua create mode 100644 support/make4ht/extensions/make4ht-ext-common_domfilters.lua create mode 100644 support/make4ht/extensions/make4ht-ext-common_filters.lua create mode 100644 support/make4ht/extensions/make4ht-ext-dvisvgm_hashes.lua create mode 100644 support/make4ht/extensions/make4ht-ext-join_colors.lua create mode 100644 support/make4ht/extensions/make4ht-ext-latexmk_build.lua create mode 100644 support/make4ht/extensions/make4ht-ext-mathjaxnode.lua create mode 100644 support/make4ht/extensions/make4ht-ext-odttemplate.lua create mode 100644 support/make4ht/extensions/make4ht-ext-preprocess_input.lua create mode 100644 support/make4ht/extensions/make4ht-ext-staticsite.lua create mode 100644 support/make4ht/extensions/make4ht-ext-tidy.lua delete mode 100644 support/make4ht/extensions/mathjaxnode.lua delete mode 100644 support/make4ht/extensions/odttemplate.lua delete mode 100644 support/make4ht/extensions/preprocess_input.lua delete mode 100644 support/make4ht/extensions/staticsite.lua delete mode 100644 support/make4ht/extensions/tidy.lua (limited to 'support/make4ht/extensions') diff --git a/support/make4ht/extensions/common_domfilters.lua b/support/make4ht/extensions/common_domfilters.lua deleted file mode 100644 index 9399492d90..0000000000 --- a/support/make4ht/extensions/common_domfilters.lua +++ /dev/null @@ -1,36 +0,0 @@ -local M = {} - - --- this variable will hold the output format name -local current_format - -local filter = require "make4ht-domfilter" --- local process = filter {"fixinlines", "idcolons", "joincharacters" } - --- filters support only html formats -function M.test(format) - current_format = format - -- if format == "odt" then return false end - return true -end - -function M.modify_build(make) - -- number of filters that should be moved to the beginning - local count = 0 - if current_format == "odt" then - -- some formats doesn't make sense in the ODT format - local process = filter {"joincharacters"} - local charclasses = {mn = true, ["text:span"] = true} - make:match("4oo$", process, {charclasses= charclasses}) - -- match math documents - make:match("4om$", process, {charclasses= charclasses}) - count = 2 - else - local process = filter {"fixinlines", "idcolons", "joincharacters", "tablerows"} - make:match("html$", process) - count = 1 - end - return make -end - -return M diff --git a/support/make4ht/extensions/common_filters.lua b/support/make4ht/extensions/common_filters.lua deleted file mode 100644 index 513fbed34e..0000000000 --- a/support/make4ht/extensions/common_filters.lua +++ /dev/null @@ -1,26 +0,0 @@ -local M = {} - - -local filter = require "make4ht-filter" -local process = filter {"cleanspan-nat", "fixligatures", "hruletohr", "entities", "fix-links"} - --- filters support only html formats -function M.test(format) - if format == "odt" then return false end - return true -end - -function M.modify_build(make) - make:match("html$", process) - local matches = make.matches - -- the filters should be first match to be executed, especially if tidy - -- should be executed as well - if #matches > 1 then - local last = matches[#matches] - table.insert(matches, 1, last) - matches[#matches] = nil - end - return make -end - -return M diff --git a/support/make4ht/extensions/dvisvgm_hashes.lua b/support/make4ht/extensions/dvisvgm_hashes.lua deleted file mode 100644 index 87f58abd57..0000000000 --- a/support/make4ht/extensions/dvisvgm_hashes.lua +++ /dev/null @@ -1,269 +0,0 @@ -local dvireader = require "make4ht-dvireader" -local mkutils = require "mkutils" -local filter = require "make4ht-filter" -local log = logging.new "dvisvgm_hashes" - - -local dvisvgm_par = {} - -local M = {} --- mapping between tex4ht image names and hashed image names -local output_map = {} -local dvisvgm_options = "-n --exact -c ${scale},${scale}" -local parallel_size = 64 --- local parallel_size = 3 - -local function make_hashed_name(base, hash) - return base .. "-" ..hash..".svg" -end - --- detect the number of available processors -local cpu_cnt = 3 -- set a reasonable default for non-Linux systems - -if os.name == 'linux' then - cpu_cnt = 0 - local cpuinfo=assert(io.open('/proc/cpuinfo', 'r')) - for line in cpuinfo:lines() do - if line:match('^processor') then - cpu_cnt = cpu_cnt + 1 - end - end - -- set default number of threds if no CPU core have been found - if cpu_cnt == 0 then cpu_cnt = 1 end - cpuinfo:close() -elseif os.name == 'cygwin' or os.type == 'windows' then - -- windows has NUMBER_OF_PROCESSORS environmental value - local nop = os.getenv('NUMBER_OF_PROCESSORS') - if tonumber(nop) then - cpu_cnt = nop - end -end - - - --- process output of dvisvgm and find output page numbers and corresponding files -local function get_generated_pages(output, pages) - local pages = pages or {} - local pos = 1 - local pos, finish, page = string.find(output, "processing page (%d+)", pos) - while(pos) do - pos, finish, file = string.find(output, "output written to ([^\n]+)", finish) - pages[tonumber(page)] = file - if not finish then break end - pos, finish, page = string.find(output, "processing page (%d+)", finish) - end - return pages -end - -local function make_ranges(pages) - local newpages = {} - local start, stop - for i=1,#pages do - local current = pages[i] - local next_el = pages[i+1] or current + 100 -- just select a big number - local diff = next_el - current - if diff == 1 then - if not start then start = current end - else - local element - if start then - element = start .. "-" .. current - else - element = current - end - newpages[#newpages+1] = element - start = nil - end - end - return newpages -end - -local function read_log(dvisvgmlog) - local f = io.open(dvisvgmlog, "rb") - if not f then return nil, "Cannot read dvisvgm log" end - local output = f:read("*all") - f:close() - return output -end - --- test the existence of GNU Make, which can execute tasks in parallel -local function test_make() - local make = io.popen("make -v", "r") - if not make then return false end - local content = make:read("*all") - make:close() - return true -end - -local function save_file(filename, text) - local f = io.open(filename, "w") - f:write(text) - f:close() -end - - -local function make_makefile_command(idvfile, page_sequences) - local logs = {} - local all = {} -- list of targets in the "all:" makefile target - local targets = {} - local basename = idvfile:gsub(".idv$", "") - local makefilename = basename .. "-images" .. ".mk" - -- build make targets - for i, ranges in ipairs(page_sequences) do - local target = basename .. "-" .. i - local logfile = target .. ".dlog" - logs[#logs + 1] = logfile - all[#all+1] = target - local chunk = target .. ":\n\tdvisvgm -v4 " .. dvisvgm_options .. " -p " .. ranges .. " " .. idvfile .. " 2> " .. logfile .. "\n" - targets[#targets + 1] = chunk - end - -- construct makefile and save it - local makefile = "all: " .. table.concat(all, " ") .. "\n\n" .. table.concat(targets, "\n") - save_file(makefilename, makefile) - local command = "make -j" .. cpu_cnt .." -f " .. makefilename - return command, logs -end - -local function prepare_command(idvfile, pages) - local logs = {} - if #pages > parallel_size and test_make() then - local page_sequences = {} - for i=1, #pages, parallel_size do - local current_pages = {} - for x = i, i+parallel_size -1 do - current_pages[#current_pages + 1] = pages[x] - end - table.insert(page_sequences,table.concat(make_ranges(current_pages), ",")) - end - return make_makefile_command(idvfile, page_sequences) - end - -- else - local pagesequence = table.concat(make_ranges(pages), ",") - -- the stderr from dvisvgm must be redirected and postprocessed - local dvisvgmlog = idvfile:gsub("idv$", "dlog") - -- local dvisvgm = io.popen("dvisvgm -v4 -n --exact -c 1.15,1.15 -p " .. pagesequence .. " " .. idvfile, "r") - local command = "dvisvgm -v4 " .. dvisvgm_options .. " -p " .. pagesequence .. " " .. idvfile .. " 2> " .. dvisvgmlog - return command, {dvisvgmlog} - -- end -end - -local function execute_dvisvgm(idvfile, pages) - if #pages < 1 then return nil, "No pages to convert" end - local command, logs = prepare_command(idvfile, pages) - log:info(command) - os.execute(command) - local generated_pages = {} - for _, dvisvgmlog in ipairs(logs) do - local output = read_log(dvisvgmlog) - generated_pages = get_generated_pages(output, generated_pages) - end - return generated_pages -end - -local function get_dvi_pages(arg) - -- list of pages to convert in this run - local to_convert = {} - local idv_file = arg.input .. ".idv" - -- set extension options - local extoptions = mkutils.get_filter_settings "dvisvgm_hashes" or {} - dvisvgm_options = arg.options or extoptions.options or dvisvgm_options - parallel_size = arg.parallel_size or extoptions.parallel_size or parallel_size - cpu_cnt = arg.cpu_cnt or extoptions.cpu_cnt or cpu_cnt - dvisvgm_par.scale = arg.scale or extoptions.scale or 1.15 - dvisvgm_options = dvisvgm_options % dvisvgm_par - local f = io.open(idv_file, "rb") - if not f then return nil, "Cannot open idv file: " .. idv_file end - local content = f:read("*all") - f:close() - local dvi_pages = dvireader.get_pages(content) - -- we must find page numbers and output name sfor the generated images - local lg = mkutils.parse_lg(arg.input ..".lg") - for _, name in ipairs(lg.images) do - local page = tonumber(name.page) - local hash = dvi_pages[page] - local tex4ht_name = name.output - local output_name = make_hashed_name(arg.input, hash) - output_map[tex4ht_name] = output_name - if not mkutils.file_exists(output_name) then - log:debug("output file: ".. output_name) - to_convert[#to_convert+1] = page - end - end - local generated_files, msg = execute_dvisvgm(idv_file, to_convert) - if not generated_files then - return nil, msg - end - - -- rename the generated files to the hashed filenames - for page, file in pairs(generated_files) do - os.rename(file, make_hashed_name(arg.input, dvi_pages[page])) - end - -end - -function M.test(format) - -- ODT format doesn't support SVG - if format == "odt" then return false end - return true -end - -function M.modify_build(make) - -- this must be used in the .mk4 file as - -- Make:dvisvgm_hashes {} - make:add("dvisvgm_hashes", function(arg) - get_dvi_pages(arg) - end, - { - }) - - -- insert dvisvgm_hashes command at the end of the build sequence -- it needs to be called after t4ht - make:dvisvgm_hashes {} - - -- replace original image names with hashed names - local executed = false - make:match(".*", function(arg) - if not executed then - executed = true - local lgfiles = make.lgfile.files - for i, filename in ipairs(lgfiles) do - local replace = output_map[filename] - if replace then - lgfiles[i] = replace - end - end - -- tex4ebook process also the images table, so we need to replace generated filenames here as well - local lgimages = make.lgfile.images - for _, image in ipairs(lgimages) do - local replace = output_map[image.output] - if replace then - image.output = replace - end - end - end - end) - - -- fix src attributes - local process = filter { - function(str) - return str:gsub('src="([^"]+)', function(filename) - local newname = output_map[filename] or filename - log:debug("newname", newname) - return 'src="'.. newname - end) - end - } - - make:match("htm.?$", process) - - -- disable the image processing - for _,v in ipairs(make.build_seq) do - if v.name == "t4ht" then - local t4ht_par = v.params.t4ht_par or make.params.t4ht_par or "" - v.params.t4ht_par = t4ht_par .. " -p" - end - end - make:image(".", function() return "" end) - return make -end - -return M diff --git a/support/make4ht/extensions/join_colors.lua b/support/make4ht/extensions/join_colors.lua deleted file mode 100644 index 182661fbdb..0000000000 --- a/support/make4ht/extensions/join_colors.lua +++ /dev/null @@ -1,16 +0,0 @@ -local M = {} - -local filter = require "make4ht-domfilter" - --- filters support only html formats -function M.test(format) - if format == "odt" then return false end - return true -end - -function M.modify_build(make) - local process = filter {"joincolors"} - make:match("html$", process) - return make -end -return M diff --git a/support/make4ht/extensions/latexmk_build.lua b/support/make4ht/extensions/latexmk_build.lua deleted file mode 100644 index bf4dcdde5a..0000000000 --- a/support/make4ht/extensions/latexmk_build.lua +++ /dev/null @@ -1,31 +0,0 @@ --- use Latexmk in first LaTeX call --- only in the first call, because we don't need to execute biber, etc. in the subsequent --- LaTeX calls, these are only for resolving the cross-references -local M = {} -function M.modify_build(make) - local used = false - local first - local build_seq = make.build_seq - -- find first htlatex call in the build sequence - for pos,v in ipairs(build_seq) do - if v.name == "htlatex" and not first then - first = pos - end - end - -- if htlatex was found - if first then - -- add dummy latexmk call to the build sequence - make:latexmk {} - -- replace name, command and type in the first htlatex - -- call with values from the dummy latexmk call - local replaced = build_seq[first] - local latexmk = build_seq[#build_seq] - replaced.name = latexmk.name - replaced.command = latexmk.command - replaced.type = latexmk.type - -- remove the dummy latexmk - table.remove(build_seq) - end - return make -end -return M diff --git a/support/make4ht/extensions/make4ht-ext-common_domfilters.lua b/support/make4ht/extensions/make4ht-ext-common_domfilters.lua new file mode 100644 index 0000000000..9399492d90 --- /dev/null +++ b/support/make4ht/extensions/make4ht-ext-common_domfilters.lua @@ -0,0 +1,36 @@ +local M = {} + + +-- this variable will hold the output format name +local current_format + +local filter = require "make4ht-domfilter" +-- local process = filter {"fixinlines", "idcolons", "joincharacters" } + +-- filters support only html formats +function M.test(format) + current_format = format + -- if format == "odt" then return false end + return true +end + +function M.modify_build(make) + -- number of filters that should be moved to the beginning + local count = 0 + if current_format == "odt" then + -- some formats doesn't make sense in the ODT format + local process = filter {"joincharacters"} + local charclasses = {mn = true, ["text:span"] = true} + make:match("4oo$", process, {charclasses= charclasses}) + -- match math documents + make:match("4om$", process, {charclasses= charclasses}) + count = 2 + else + local process = filter {"fixinlines", "idcolons", "joincharacters", "tablerows"} + make:match("html$", process) + count = 1 + end + return make +end + +return M diff --git a/support/make4ht/extensions/make4ht-ext-common_filters.lua b/support/make4ht/extensions/make4ht-ext-common_filters.lua new file mode 100644 index 0000000000..513fbed34e --- /dev/null +++ b/support/make4ht/extensions/make4ht-ext-common_filters.lua @@ -0,0 +1,26 @@ +local M = {} + + +local filter = require "make4ht-filter" +local process = filter {"cleanspan-nat", "fixligatures", "hruletohr", "entities", "fix-links"} + +-- filters support only html formats +function M.test(format) + if format == "odt" then return false end + return true +end + +function M.modify_build(make) + make:match("html$", process) + local matches = make.matches + -- the filters should be first match to be executed, especially if tidy + -- should be executed as well + if #matches > 1 then + local last = matches[#matches] + table.insert(matches, 1, last) + matches[#matches] = nil + end + return make +end + +return M diff --git a/support/make4ht/extensions/make4ht-ext-dvisvgm_hashes.lua b/support/make4ht/extensions/make4ht-ext-dvisvgm_hashes.lua new file mode 100644 index 0000000000..87f58abd57 --- /dev/null +++ b/support/make4ht/extensions/make4ht-ext-dvisvgm_hashes.lua @@ -0,0 +1,269 @@ +local dvireader = require "make4ht-dvireader" +local mkutils = require "mkutils" +local filter = require "make4ht-filter" +local log = logging.new "dvisvgm_hashes" + + +local dvisvgm_par = {} + +local M = {} +-- mapping between tex4ht image names and hashed image names +local output_map = {} +local dvisvgm_options = "-n --exact -c ${scale},${scale}" +local parallel_size = 64 +-- local parallel_size = 3 + +local function make_hashed_name(base, hash) + return base .. "-" ..hash..".svg" +end + +-- detect the number of available processors +local cpu_cnt = 3 -- set a reasonable default for non-Linux systems + +if os.name == 'linux' then + cpu_cnt = 0 + local cpuinfo=assert(io.open('/proc/cpuinfo', 'r')) + for line in cpuinfo:lines() do + if line:match('^processor') then + cpu_cnt = cpu_cnt + 1 + end + end + -- set default number of threds if no CPU core have been found + if cpu_cnt == 0 then cpu_cnt = 1 end + cpuinfo:close() +elseif os.name == 'cygwin' or os.type == 'windows' then + -- windows has NUMBER_OF_PROCESSORS environmental value + local nop = os.getenv('NUMBER_OF_PROCESSORS') + if tonumber(nop) then + cpu_cnt = nop + end +end + + + +-- process output of dvisvgm and find output page numbers and corresponding files +local function get_generated_pages(output, pages) + local pages = pages or {} + local pos = 1 + local pos, finish, page = string.find(output, "processing page (%d+)", pos) + while(pos) do + pos, finish, file = string.find(output, "output written to ([^\n]+)", finish) + pages[tonumber(page)] = file + if not finish then break end + pos, finish, page = string.find(output, "processing page (%d+)", finish) + end + return pages +end + +local function make_ranges(pages) + local newpages = {} + local start, stop + for i=1,#pages do + local current = pages[i] + local next_el = pages[i+1] or current + 100 -- just select a big number + local diff = next_el - current + if diff == 1 then + if not start then start = current end + else + local element + if start then + element = start .. "-" .. current + else + element = current + end + newpages[#newpages+1] = element + start = nil + end + end + return newpages +end + +local function read_log(dvisvgmlog) + local f = io.open(dvisvgmlog, "rb") + if not f then return nil, "Cannot read dvisvgm log" end + local output = f:read("*all") + f:close() + return output +end + +-- test the existence of GNU Make, which can execute tasks in parallel +local function test_make() + local make = io.popen("make -v", "r") + if not make then return false end + local content = make:read("*all") + make:close() + return true +end + +local function save_file(filename, text) + local f = io.open(filename, "w") + f:write(text) + f:close() +end + + +local function make_makefile_command(idvfile, page_sequences) + local logs = {} + local all = {} -- list of targets in the "all:" makefile target + local targets = {} + local basename = idvfile:gsub(".idv$", "") + local makefilename = basename .. "-images" .. ".mk" + -- build make targets + for i, ranges in ipairs(page_sequences) do + local target = basename .. "-" .. i + local logfile = target .. ".dlog" + logs[#logs + 1] = logfile + all[#all+1] = target + local chunk = target .. ":\n\tdvisvgm -v4 " .. dvisvgm_options .. " -p " .. ranges .. " " .. idvfile .. " 2> " .. logfile .. "\n" + targets[#targets + 1] = chunk + end + -- construct makefile and save it + local makefile = "all: " .. table.concat(all, " ") .. "\n\n" .. table.concat(targets, "\n") + save_file(makefilename, makefile) + local command = "make -j" .. cpu_cnt .." -f " .. makefilename + return command, logs +end + +local function prepare_command(idvfile, pages) + local logs = {} + if #pages > parallel_size and test_make() then + local page_sequences = {} + for i=1, #pages, parallel_size do + local current_pages = {} + for x = i, i+parallel_size -1 do + current_pages[#current_pages + 1] = pages[x] + end + table.insert(page_sequences,table.concat(make_ranges(current_pages), ",")) + end + return make_makefile_command(idvfile, page_sequences) + end + -- else + local pagesequence = table.concat(make_ranges(pages), ",") + -- the stderr from dvisvgm must be redirected and postprocessed + local dvisvgmlog = idvfile:gsub("idv$", "dlog") + -- local dvisvgm = io.popen("dvisvgm -v4 -n --exact -c 1.15,1.15 -p " .. pagesequence .. " " .. idvfile, "r") + local command = "dvisvgm -v4 " .. dvisvgm_options .. " -p " .. pagesequence .. " " .. idvfile .. " 2> " .. dvisvgmlog + return command, {dvisvgmlog} + -- end +end + +local function execute_dvisvgm(idvfile, pages) + if #pages < 1 then return nil, "No pages to convert" end + local command, logs = prepare_command(idvfile, pages) + log:info(command) + os.execute(command) + local generated_pages = {} + for _, dvisvgmlog in ipairs(logs) do + local output = read_log(dvisvgmlog) + generated_pages = get_generated_pages(output, generated_pages) + end + return generated_pages +end + +local function get_dvi_pages(arg) + -- list of pages to convert in this run + local to_convert = {} + local idv_file = arg.input .. ".idv" + -- set extension options + local extoptions = mkutils.get_filter_settings "dvisvgm_hashes" or {} + dvisvgm_options = arg.options or extoptions.options or dvisvgm_options + parallel_size = arg.parallel_size or extoptions.parallel_size or parallel_size + cpu_cnt = arg.cpu_cnt or extoptions.cpu_cnt or cpu_cnt + dvisvgm_par.scale = arg.scale or extoptions.scale or 1.15 + dvisvgm_options = dvisvgm_options % dvisvgm_par + local f = io.open(idv_file, "rb") + if not f then return nil, "Cannot open idv file: " .. idv_file end + local content = f:read("*all") + f:close() + local dvi_pages = dvireader.get_pages(content) + -- we must find page numbers and output name sfor the generated images + local lg = mkutils.parse_lg(arg.input ..".lg") + for _, name in ipairs(lg.images) do + local page = tonumber(name.page) + local hash = dvi_pages[page] + local tex4ht_name = name.output + local output_name = make_hashed_name(arg.input, hash) + output_map[tex4ht_name] = output_name + if not mkutils.file_exists(output_name) then + log:debug("output file: ".. output_name) + to_convert[#to_convert+1] = page + end + end + local generated_files, msg = execute_dvisvgm(idv_file, to_convert) + if not generated_files then + return nil, msg + end + + -- rename the generated files to the hashed filenames + for page, file in pairs(generated_files) do + os.rename(file, make_hashed_name(arg.input, dvi_pages[page])) + end + +end + +function M.test(format) + -- ODT format doesn't support SVG + if format == "odt" then return false end + return true +end + +function M.modify_build(make) + -- this must be used in the .mk4 file as + -- Make:dvisvgm_hashes {} + make:add("dvisvgm_hashes", function(arg) + get_dvi_pages(arg) + end, + { + }) + + -- insert dvisvgm_hashes command at the end of the build sequence -- it needs to be called after t4ht + make:dvisvgm_hashes {} + + -- replace original image names with hashed names + local executed = false + make:match(".*", function(arg) + if not executed then + executed = true + local lgfiles = make.lgfile.files + for i, filename in ipairs(lgfiles) do + local replace = output_map[filename] + if replace then + lgfiles[i] = replace + end + end + -- tex4ebook process also the images table, so we need to replace generated filenames here as well + local lgimages = make.lgfile.images + for _, image in ipairs(lgimages) do + local replace = output_map[image.output] + if replace then + image.output = replace + end + end + end + end) + + -- fix src attributes + local process = filter { + function(str) + return str:gsub('src="([^"]+)', function(filename) + local newname = output_map[filename] or filename + log:debug("newname", newname) + return 'src="'.. newname + end) + end + } + + make:match("htm.?$", process) + + -- disable the image processing + for _,v in ipairs(make.build_seq) do + if v.name == "t4ht" then + local t4ht_par = v.params.t4ht_par or make.params.t4ht_par or "" + v.params.t4ht_par = t4ht_par .. " -p" + end + end + make:image(".", function() return "" end) + return make +end + +return M diff --git a/support/make4ht/extensions/make4ht-ext-join_colors.lua b/support/make4ht/extensions/make4ht-ext-join_colors.lua new file mode 100644 index 0000000000..182661fbdb --- /dev/null +++ b/support/make4ht/extensions/make4ht-ext-join_colors.lua @@ -0,0 +1,16 @@ +local M = {} + +local filter = require "make4ht-domfilter" + +-- filters support only html formats +function M.test(format) + if format == "odt" then return false end + return true +end + +function M.modify_build(make) + local process = filter {"joincolors"} + make:match("html$", process) + return make +end +return M diff --git a/support/make4ht/extensions/make4ht-ext-latexmk_build.lua b/support/make4ht/extensions/make4ht-ext-latexmk_build.lua new file mode 100644 index 0000000000..bf4dcdde5a --- /dev/null +++ b/support/make4ht/extensions/make4ht-ext-latexmk_build.lua @@ -0,0 +1,31 @@ +-- use Latexmk in first LaTeX call +-- only in the first call, because we don't need to execute biber, etc. in the subsequent +-- LaTeX calls, these are only for resolving the cross-references +local M = {} +function M.modify_build(make) + local used = false + local first + local build_seq = make.build_seq + -- find first htlatex call in the build sequence + for pos,v in ipairs(build_seq) do + if v.name == "htlatex" and not first then + first = pos + end + end + -- if htlatex was found + if first then + -- add dummy latexmk call to the build sequence + make:latexmk {} + -- replace name, command and type in the first htlatex + -- call with values from the dummy latexmk call + local replaced = build_seq[first] + local latexmk = build_seq[#build_seq] + replaced.name = latexmk.name + replaced.command = latexmk.command + replaced.type = latexmk.type + -- remove the dummy latexmk + table.remove(build_seq) + end + return make +end +return M diff --git a/support/make4ht/extensions/make4ht-ext-mathjaxnode.lua b/support/make4ht/extensions/make4ht-ext-mathjaxnode.lua new file mode 100644 index 0000000000..cbad897d4e --- /dev/null +++ b/support/make4ht/extensions/make4ht-ext-mathjaxnode.lua @@ -0,0 +1,16 @@ +local M = {} + + +local filter = require "make4ht-filter" +function M.test(format) + if format == "odt" then return false end + return true +end + +function M.modify_build(make) + local mathjax = filter { "mathjaxnode"} + make:match("html$",mathjax) + return make +end + +return M diff --git a/support/make4ht/extensions/make4ht-ext-odttemplate.lua b/support/make4ht/extensions/make4ht-ext-odttemplate.lua new file mode 100644 index 0000000000..3b0af2a699 --- /dev/null +++ b/support/make4ht/extensions/make4ht-ext-odttemplate.lua @@ -0,0 +1,16 @@ +local M = {} + +local filter = require "make4ht-filter" + +-- this extension only works for the ODT format +M.test = function(format) + return format=="odt" +end + +M.modify_build = function(make) + local process = filter {"odttemplate"} + make:match("4oy$", process) + return make +end + +return M diff --git a/support/make4ht/extensions/make4ht-ext-preprocess_input.lua b/support/make4ht/extensions/make4ht-ext-preprocess_input.lua new file mode 100644 index 0000000000..3155a8a781 --- /dev/null +++ b/support/make4ht/extensions/make4ht-ext-preprocess_input.lua @@ -0,0 +1,108 @@ +-- preprocess R literate sources or Markdown files to LaTeX +local M = {} +local log = logging.new "preprocess_input" +local mkutils = require "mkutils" + +local commands = { + knitr = { command = 'Rscript -e "library(knitr); knit(\'${tex_file}\', output=\'${tmp_file}\')"'}, + pandoc = { command = 'pandoc -f ${input_format} -s -o \'${tmp_file}\' -t latex \'${tex_file}\''} +} +local filetypes = { + rnw = {sequence = {"knitr"} }, + rtex = {sequence = {"knitr"}}, + rmd = {sequence = {"knitr", "pandoc"}, options = {input_format = "markdown"}}, + rrst = {sequence = {"knitr", "pandoc"}, options = {input_format = "rst"}}, + md = {sequence = {"pandoc"}, options = {input_format = "markdown"}}, + rst = {sequence = {"pandoc"}, options = {input_format = "rst"}}, +} + + +local function execute_sequence(sequence, arg, make) + -- keep track of all generated tmp files + local temp_files = {} + -- the temporary file for the current compilation step + -- should become the tex_file for the next one. It doesn't + -- matter that it isn't TeX file in some cases + local previous_temp + for _, cmd_name in ipairs(sequence) do + local tmp_name = os.tmpname() + temp_files[#temp_files+1] = tmp_name + -- make the temp file name accessible to the executed commands + arg.tmp_file = tmp_name + -- the current temporary file should become tex_file in the next step + -- in the first execution of the compilation sequence we will use the + -- actual input file name + arg.tex_file = previous_temp or arg.tex_file + previous_temp = tmp_name + -- get the command to execute + local cmd = commands[cmd_name] + -- fill the command template with make4ht arguments and execute + local command = cmd.command % arg + log:info(command) + mkutils.execute(command) + end + return temp_files +end + +local function get_preprocessing_pipeline(input_file) + -- detect the file extension + local extension = input_file:match("%.(.-)$") + if not extension then return nil, "Cannot get extension: " .. input_file end + -- the table with file actions is case insensitive + -- the extension is converted to lowercase in order + -- to support both .rnw and .Rnw + extension = string.lower(extension) + local matched = filetypes[extension] + if not matched then return nil, "Unsupported extension: " .. extension end + return matched +end + +-- join the make4ht params and command options tables +local function make_options(arg, command_options) + local options = {} + local command_options = command_options or {} + for k,v in pairs(arg) do options[k] = v end + for k,v in pairs(command_options) do options[k] = v end + return options +end + +M.modify_build = function(make) + + -- get access to the main argumens + local arg = make.params + -- get the execution sequence for the input format + local matched, msg = get_preprocessing_pipeline(arg.tex_file) + if not matched then + log:error("preprocess_input error: ".. msg) + return + end + -- prepare options + local options = make_options(arg, matched.options) + -- run the execution sequence + local temp_files = execute_sequence(matched.sequence or {}, options, make) + -- the last temporary file contains the actual TeX file + local last_temp_file = temp_files[#temp_files] + -- remove the intermediate temp files + if #temp_files > 2 then + for i = 1, #temp_files - 1 do + log:debug("Removing temporary file", temp_files[i]) + os.remove(temp_files[i]) + end + end + if last_temp_file then + -- update all commands in the .mk4 file with the temp file as tex_file + local update_params = function(cmd) + local params = cmd.params + params.tex_file = last_temp_file + params.is_tmp_file = true + end + for _, cmd in ipairs(make.build_seq) do + update_params(cmd) + end + -- also update the main params + update_params(make) + end + return make +end + +return M diff --git a/support/make4ht/extensions/make4ht-ext-staticsite.lua b/support/make4ht/extensions/make4ht-ext-staticsite.lua new file mode 100644 index 0000000000..a4204bc173 --- /dev/null +++ b/support/make4ht/extensions/make4ht-ext-staticsite.lua @@ -0,0 +1,136 @@ +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", 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 diff --git a/support/make4ht/extensions/make4ht-ext-tidy.lua b/support/make4ht/extensions/make4ht-ext-tidy.lua new file mode 100644 index 0000000000..b381a05a8f --- /dev/null +++ b/support/make4ht/extensions/make4ht-ext-tidy.lua @@ -0,0 +1,58 @@ +local M = {} + +local log = logging.new "tidy" +function M.test(format) + if format == "odt" then return false end + return true +end + +local empty_elements = { + area=true, + base=true, + br=true, + col=true, + embed=true, + hr=true, + img=true, + input=true, + keygen=true, + link=true, + meta=true, + param=true, + source=true, + track=true, + wbr=true, +} + +-- LuaXML cannot read HTML with unclosed tags (like ) +-- Tidy removes end slashes in the HTML output, so +-- this function will add them back +local function close_tags(s) + return s:gsub("<(%w+)([^>]-)>", function(tag, rest) + local endslash = "" + if empty_elements[tag] then endslash = " /" end + return string.format("<%s%s%s>", tag, rest, endslash) + end) +end + + + +function M.modify_build(make) + make:match("html$", function(filename, par) + local settings = get_filter_settings "tidy" or {} + par.options = par.options or settings.options or "-utf8 -w 512 -ashtml -q" + local command = "tidy ${options} ${filename}" % par + log:info("running tidy: ".. command) + -- os.execute(command) + local run = io.popen(command, "r") + local result = run:read("*all") + run:close() + result = close_tags(result) + local f = io.open(filename, "w") + f:write(result) + f:close() + end) + return make +end + +return M diff --git a/support/make4ht/extensions/mathjaxnode.lua b/support/make4ht/extensions/mathjaxnode.lua deleted file mode 100644 index cbad897d4e..0000000000 --- a/support/make4ht/extensions/mathjaxnode.lua +++ /dev/null @@ -1,16 +0,0 @@ -local M = {} - - -local filter = require "make4ht-filter" -function M.test(format) - if format == "odt" then return false end - return true -end - -function M.modify_build(make) - local mathjax = filter { "mathjaxnode"} - make:match("html$",mathjax) - return make -end - -return M diff --git a/support/make4ht/extensions/odttemplate.lua b/support/make4ht/extensions/odttemplate.lua deleted file mode 100644 index 3b0af2a699..0000000000 --- a/support/make4ht/extensions/odttemplate.lua +++ /dev/null @@ -1,16 +0,0 @@ -local M = {} - -local filter = require "make4ht-filter" - --- this extension only works for the ODT format -M.test = function(format) - return format=="odt" -end - -M.modify_build = function(make) - local process = filter {"odttemplate"} - make:match("4oy$", process) - return make -end - -return M diff --git a/support/make4ht/extensions/preprocess_input.lua b/support/make4ht/extensions/preprocess_input.lua deleted file mode 100644 index 3155a8a781..0000000000 --- a/support/make4ht/extensions/preprocess_input.lua +++ /dev/null @@ -1,108 +0,0 @@ --- preprocess R literate sources or Markdown files to LaTeX -local M = {} -local log = logging.new "preprocess_input" -local mkutils = require "mkutils" - -local commands = { - knitr = { command = 'Rscript -e "library(knitr); knit(\'${tex_file}\', output=\'${tmp_file}\')"'}, - pandoc = { command = 'pandoc -f ${input_format} -s -o \'${tmp_file}\' -t latex \'${tex_file}\''} -} -local filetypes = { - rnw = {sequence = {"knitr"} }, - rtex = {sequence = {"knitr"}}, - rmd = {sequence = {"knitr", "pandoc"}, options = {input_format = "markdown"}}, - rrst = {sequence = {"knitr", "pandoc"}, options = {input_format = "rst"}}, - md = {sequence = {"pandoc"}, options = {input_format = "markdown"}}, - rst = {sequence = {"pandoc"}, options = {input_format = "rst"}}, -} - - -local function execute_sequence(sequence, arg, make) - -- keep track of all generated tmp files - local temp_files = {} - -- the temporary file for the current compilation step - -- should become the tex_file for the next one. It doesn't - -- matter that it isn't TeX file in some cases - local previous_temp - for _, cmd_name in ipairs(sequence) do - local tmp_name = os.tmpname() - temp_files[#temp_files+1] = tmp_name - -- make the temp file name accessible to the executed commands - arg.tmp_file = tmp_name - -- the current temporary file should become tex_file in the next step - -- in the first execution of the compilation sequence we will use the - -- actual input file name - arg.tex_file = previous_temp or arg.tex_file - previous_temp = tmp_name - -- get the command to execute - local cmd = commands[cmd_name] - -- fill the command template with make4ht arguments and execute - local command = cmd.command % arg - log:info(command) - mkutils.execute(command) - end - return temp_files -end - -local function get_preprocessing_pipeline(input_file) - -- detect the file extension - local extension = input_file:match("%.(.-)$") - if not extension then return nil, "Cannot get extension: " .. input_file end - -- the table with file actions is case insensitive - -- the extension is converted to lowercase in order - -- to support both .rnw and .Rnw - extension = string.lower(extension) - local matched = filetypes[extension] - if not matched then return nil, "Unsupported extension: " .. extension end - return matched -end - --- join the make4ht params and command options tables -local function make_options(arg, command_options) - local options = {} - local command_options = command_options or {} - for k,v in pairs(arg) do options[k] = v end - for k,v in pairs(command_options) do options[k] = v end - return options -end - -M.modify_build = function(make) - - -- get access to the main argumens - local arg = make.params - -- get the execution sequence for the input format - local matched, msg = get_preprocessing_pipeline(arg.tex_file) - if not matched then - log:error("preprocess_input error: ".. msg) - return - end - -- prepare options - local options = make_options(arg, matched.options) - -- run the execution sequence - local temp_files = execute_sequence(matched.sequence or {}, options, make) - -- the last temporary file contains the actual TeX file - local last_temp_file = temp_files[#temp_files] - -- remove the intermediate temp files - if #temp_files > 2 then - for i = 1, #temp_files - 1 do - log:debug("Removing temporary file", temp_files[i]) - os.remove(temp_files[i]) - end - end - if last_temp_file then - -- update all commands in the .mk4 file with the temp file as tex_file - local update_params = function(cmd) - local params = cmd.params - params.tex_file = last_temp_file - params.is_tmp_file = true - end - for _, cmd in ipairs(make.build_seq) do - update_params(cmd) - end - -- also update the main params - update_params(make) - end - return make -end - -return M diff --git a/support/make4ht/extensions/staticsite.lua b/support/make4ht/extensions/staticsite.lua deleted file mode 100644 index a4204bc173..0000000000 --- a/support/make4ht/extensions/staticsite.lua +++ /dev/null @@ -1,136 +0,0 @@ -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", 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 diff --git a/support/make4ht/extensions/tidy.lua b/support/make4ht/extensions/tidy.lua deleted file mode 100644 index b381a05a8f..0000000000 --- a/support/make4ht/extensions/tidy.lua +++ /dev/null @@ -1,58 +0,0 @@ -local M = {} - -local log = logging.new "tidy" -function M.test(format) - if format == "odt" then return false end - return true -end - -local empty_elements = { - area=true, - base=true, - br=true, - col=true, - embed=true, - hr=true, - img=true, - input=true, - keygen=true, - link=true, - meta=true, - param=true, - source=true, - track=true, - wbr=true, -} - --- LuaXML cannot read HTML with unclosed tags (like ) --- Tidy removes end slashes in the HTML output, so --- this function will add them back -local function close_tags(s) - return s:gsub("<(%w+)([^>]-)>", function(tag, rest) - local endslash = "" - if empty_elements[tag] then endslash = " /" end - return string.format("<%s%s%s>", tag, rest, endslash) - end) -end - - - -function M.modify_build(make) - make:match("html$", function(filename, par) - local settings = get_filter_settings "tidy" or {} - par.options = par.options or settings.options or "-utf8 -w 512 -ashtml -q" - local command = "tidy ${options} ${filename}" % par - log:info("running tidy: ".. command) - -- os.execute(command) - local run = io.popen(command, "r") - local result = run:read("*all") - run:close() - result = close_tags(result) - local f = io.open(filename, "w") - f:write(result) - f:close() - end) - return make -end - -return M -- cgit v1.2.3