summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/scripts/make4ht
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2019-11-01 21:00:21 +0000
committerKarl Berry <karl@freefriends.org>2019-11-01 21:00:21 +0000
commitfdb7d0585af6b9054e895d6f3047766f799b6098 (patch)
tree59e8b2c6971d1fb91d08250283dfa74589869d2d /Master/texmf-dist/scripts/make4ht
parent1eea7ddd33803c5945bc4b2b2654c960d42aa0c2 (diff)
make4ht (1nov19)
git-svn-id: svn://tug.org/texlive/trunk@52603 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/scripts/make4ht')
-rw-r--r--Master/texmf-dist/scripts/make4ht/domfilters/make4ht-aeneas.lua3
-rw-r--r--Master/texmf-dist/scripts/make4ht/domfilters/make4ht-collapsetoc.lua198
-rw-r--r--Master/texmf-dist/scripts/make4ht/domfilters/make4ht-joincharacters.lua8
-rw-r--r--Master/texmf-dist/scripts/make4ht/domfilters/make4ht-joincolors.lua3
-rw-r--r--Master/texmf-dist/scripts/make4ht/domfilters/make4ht-odtimagesize.lua3
-rw-r--r--Master/texmf-dist/scripts/make4ht/domfilters/make4ht-odtpartable.lua9
-rw-r--r--Master/texmf-dist/scripts/make4ht/domfilters/make4ht-tablerows.lua58
-rw-r--r--Master/texmf-dist/scripts/make4ht/extensions/common_domfilters.lua29
-rw-r--r--Master/texmf-dist/scripts/make4ht/extensions/dvisvgm_hashes.lua7
-rw-r--r--Master/texmf-dist/scripts/make4ht/extensions/preprocess_input.lua108
-rw-r--r--Master/texmf-dist/scripts/make4ht/extensions/staticsite.lua3
-rw-r--r--Master/texmf-dist/scripts/make4ht/extensions/tidy.lua3
-rw-r--r--Master/texmf-dist/scripts/make4ht/filters/make4ht-domfilter.lua7
-rw-r--r--Master/texmf-dist/scripts/make4ht/filters/make4ht-entities-to-unicode.lua8
-rw-r--r--Master/texmf-dist/scripts/make4ht/filters/make4ht-mathjaxnode.lua11
-rw-r--r--Master/texmf-dist/scripts/make4ht/filters/make4ht-staticsite.lua6
-rw-r--r--Master/texmf-dist/scripts/make4ht/filters/make4ht-svg-height.lua4
-rw-r--r--Master/texmf-dist/scripts/make4ht/formats/docbook.lua3
-rw-r--r--Master/texmf-dist/scripts/make4ht/formats/odt.lua23
-rwxr-xr-xMaster/texmf-dist/scripts/make4ht/make4ht32
-rwxr-xr-xMaster/texmf-dist/scripts/make4ht/make4ht-errorlogparser.lua97
-rwxr-xr-xMaster/texmf-dist/scripts/make4ht/make4ht-htlatex.lua75
-rwxr-xr-xMaster/texmf-dist/scripts/make4ht/make4ht-indexing.lua190
-rwxr-xr-xMaster/texmf-dist/scripts/make4ht/make4ht-lib.lua29
-rwxr-xr-xMaster/texmf-dist/scripts/make4ht/make4ht-logging.lua105
-rwxr-xr-xMaster/texmf-dist/scripts/make4ht/make4ht-xtpipes.lua15
-rwxr-xr-xMaster/texmf-dist/scripts/make4ht/mkparams.lua134
-rwxr-xr-xMaster/texmf-dist/scripts/make4ht/mkutils.lua131
28 files changed, 1114 insertions, 188 deletions
diff --git a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-aeneas.lua b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-aeneas.lua
index 0b93c958404..4a21c893323 100644
--- a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-aeneas.lua
+++ b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-aeneas.lua
@@ -5,6 +5,7 @@
--
local cssquery = require "luaxml-cssquery"
local mkutils = require "mkutils"
+local log = logging.new "aeneas"
-- Table of CSS selectors to be skipped.
local skip_elements = { "math", "svg"}
@@ -111,7 +112,7 @@ local function aeneas(dom, par)
then
local idtitle
idtitle, id = make_id(id, id_prefix)
- print(el._name, first_child._text)
+ log:debug(el._name, first_child._text)
el:set_attribute("id", idtitle)
return el
end
diff --git a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-collapsetoc.lua b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-collapsetoc.lua
new file mode 100644
index 00000000000..0b77b9dbbba
--- /dev/null
+++ b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-collapsetoc.lua
@@ -0,0 +1,198 @@
+local domobject = require "luaxml-domobject"
+
+local filter = require "make4ht-filter"
+local log = logging.new "collapsetoc"
+
+
+local toc_levels = {"partToc", "chapterToc", "sectionToc", "subsectionToc", "subsubsectionToc"}
+
+local debug_print = function(...) log:debug(...) end
+
+
+-- return toc element type and it's id
+local function get_id(el)
+ local name = el:get_attribute "class"
+ local id
+ local a = el:query_selector "a" or {}
+ local first = a[1]
+ if first then
+ local href = first:get_attribute "href"
+ id = href:match("#(.+)$")
+ end
+ return name, id
+end
+
+local function remove_sections(part_elements, currentpart)
+ -- we need to remove toc entries from the previous part if the
+ -- current document isn't part of it
+ if currentpart == false then
+ for _, part in ipairs(part_elements) do
+ part:remove_node()
+ end
+ end
+end
+
+local function make_toc_selector(toc_levels)
+ local level_classes = {}
+ for _, l in ipairs(toc_levels) do
+ level_classes[#level_classes+1] = "." .. l
+ end
+ return table.concat(level_classes, ", ")
+end
+
+local function find_toc_levels(toc)
+ -- find toc levels used in the document
+ -- it ecpects that sectioning levels appears in the TOC in the descending order
+ local levels, used = {}, {}
+ local level = 1
+ -- we still expect the standard class names
+ local toc_selector = make_toc_selector(toc_levels)
+ for _, el in ipairs(toc:query_selector(toc_selector)) do
+ local class = el:get_attribute("class")
+ if not used[class] then
+ table.insert(levels, class)
+ used[class] = level
+ level = level + 1
+ end
+ end
+ return levels, used
+end
+
+local function remove_levels(toc, matched_ids)
+ -- sort the matched sections according to their levels
+ local levels, level_numbers = find_toc_levels(toc)
+ debug_print("remove levels", #levels)
+ -- for _, level in ipairs(levels) do
+ -- print(level, level_numbers[level], matched_ids[level])
+ -- end
+ local keep_branch = false
+ local matched_levels = {}
+ local toc_selector = make_toc_selector(toc_levels)
+ for _, el in ipairs(toc:query_selector(toc_selector)) do
+ local name, id = get_id(el)
+ -- get the current toc hiearchy level
+ local level = level_numbers[name]
+ -- get the matched id for the current level
+ local level_id = matched_ids[name]
+ local matched = level_id == id
+ local remove = true
+ -- we will use this for toc elements at lower hiearchy than is the top sectioning level on the page
+ if matched then keep_branch = true end
+ -- find the parent level to the current section level
+ local parent_level = toc_levels[level - 1]
+ local parent_matched = matched_levels[parent_level]
+ if matched then
+ debug_print("match",name, id, level_id, level, #levels)
+ keep_branch = true
+ remove = false
+ elseif level==1 then
+ -- don't remove the top level
+ debug_print("part",name, id, level_id, level)
+ remove = false
+ matched_levels = {}
+ if not matched then keep_branch = false end
+ elseif keep_branch then
+ -- if level >= (#levels - 1) then
+ if level > matched_ids._levels then
+ debug_print("level",name, id, level_id, level, parent_level, parent_matched)
+ remove = false
+ elseif matched_ids.ids[id] then
+ debug_print("matched id",name, id, level_id, level, parent_level, parent_matched)
+ remove = false
+ elseif parent_matched then
+ debug_print("parent_matched",name, id, level_id, level, parent_level, parent_matched)
+ keep_branch = false
+ remove = false
+ end
+ -- else
+ -- print("remove", name, id, level_id, level, #matched_ids)
+ -- end
+ elseif parent_matched then
+ debug_print("parent_matched alternative",name, id, level_id, level, parent_level, parent_matched)
+ remove = false
+ else
+ debug_print("else",name, id, level_id, level, keep_branch)
+ keep_branch = false
+ end
+ matched_levels[name] = matched
+ if remove then
+ el:remove_node()
+ --print(name,id, level_id, matched)
+ end
+ end
+
+end
+
+
+
+
+
+-- local process = filter{ function(s)
+ -- local dom = domobject.parse(s)
+local function collapse_toc(dom, par)
+ -- set options
+ local options = get_filter_settings "collapsetoc"
+ local toc_query = par.toc_query or options.toc_query or ".tableofcontents"
+ local title_query = par.title_query or options.title_query or ".partHead a, .chapterHead a, .sectionHead a, .subsectionHead a"
+ toc_levels = par.toc_levels or options.toc_levels or toc_levels
+ -- keep track of current id of each sectioning level
+ local current_ids, matched_ids = {}, {_levels = 0, ids = {}}
+ -- search sectioning elements
+ local titles = dom:query_selector(title_query)
+ local section_ids = {}
+ for _, x in ipairs(titles) do
+ -- get their id attributes and save them in a table
+ section_ids[#section_ids+1] = x:get_attribute("id")
+ end
+
+ -- we need to retrieve the first table of contents
+ local toctables = dom:query_selector(toc_query) or {}
+ -- process only when we got a TOC
+ debug_print("toc query", toc_query, #toctables)
+ if #toctables > 0 then
+ local tableofcontents = toctables[1]
+ -- all toc entries are in span elements
+ local toc = tableofcontents:query_selector("span")
+ local currentpart = false
+ local part_elements = {}
+ for _, el in ipairs(toc) do
+ -- get sectioning level and id of the current TOC entry
+ local name, id = get_id(el)
+ -- set the id of the current sectioning level
+ current_ids[name] = id
+ for _, sectid in ipairs(section_ids) do
+ -- detect if the current TOC entry match some sectioning element in the current document
+ if id == sectid then
+ currentpart = true
+ -- save the current id as a matched id
+ matched_ids.ids[id] = true
+ -- copy the TOC hiearchy for the current toc level
+ for i, level in ipairs(toc_levels) do
+ -- print("xxx",i, level, current_ids[level])
+ matched_ids[level] = current_ids[level]
+ -- set the maximum matched level
+ if i > matched_ids._levels then matched_ids._levels = i end
+ if level == name then break end
+ end
+ debug_print("match", id)
+ end
+ end
+ end
+ remove_levels(tableofcontents, matched_ids)
+
+ -- remove sections from the last part
+ -- remove_sections(part_elements,currentpart)
+ -- remove unneeded br elements
+ local br = tableofcontents:query_selector("br")
+ for _, el in ipairs(br) do el:remove_node() end
+ -- remove unneded whitespace
+ for _, el in ipairs(tableofcontents:get_children()) do
+ if el:is_text() then el:remove_node() end
+ end
+ end
+ return dom
+end
+
+return collapse_toc
+
+-- Make:match("html$", process)
diff --git a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-joincharacters.lua b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-joincharacters.lua
index 99d3058d7dd..30ed6e1382a 100644
--- a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-joincharacters.lua
+++ b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-joincharacters.lua
@@ -1,4 +1,4 @@
-local charclases = {
+local charclasses = {
span=true,
mn = true,
}
@@ -8,7 +8,7 @@ local function join_characters(obj,par)
-- tex4ht to just one object.
local par = par or {}
local options = get_filter_settings "joincharacters"
- local charclases = options.charclases or par.charclases or charclases
+ local charclasses = options.charclasses or par.charclasses or charclasses
obj:traverse_elements(function(el)
local get_name = function(curr)
@@ -18,7 +18,7 @@ local function join_characters(obj,par)
return next_el:get_attribute("class")
end
local is_span = function(next_el)
- return charclases[get_name(next_el)]
+ return charclasses[get_name(next_el)]
end
local function get_next(curr, class)
@@ -33,7 +33,7 @@ local function join_characters(obj,par)
end
end
-- loop over all elements and test if the current element is in a list of
- -- processed elements (charclases)
+ -- processed elements (charclasses)
if is_span(el) then
local next_el = get_next(el)
-- loop over the following elements and test whether they are of the same type
diff --git a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-joincolors.lua b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-joincolors.lua
index 94a3a054e61..730f66a7a0d 100644
--- a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-joincolors.lua
+++ b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-joincolors.lua
@@ -1,4 +1,5 @@
local cssfiles = {}
+local log = logging.new "joincolors"
-- keep mapping between span ids and colors
@@ -45,7 +46,7 @@ local function process_css_files(dom)
for _, el in ipairs(dom:query_selector("link")) do
local href = el:get_attribute("href") or ""
if not cssfiles[href] and href:match("css$") then
- print("Load CSS file ", href)
+ log:debug("Load CSS file ", href)
cssfiles[href] = true
process_css(href)
end
diff --git a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-odtimagesize.lua b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-odtimagesize.lua
index 4ce8f0d92ea..2b87372fdb1 100644
--- a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-odtimagesize.lua
+++ b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-odtimagesize.lua
@@ -1,3 +1,4 @@
+local log = logging.new "odtimagesize"
-- set correct dimensions to frames around images
return function(dom)
local frames = dom:query_selector("draw|frame")
@@ -9,7 +10,7 @@ return function(dom)
local height = image:get_attribute("svg:height")
if widht then frame:set_attribute("svg:width", width) end
if height then frame:set_attribute("svg:height", height) end
- print("image dimensions", width, height)
+ log:debug("image dimensions", width, height)
end
end
return dom
diff --git a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-odtpartable.lua b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-odtpartable.lua
new file mode 100644
index 00000000000..f4e84b55d96
--- /dev/null
+++ b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-odtpartable.lua
@@ -0,0 +1,9 @@
+-- find all tables inside paragraphs, replace the found paragraphs with the child table
+return function(dom)
+ for _,table in ipairs(dom:query_selector("text|p table|table")) do
+ -- replace the paragraph by its child element
+ local parent = table:get_parent()
+ parent:replace_node(table)
+ end
+ return dom
+end
diff --git a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-tablerows.lua b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-tablerows.lua
new file mode 100644
index 00000000000..155c24529ac
--- /dev/null
+++ b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-tablerows.lua
@@ -0,0 +1,58 @@
+local log = logging.new ("tablerows")
+return function(dom)
+ local is_empty_row = function(row)
+ local not_empty = false
+ local element_count = 0
+ -- ignore hline rows
+ local row_class = row:get_attribute("class")
+ if row_class == "hline" or row_class == "cline" then return false end
+ -- detect if the row contain only one empty child
+ for _,child in ipairs(row:get_children() or {}) do
+ if child:is_element() then
+ element_count = element_count + 1
+ -- empty rows contain only one element, it is not empty otherwise
+ if element_count > 1 then return false end
+ -- detect if it contains only whitespace
+ not_empty = child:get_text():gsub("%s","") ~= "" or not_empty
+ end
+ end
+ -- print("element count", element_count, not_empty)
+ return element_count == 1 and not_empty == false
+ end
+ local is_not_styled = function(row, css)
+ -- get the id attribute and escape it, so it can be used in regexp
+ local id = row:get_attribute("id")
+ if not id then return true end -- no styling without id
+ local search_term = "%#" .. id:gsub("%-", "%%-")
+ -- if the CSS file contains the row id (<td> elements can also have id
+ -- that matches this pattern, so we should keep the row if we match them too)
+ return not css:match(search_term)
+ end
+ local load_css_files = function()
+ -- the empty rows can be styled using CSS, for example configuration for
+ -- Booktabs does that. We shouldn't remove such rows.
+ local cssfiles = {}
+ for _, link in ipairs(dom:query_selector("head link")) do
+ local src = link:get_attribute("href")
+ if src then
+ local f = io.open(src, "r")
+ if f then
+ local contents = f:read("*all")
+ f:close()
+ table.insert(cssfiles, contents)
+ end
+ end
+ end
+ return table.concat(cssfiles, "\n")
+ end
+ local css = load_css_files()
+ for _, tbl in ipairs(dom:query_selector("table")) do
+ -- find the empty rows
+ for _, row in ipairs(tbl:query_selector("tr")) do
+ if is_empty_row(row) and is_not_styled(row, css) then row:remove_node() end
+ end
+
+ end
+ return dom
+end
+
diff --git a/Master/texmf-dist/scripts/make4ht/extensions/common_domfilters.lua b/Master/texmf-dist/scripts/make4ht/extensions/common_domfilters.lua
index 7c9a2dfaea4..9399492d907 100644
--- a/Master/texmf-dist/scripts/make4ht/extensions/common_domfilters.lua
+++ b/Master/texmf-dist/scripts/make4ht/extensions/common_domfilters.lua
@@ -1,25 +1,34 @@
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)
- if format == "odt" then return false end
+ current_format = format
+ -- if format == "odt" then return false end
return true
end
function M.modify_build(make)
- local process = filter {"fixinlines", "idcolons", "joincharacters"}
- 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
+ -- 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
diff --git a/Master/texmf-dist/scripts/make4ht/extensions/dvisvgm_hashes.lua b/Master/texmf-dist/scripts/make4ht/extensions/dvisvgm_hashes.lua
index 83010ac388f..87f58abd57c 100644
--- a/Master/texmf-dist/scripts/make4ht/extensions/dvisvgm_hashes.lua
+++ b/Master/texmf-dist/scripts/make4ht/extensions/dvisvgm_hashes.lua
@@ -1,6 +1,7 @@
local dvireader = require "make4ht-dvireader"
local mkutils = require "mkutils"
local filter = require "make4ht-filter"
+local log = logging.new "dvisvgm_hashes"
local dvisvgm_par = {}
@@ -149,7 +150,7 @@ 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)
- print(command)
+ log:info(command)
os.execute(command)
local generated_pages = {}
for _, dvisvgmlog in ipairs(logs) do
@@ -184,7 +185,7 @@ local function get_dvi_pages(arg)
local output_name = make_hashed_name(arg.input, hash)
output_map[tex4ht_name] = output_name
if not mkutils.file_exists(output_name) then
- print(output_name)
+ log:debug("output file: ".. output_name)
to_convert[#to_convert+1] = page
end
end
@@ -246,7 +247,7 @@ function M.modify_build(make)
function(str)
return str:gsub('src="([^"]+)', function(filename)
local newname = output_map[filename] or filename
- print("newname", newname)
+ log:debug("newname", newname)
return 'src="'.. newname
end)
end
diff --git a/Master/texmf-dist/scripts/make4ht/extensions/preprocess_input.lua b/Master/texmf-dist/scripts/make4ht/extensions/preprocess_input.lua
new file mode 100644
index 00000000000..3155a8a7810
--- /dev/null
+++ b/Master/texmf-dist/scripts/make4ht/extensions/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/Master/texmf-dist/scripts/make4ht/extensions/staticsite.lua b/Master/texmf-dist/scripts/make4ht/extensions/staticsite.lua
index fcb6c09e17d..a4204bc1733 100644
--- a/Master/texmf-dist/scripts/make4ht/extensions/staticsite.lua
+++ b/Master/texmf-dist/scripts/make4ht/extensions/staticsite.lua
@@ -1,6 +1,7 @@
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)
@@ -15,7 +16,7 @@ local function get_slug(settings)
local f = io.open(published_name, "r")
local readtime = f:read("*line")
time = tonumber(readtime)
- print("Already pubslished", slug)
+ log:info("Already pubslished", slug)
f:close()
else
-- escape
diff --git a/Master/texmf-dist/scripts/make4ht/extensions/tidy.lua b/Master/texmf-dist/scripts/make4ht/extensions/tidy.lua
index cf8ea9785a5..b381a05a8fb 100644
--- a/Master/texmf-dist/scripts/make4ht/extensions/tidy.lua
+++ b/Master/texmf-dist/scripts/make4ht/extensions/tidy.lua
@@ -1,5 +1,6 @@
local M = {}
+local log = logging.new "tidy"
function M.test(format)
if format == "odt" then return false end
return true
@@ -41,7 +42,7 @@ function M.modify_build(make)
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
- print("execute: ".. command)
+ log:info("running tidy: ".. command)
-- os.execute(command)
local run = io.popen(command, "r")
local result = run:read("*all")
diff --git a/Master/texmf-dist/scripts/make4ht/filters/make4ht-domfilter.lua b/Master/texmf-dist/scripts/make4ht/filters/make4ht-domfilter.lua
index 27d9ed871d1..f6df769d60c 100644
--- a/Master/texmf-dist/scripts/make4ht/filters/make4ht-domfilter.lua
+++ b/Master/texmf-dist/scripts/make4ht/filters/make4ht-domfilter.lua
@@ -1,6 +1,7 @@
local filter_lib = require "make4ht-filterlib"
local dom = require "luaxml-domobject"
local mkutils = require "mkutils"
+local log = logging.new "domfilter"
local function load_filter(filtername)
return require("domfilters.make4ht-"..filtername)
@@ -42,8 +43,8 @@ local function filter(filters, name)
return dom.parse(input)
end)
if not status then
- print("DOM parsing of " .. filename .. " failed:")
- print(domobject)
+ log:warning("DOM parsing of " .. filename .. " failed:")
+ log:warning(domobject)
return nil, "DOM parsing failed"
end
for _,f in pairs(sequence) do
@@ -53,7 +54,7 @@ local function filter(filters, name)
if output then
filter_lib.save_input_file(filename, output)
else
- print("DOM filter failed on ".. filename)
+ log:warning("DOM filter failed on ".. filename)
end
-- mark the filename as processed
processed_files[filename] = true
diff --git a/Master/texmf-dist/scripts/make4ht/filters/make4ht-entities-to-unicode.lua b/Master/texmf-dist/scripts/make4ht/filters/make4ht-entities-to-unicode.lua
index fb921a631a3..4bf106a79fc 100644
--- a/Master/texmf-dist/scripts/make4ht/filters/make4ht-entities-to-unicode.lua
+++ b/Master/texmf-dist/scripts/make4ht/filters/make4ht-entities-to-unicode.lua
@@ -6,10 +6,12 @@ local disabled = { ["&"] = "&amp;", ["<"] = "&lt;", [">"] = "&gt;"}
return function(content)
local content = content:gsub("%&%#x([A-Fa-f0-9]+);", function(entity)
-- convert hexadecimal entity to Unicode
- local newchar = utfchar(tonumber(entity, 16))
+ local char_number = tonumber(entity, 16)
+ -- fix for non-breaking spaces, LO cannot open file when they are present as Unicode
+ if char_number == 160 then return "&#xA0;" end
+ local newchar = utfchar(char_number)
-- we don't want to break XML validity with forbidden characters
return disabled[newchar] or newchar
end)
- -- the non-breaking space character cause issues in the ODT opening
- return content:gsub(string.char(160), "&#xA0;")
+ return content
end
diff --git a/Master/texmf-dist/scripts/make4ht/filters/make4ht-mathjaxnode.lua b/Master/texmf-dist/scripts/make4ht/filters/make4ht-mathjaxnode.lua
index 2b453e4255b..748ecfd4839 100644
--- a/Master/texmf-dist/scripts/make4ht/filters/make4ht-mathjaxnode.lua
+++ b/Master/texmf-dist/scripts/make4ht/filters/make4ht-mathjaxnode.lua
@@ -1,4 +1,5 @@
local mkutils = require "mkutils"
+local log = logging.new("mathjaxnode")
-- other possible value is page2svg
local mathnodepath = "mjpage"
-- options for MathJax command
@@ -13,13 +14,13 @@ local cssfilename = "mathjax-chtml.css"
local function compile(text)
local tmpfile = os.tmpname()
- print("Compile using MathJax")
+ log:info("Compile using MathJax")
local command = mathnodepath .. " ".. options .. " > " .. tmpfile
- print(command)
+ log:info(command)
local commandhandle = io.popen(command,"w")
commandhandle:write(text)
commandhandle:close()
- print("Result written to: ".. tmpfile)
+ log:info("Result written to: ".. tmpfile)
local f = io.open(tmpfile)
local content = f:read("*all")
f:close()
@@ -53,7 +54,7 @@ local function use_fonts(css)
if not face:match("url%(") then return face end
-- print(face)
local family, filename = face:match(family_pattern)
- print(family, filename)
+ log:info("use font: ",family, filename)
local newfile = string.format("%s/%s.%s", fontdir, filename, fontformat)
Make:add_file(newfile)
return family_build:format(family, fontdir, filename, fontformat, fontformat)
@@ -89,6 +90,6 @@ return function(text, arguments)
save_css(cssfile, css)
Make:add_file(cssfile)
-- print(css)
- print(cssfile)
+ log:info("CSS file: " .. cssfile)
return newtext
end
diff --git a/Master/texmf-dist/scripts/make4ht/filters/make4ht-staticsite.lua b/Master/texmf-dist/scripts/make4ht/filters/make4ht-staticsite.lua
index 6378f0440aa..969d47ecaaa 100644
--- a/Master/texmf-dist/scripts/make4ht/filters/make4ht-staticsite.lua
+++ b/Master/texmf-dist/scripts/make4ht/filters/make4ht-staticsite.lua
@@ -1,4 +1,5 @@
local domobj = require "luaxml-domobject"
+local log = logging.new("staticsite")
-- save the header settings in YAML format
local function make_yaml(tbl, level)
local t = {}
@@ -69,7 +70,6 @@ local function get_header(tbl)
end
return function(s,par)
- print(os.getenv "blog_home")
local dom = domobj.parse(s)
local properties = {}
local head = dom:query_selector("head")[1]
@@ -84,7 +84,7 @@ return function(s,par)
properties.styles = styles
local metas = {}
for _, meta in ipairs(head:query_selector("meta")) do
- print(meta:serialize())
+ log:debug("parsed meta: " .. meta:serialize())
table.insert(metas, {charset= meta:get_attribute("charset"), content = meta:get_attribute("content"), property = meta:get_attribute("property"), name = meta:get_attribute("name")})
end
properties.meta = metas
@@ -92,7 +92,7 @@ return function(s,par)
local body = dom:query_selector("body")[1]
- print(get_header(properties))
+ log:debug(get_header(properties))
-- return s
return get_header(properties) .. body:serialize():gsub("<body.->", ""):gsub("</body>", "")
end
diff --git a/Master/texmf-dist/scripts/make4ht/filters/make4ht-svg-height.lua b/Master/texmf-dist/scripts/make4ht/filters/make4ht-svg-height.lua
index 44e98748ea9..bb9f8dbdc60 100644
--- a/Master/texmf-dist/scripts/make4ht/filters/make4ht-svg-height.lua
+++ b/Master/texmf-dist/scripts/make4ht/filters/make4ht-svg-height.lua
@@ -1,6 +1,8 @@
+local log = logging.new("svg-height")
-- Make:image("svg$", "dvisvgm -n -a -p ${page} -b preview -c 1.4,1.4 -s ${source} > ${output}")
+
local max = function(a,b)
return a > b and a or b
end
@@ -34,7 +36,7 @@ return function(svg)
max_height = get_max_height(path, max_height)
end
-- update the height only if the max_height is larger than height set in the SVG file
- print(max_height, height)
+ log:debug("max height and height", max_height, height)
if max_height > height then
svg = update_height(svg, max_height)
end
diff --git a/Master/texmf-dist/scripts/make4ht/formats/docbook.lua b/Master/texmf-dist/scripts/make4ht/formats/docbook.lua
index 9e5ffe9488b..3bd79eb83ed 100644
--- a/Master/texmf-dist/scripts/make4ht/formats/docbook.lua
+++ b/Master/texmf-dist/scripts/make4ht/formats/docbook.lua
@@ -6,6 +6,7 @@ local kpse = require "kpse"
local filter = require "make4ht-filter"
local domfilter = require "make4ht-domfilter"
local xtpipeslib = require "make4ht-xtpipes"
+local log = logging.new "docbook"
function M.prepare_parameters(settings, extensions)
settings.tex4ht_sty_par = settings.tex4ht_sty_par ..",docbook"
@@ -25,7 +26,7 @@ local function call_xtpipes(make)
make:match("xml$", matchfunction)
move_matches(make)
else
- print "Cannot locate xtpipes. Try to set TEXMFROOT variable to a root directory of your TeX distribution"
+ log:warning "Cannot locate xtpipes. Try to set TEXMFROOT variable to a root directory of your TeX distribution"
end
end
diff --git a/Master/texmf-dist/scripts/make4ht/formats/odt.lua b/Master/texmf-dist/scripts/make4ht/formats/odt.lua
index 64b8793e2a7..c515a154a1b 100644
--- a/Master/texmf-dist/scripts/make4ht/formats/odt.lua
+++ b/Master/texmf-dist/scripts/make4ht/formats/odt.lua
@@ -6,6 +6,7 @@ local kpse = require "kpse"
local filter = require "make4ht-filter"
local domfilter = require "make4ht-domfilter"
local xtpipeslib = require "make4ht-xtpipes"
+local log = logging.new "odt"
function M.prepare_parameters(settings, extensions)
@@ -23,9 +24,12 @@ Odtfile.__index = Odtfile
Odtfile.new = function(archivename)
local self = setmetatable({}, Odtfile)
- -- create temporary directory
+ -- create a temporary file
local tmpname = os.tmpname()
- tmpname = tmpname:match("([a-zA-Z0-9_%-]+)$")
+ -- remove a temporary file, we are interested only in the unique file name
+ os.remove(tmpname)
+ -- get the unique dir name
+ tmpname = tmpname:match("([a-zA-Z0-9_%-%.]+)$")
local status, msg = lfs.mkdir(tmpname)
if not status then return nil, msg end
-- make picture dir
@@ -68,10 +72,10 @@ function Odtfile:pack()
lfs.chdir(self.archivelocation)
-- make temporary mime type file
self:make_mimetype()
- os.execute(zip_command .. " -q0X " .. self.name .. " " .. self.mimetypename)
+ mkutils.execute(zip_command .. " -q0X " .. self.name .. " " .. self.mimetypename)
-- remove it, so the next command doesn't overwrite it
self:remove_mimetype()
- os.execute(zip_command .." -r " .. self.name .. " *")
+ mkutils.execute(zip_command .." -r " .. self.name .. " *")
lfs.chdir(currentdir)
mkutils.cp(self.archivelocation .. "/" .. self.name, self.name)
mkutils.delete_dir(self.archivelocation)
@@ -99,7 +103,7 @@ local function call_xtpipes(make)
move_matches(make)
move_matches(make)
else
- print "Cannot locate xtpipes. Try to set TEXMFROOT variable to a root directory of your TeX distribution"
+ log:warning "Cannot locate xtpipes. Try to set TEXMFROOT variable to a root directory of your TeX distribution"
end
end
@@ -111,7 +115,7 @@ local function prepare_output_files(lgfiles)
local group = groups[extension] or {}
table.insert(group, basename)
groups[extension] = group
- print(basename, extension)
+ log:debug("prepare output file", basename, extension)
end
return groups
end
@@ -130,7 +134,7 @@ function M.modify_build(make)
-- expanded in tex4ht.env in Miktex or Debian
call_xtpipes(make)
-- fix the image dimensions wrongly set by xtpipes
- local domfilters = domfilter {"t4htlinks"}
+ local domfilters = domfilter {"t4htlinks", "odtpartable"}
make:match("4oo$", domfilters)
-- execute it before xtpipes, because we don't want xtpipes to mess with t4htlink elements
move_matches(make)
@@ -138,9 +142,6 @@ function M.modify_build(make)
local fixentities = filter {"entities-to-unicode"}
make:match("4oo", fixentities)
make:match("4om", fixentities)
- -- execute fixentities as first
- move_matches(make)
- move_matches(make)
-- build the ODT file. This match must be executed as a last one
-- this will be executed as a first match, just to find the last filename
@@ -161,7 +162,7 @@ function M.modify_build(make)
local odtname = basename .. ".odt"
local odt,msg = Odtfile.new(odtname)
if not odt then
- print("Cannot create ODT file: " .. msg)
+ log:error("Cannot create ODT file: " .. msg)
end
-- helper function for simple file moving
local function move_file(group, dest)
diff --git a/Master/texmf-dist/scripts/make4ht/make4ht b/Master/texmf-dist/scripts/make4ht/make4ht
index 564bc6e7a04..b1ff84f7006 100755
--- a/Master/texmf-dist/scripts/make4ht/make4ht
+++ b/Master/texmf-dist/scripts/make4ht/make4ht
@@ -3,8 +3,10 @@
-- This package is subject of LPPL license, version 1.3
kpse.set_program_name("luatex")
-
-
+-- logging should be globally available
+logging = require "make4ht-logging"
+if os.type == "windows" then logging.use_colors = false end
+local log = logging.new("make4ht")
local make4ht = require("make4ht-lib")
local lapp = require("lapp-mk4")
local mkutils = require("mkutils")
@@ -13,7 +15,7 @@ local mk_config = require("make4ht-config")
-- args string is here just as sample, we dont pass it it to
-- mkparams.get_args() so default args string is used
local args = [[
-make4ht - build system for tex4ht
+make4ht - build system for TeX4ht
Usage:
make4ht [options] filename ["tex4ht.sty op." "tex4ht op." "t4ht op" "latex op"]
-c,--config (default xhtml) Custom config file
@@ -27,13 +29,16 @@ make4ht [options] filename ["tex4ht.sty op." "tex4ht op." "t4ht op" "latex op"]
-- set version number. the template should be replaced by the
-- actual version number by the build script
-local version = "v0.2g"
+local version = "v0.3"
mkparams.version_number = version
local args = mkparams.get_args()
local parameters = mkparams.process_args(args)
+log:status("Conversion started")
+log:status("Input file: " .. parameters.tex_file)
+
local mode = parameters.mode
local build_file = parameters.build_file
@@ -48,7 +53,7 @@ if allowed_output_formats[ output_format ] then
else
-- load html5 as default output format
if output_format then
- print("Cannot load output format: ".. output_format)
+ log:warning("Cannot load output format: ".. output_format)
end
formatter = mkutils.load_output_format("html5")
end
@@ -56,7 +61,7 @@ end
local configname = "make4ht"
local conffile = mk_config.find_config(configname) or mk_config.find_xdg_config(configname)
if conffile then
- print("Using configuration file: " .. conffile)
+ log:info("Using configuration file: " .. conffile)
mkutils.load_config(parameters, conffile)
end
local extensions = formatter.prepare_extensions(parameters.extensions)
@@ -96,15 +101,26 @@ end
-- allow output formats to modify the build process at the end
make = formatter.modify_build(make) or make
+make:match("tmp$", function(filename,params)
+ -- remove the temporary tex file created when the input comes from the standard input
+ if params.is_tmp_file then
+ log:info("removing temp file", params.tex_file)
+ os.remove(params.tex_file)
+ end
+ -- prevent copying of the temporary file to the outdir
+ return false,"tmp file" end
+)
-make:match("tmp$", function() return false,"tmp file" end)
make:match(".*",function(filename,par)
local outdir = '' --par["outdir"] and par["outdir"] .."/" or ''
if par['outdir'] ~= "" then outdir = par['outdir'] .. '/' end
- print("outdir: "..outdir)
+ log:info("outdir: "..outdir)
local outfilename = outdir .. filename
mkutils.copy(filename,outfilename)
return true
end)
make:run()
+
+log:status("Conversion finished")
+
diff --git a/Master/texmf-dist/scripts/make4ht/make4ht-errorlogparser.lua b/Master/texmf-dist/scripts/make4ht/make4ht-errorlogparser.lua
new file mode 100755
index 00000000000..b48957c6514
--- /dev/null
+++ b/Master/texmf-dist/scripts/make4ht/make4ht-errorlogparser.lua
@@ -0,0 +1,97 @@
+local m = {}
+
+local function get_filename(chunk)
+ local filename = chunk:match("([^\n^%(]+)")
+ local first = filename:match("^[%./\\]+")
+ if first then return filename end
+ return false
+end
+
+local function get_chunks(text)
+ -- parse log for particular included files
+ local chunks = {}
+ -- each file is enclosed in matching () brackets
+ local newtext = text:gsub("(%b())", function(a)
+ local chunk = string.sub(a,2,-2)
+ -- if no filename had been found in the chunk, it is probably not file chunk
+ -- so just return the original text
+ local filename = get_filename(chunk)
+ if not filename then return a end
+ local children, text = get_chunks(chunk)
+ table.insert(chunks, {filename = filename, text = text, children = children})
+ return ""
+ end)
+ return chunks, newtext
+end
+
+
+function print_chunks(chunks, level)
+ local level = level or 0
+ local indent = string.rep(" ", level)
+ for k,v in ipairs(chunks) do
+ print(indent .. (v.filename or "?"), string.len(v.text))
+ print_chunks(v.children, level + 1)
+ end
+end
+
+local function parse_errors(text)
+ local lines = {}
+ local errors = {}
+ local find_line_no = false
+ local error_lines = {}
+ for line in text:gmatch("([^\n]+)") do
+ lines[#lines+1] = line
+ end
+ for i = 1, #lines do
+ local line = lines[i]
+ -- error lines start with !
+ local err = line:match("^!(.+)")
+ -- error lines can be on following lines
+ -- the format is l.number
+ local lineno = line:match("^l%.([0-9]+)")
+ if err then
+ errors[#errors+1] = err
+ -- we didn't find error line number since previous error, insert
+ if find_line_no then
+ error_lines[#error_lines+1] = false
+ end
+ find_line_no = true
+ elseif lineno then
+ find_line_no = false
+ error_lines[#error_lines+1] = tonumber(lineno)
+ end
+ i = i + 1
+ end
+ return errors, error_lines
+end
+
+
+local function get_errors(chunks, errors)
+ local errors = errors or {}
+ for _, v in ipairs(chunks) do
+ local current_errors, error_lines = parse_errors(v.text)
+ for i, err in ipairs(current_errors) do
+ table.insert(errors, {filename = v.filename, error = err, line = error_lines[i] })
+ end
+ errors = get_errors(v.children, errors)
+ end
+ return errors
+end
+
+
+function m.parse(log)
+ local chunks, newtext = get_chunks(log)
+ -- save the unparsed text that contains system messages
+ table.insert(chunks, {text = newtext, children = {}})
+ -- print_chunks(chunks)
+ local errors = get_errors(chunks)
+ -- for _,v in ipairs(errors) do
+ -- print("error", v.filename, v.line, v.error)
+ -- end
+ return errors, chunks
+end
+
+
+m.print_chunks = print_chunks
+
+return m
diff --git a/Master/texmf-dist/scripts/make4ht/make4ht-htlatex.lua b/Master/texmf-dist/scripts/make4ht/make4ht-htlatex.lua
new file mode 100755
index 00000000000..214972e8bb9
--- /dev/null
+++ b/Master/texmf-dist/scripts/make4ht/make4ht-htlatex.lua
@@ -0,0 +1,75 @@
+local log = logging.new "htlatex"
+
+local error_logparser = require("make4ht-errorlogparser")
+
+local Make = Make or {}
+-- this function reads the LaTeX log file and tries to detect fatal errors in the compilation
+local function testlogfile(par)
+ local logfile = par.input .. ".log"
+ local f = io.open(logfile,"r")
+ if not f then
+ log:warning("Make4ht: cannot open log file "..logfile)
+ return 1
+ end
+ local content = f:read("*a")
+ -- test only the end of the log file, no need to run search functions on everything
+ local text = content:sub(-1256)
+ f:close()
+ -- parse log file for all errors in non-interactive modes
+ if par.interaction~="errorstopmode" then
+ -- the error log parsing can be slow, so detect errors first
+ if content:match("\n!") then
+ local errors, chunks = error_logparser.parse(content)
+ if #errors > 0 then
+ log:error("Compilation errors in the htlatex run")
+ log:error("Filename", "Line", "Message")
+ for _, err in ipairs(errors) do
+ log:error(err.filename or "?", err.line or "?", err.error)
+ end
+ end
+ end
+ end
+ -- test for fatal errors
+ if text:match("No pages of output") or text:match("TeX capacity exceeded, sorry") or text:match("That makes 100 errors") or text:match("Emergency stop") then return 1 end
+ return 0
+end
+
+
+-- Make this function available in the build files
+Make.testlogfile = testlogfile
+--env.Make:add("htlatex", "${htlatex} ${latex_par} '\\\makeatletter\\def\\HCode{\\futurelet\\HCode\\HChar}\\def\\HChar{\\ifx\"\\HCode\\def\\HCode\"##1\"{\\Link##1}\\expandafter\\HCode\\else\\expandafter\\Link\\fi}\\def\\Link#1.a.b.c.{\\g@addto@macro\\@documentclasshook{\\RequirePackage[#1,html]{tex4ht}\\let\\HCode\\documentstyle\\def\\documentstyle{\\let\\documentstyle\\HCode\\expandafter\\def\\csname tex4ht\\endcsname{#1,html}\\def\\HCode####1{\\documentstyle[tex4ht,}\\@ifnextchar[{\\HCode}{\\documentstyle[tex4ht]}}}\\makeatother\\HCode '${config}${tex4ht_sty_par}'.a.b.c.\\input ' ${input}")
+
+-- template for calling LaTeX with tex4ht loaded
+Make.latex_command = "${htlatex} --interaction=${interaction} ${latex_par} '\\makeatletter"..
+"\\def\\HCode{\\futurelet\\HCode\\HChar}\\def\\HChar{\\ifx\"\\HCode"..
+"\\def\\HCode\"##1\"{\\Link##1}\\expandafter\\HCode\\else"..
+"\\expandafter\\Link\\fi}\\def\\Link#1.a.b.c.{\\g@addto@macro"..
+"\\@documentclasshook{\\RequirePackage[#1,html]{tex4ht}${packages}}"..
+"\\let\\HCode\\documentstyle\\def\\documentstyle{\\let\\documentstyle"..
+"\\HCode\\expandafter\\def\\csname tex4ht\\endcsname{#1,html}\\def"..
+"\\HCode####1{\\documentstyle[tex4ht,}\\@ifnextchar[{\\HCode}{"..
+"\\documentstyle[tex4ht]}}}\\makeatother\\HCode ${tex4ht_sty_par}.a.b.c."..
+"\\input \"\\detokenize{${tex_file}}\"'"
+
+
+local m = {}
+
+function m.htlatex(par)
+ local command = Make.latex_command
+ local devnull = " > /dev/null 2>&1"
+ if os.type == "windows" then
+ command = command:gsub("'",'')
+ devnull = " > nul 2>&1"
+ end
+ par.interaction = par.interaction or "batchmode"
+ -- remove all terminal output from the batchmode
+ if par.interaction == "batchmode" then
+ command = command .. devnull
+ end
+ command = command % par
+ log:info("LaTeX call: "..command)
+ os.execute(command)
+ return Make.testlogfile(par)
+end
+
+return m
diff --git a/Master/texmf-dist/scripts/make4ht/make4ht-indexing.lua b/Master/texmf-dist/scripts/make4ht/make4ht-indexing.lua
new file mode 100755
index 00000000000..5801df509bc
--- /dev/null
+++ b/Master/texmf-dist/scripts/make4ht/make4ht-indexing.lua
@@ -0,0 +1,190 @@
+
+local M = {}
+local log = logging.new "indexing"
+
+-- Handle accented characters in files created with \usepackage[utf]{inputenc}
+-- this code was originally part of https://github.com/michal-h21/iec2utf/
+local enc = {}
+
+local licrs = {}
+local codepoint2utf = unicode.utf8.char
+local used_encodings = {}
+
+-- load inputenc encoding file
+local function load_encfiles(f)
+ local file= io.open(f,"r")
+ local encodings = file:read("*all")
+ file:close()
+ for codepoint, licr in encodings:gmatch('DeclareUnicodeCharacter(%b{})(%b{})') do
+ local codepoint = codepoint2utf(tonumber(codepoint:sub(2,-2),16))
+ local licr= licr:sub(2,-2):gsub('@tabacckludge','')
+ licrs[licr] = codepoint
+ end
+end
+
+local function sanitize_licr(l)
+ return l:gsub(" (.)",function(s) if s:match("[%a]") then return " "..s else return s end end):sub(2,-2)
+end
+
+local load_enc = function(enc)
+ -- use default encodings if used doesn't provide one
+ enc = enc or {"T1","T2A","T2B","T2C","T3","T5", "LGR"}
+ for _,e in pairs(enc) do
+ local filename = e:lower() .. "enc.dfu"
+ -- don't process an enc file multiple times
+ if not used_encodings[filename] then
+ local dfufile = kpse.find_file(filename)
+ if dfufile then
+ load_encfiles(dfufile)
+ end
+ end
+ used_encodings[filename] = true
+ end
+end
+
+
+
+local cache = {}
+
+local get_utf8 = function(input)
+ local output = input:gsub('\\IeC[%s]*(%b{})',function(iec)
+ -- remove \protect commands
+ local iec = iec:gsub("\\protect%s*", "")
+ local code = cache[iec] or licrs[sanitize_licr(iec)] or '\\IeC '..iec
+ -- print(iec, code)
+ cache[iec] = code
+ return code
+ end)
+ return output
+end
+
+
+-- parse the idx file produced by tex4ht
+-- it replaces the document page numbers by index entry number
+-- each index entry can then link to place in the HTML file where the
+-- \index command had been used
+
+local parse_idx = function(content)
+ -- index entry number
+ local current_entry = 0
+ -- map between index entry number and corresponding HTML file and destination
+ local map = {}
+ local buffer = {}
+
+ for line in content:gmatch("([^\n]+)") do
+ if line:match("^\\beforeentry") then
+ -- increment index entry number
+ current_entry = current_entry + 1
+ local file, dest = line:match("\\beforeentry{(.-)}{(.-)}")
+ map[current_entry] = {file = file, dest = dest}
+ elseif line:match("^\\indexentry") then
+ -- replace the page number with the current
+ -- index entry number
+ local result = line:gsub("{[0-9]+}", "{"..current_entry .."}")
+ buffer[#buffer+1] = get_utf8(result)
+ else
+ buffer[#buffer+1] = line
+ end
+ end
+ -- return table with page to dest map and updated idx file
+ return {map = map, idx = table.concat(buffer, "\n")}
+end
+
+-- replace page numbers in the ind file with hyperlinks
+local fix_idx_pages = function(content, idxobj)
+ local buffer = {}
+ local entries = idxobj.map
+ for line in content:gmatch("([^\n]+)") do
+ local line = line:gsub("(%s*\\%a+.-%,)(.+)$", function(start,rest)
+ return start .. rest:gsub("(%d+)", function(page)
+ local entry = entries[tonumber(page)]
+ if entry then
+ -- construct link to the index entry
+ return "\\Link[" .. entry.file .."]{".. entry.dest .."}{}" .. page .."\\EndLink{}"
+ else
+ return page
+ end
+ end)
+ end)
+ buffer[#buffer+1] = line
+ end
+ return table.concat(buffer, "\n")
+end
+
+-- prepare the .idx file produced by tex4ht
+-- for use with Xindy or Makeindex
+local prepare_idx = function(filename)
+ local f = io.open(filename, "r")
+ if not f then return nil, "Cannot open file :".. tostring(filename) end
+ local content = f:read("*all")
+ local idx = parse_idx(content)
+ local idxname = os.tmpname()
+ local f = io.open(idxname, "w")
+ f:write(idx.idx)
+ f:close()
+ -- return the object with mapping between dummy page numbers
+ -- and link destinations in the files, and the temporary .idx file
+ -- these can be used for the processing with the index processor
+ return idx, idxname
+end
+
+-- add links to a index file
+local process_index = function(indname, idx)
+ local f = io.open(indname, "r")
+ if not f then return nil, "Cannot open .ind file: " .. tostring(indname) end
+ local content = f:read("*all")
+ f:close()
+
+ local newcontent = fix_idx_pages(content, idx)
+ local f = io.open(indname,"w")
+ f:write(newcontent)
+ f:close()
+ return true
+end
+
+local prepare_tmp_idx = function(par)
+ par.idxfile = par.idxfile or par.input .. ".idx"
+ -- construct the .ind name, based on the .idx name
+ par.indfile = par.indfile or par.idxfile:gsub("idx$", "ind")
+ load_enc()
+ -- save hyperlinks and clean the .idx file
+ local idxdata, newidxfile = prepare_idx(par.idxfile)
+ if not idxdata then
+ -- if the prepare_idx function returns nil, the second reuturned value contains error msg
+ return nil, newidxfile
+ end
+ return newidxfile, idxdata
+end
+
+local run_indexing_command = function(command, par)
+ -- detect command name from the command. It will be the first word
+ local cmd_name = command:match("^[%a]+") or "indexing"
+ local xindylog = logging.new(cmd_name)
+ local newidxfile, idxdata = prepare_tmp_idx(par)
+ if not newidxfile then
+ -- the idxdata will contain error message in the case of error
+ xindylog:warning(idxdata)
+ return false
+ end
+ par.newidxfile = newidxfile
+ xindylog:debug("Prepared temporary idx file: ", newidxfile)
+ -- prepare modules
+ local xindy_call = command % par
+ xindylog:info(xindy_call)
+ local status = mkutils.execute(xindy_call)
+ -- insert correct links to the index
+ local status, msg = process_index(par.indfile, idxdata)
+ if not status then xindylog:warning(msg) end
+ -- remove the temporary idx file
+ os.remove(newidxfile)
+end
+
+M.get_utf8 = get_utf8
+M.load_enc = load_enc
+M.parse_idx = parse_idx
+M.fix_idx_pages = fix_idx_pages
+M.prepare_idx = prepare_idx
+M.process_index = process_index
+M.prepare_tmp_idx = prepare_tmp_idx
+M.run_indexing_command = run_indexing_command
+return M
diff --git a/Master/texmf-dist/scripts/make4ht/make4ht-lib.lua b/Master/texmf-dist/scripts/make4ht/make4ht-lib.lua
index 2ada398f869..91418d18b5a 100755
--- a/Master/texmf-dist/scripts/make4ht/make4ht-lib.lua
+++ b/Master/texmf-dist/scripts/make4ht/make4ht-lib.lua
@@ -2,6 +2,7 @@
--kpse.set_program_name("luatex")
-- module(...,package.seeall)
local m = {}
+local log = logging.new "make4ht-lib"
Make = {}
--Make.params = {}
@@ -17,13 +18,13 @@ Make.add = function(self,name,fn,par,rep)
Make[name] = function(self,p,typ)
local params = {}
for k,v in pairs(self.params) do params[k] = v end
- for k,v in pairs(par) do params[k] = v; print("setting param "..k) end
+ for k,v in pairs(par) do params[k] = v; log:info("setting param "..k) end
local typ = typ or "make"
local p = p or {}
local fn = fn
for k,v in pairs(p) do
params[k]=v
- print("Adding: ",k,v)
+ log:info("Adding: ",k,v)
end
-- print( fn % params)
local command = {
@@ -50,14 +51,14 @@ Make.run_command = function(self,filename,s)
local command = s.command
local params = s.params
params["filename"] = filename
- print("parse_lg process file: "..filename)
+ log:info("parse_lg process file: "..filename)
--for k,v in pairs(params) do print(k..": "..v) end
if type(command) == "function" then
return command(filename,params)
elseif type(command) == "string" then
local run = command % params
- print("Execute: " .. run)
- return os.execute(run)
+ log:info("Execute: " .. run)
+ return mkutils.execute(run)
end
return false, "parse_lg: Command is not string or function"
end
@@ -95,8 +96,8 @@ Make.image_convert = function(self, images)
command(p)
elseif type(command) == "string" then
local c = command % p
- print("Make4ht convert: "..c)
- os.execute(c)
+ log:info("Make4ht convert: "..c)
+ mkutils.execute(c)
end
break
end
@@ -125,7 +126,7 @@ Make.file_matches = function(self, files)
msg = msg or "No message given"
table.insert(statuses[file],status)
if status == false then
- print(msg)
+ log:info(msg)
break
end
end
@@ -173,14 +174,14 @@ Make.run = function(self)
self.run_count[v.command] = run_count
local repetition = v.repetition
if repetition and run_count > repetition then
- print ("Make4ht: ".. command .." can be executed only "..repetition .."x")
+ log:warning (command .." can be executed only "..repetition .."x")
else
- print("Make4ht: " .. command)
- local status = os.execute(command)
+ log:info("executing: " .. command)
+ local status = mkutils.execute(command)
table.insert(return_codes,{name=v.name,status=status})
end
else
- print("Unknown command type, must be string or function - " ..v.name..": "..type(v.command))
+ log:warning("Unknown command type, must be string or function - " ..v.name..": "..type(v.command))
end
local correct_exit = params.correct_exit or nil
if correct_exit then
@@ -188,7 +189,7 @@ Make.run = function(self)
local current_status = last_return.status or 0
if current_status ~= correct_exit then
local last_name = last_return.name or "unknown"
- print("Make4ht: Fatal error. Command "..last_name .." returned exit code "..current_status)
+ log:fatal("Fatal error. Command "..last_name .." returned exit code "..current_status)
os.exit(1)
end
end
@@ -208,7 +209,7 @@ Make.run = function(self)
end
self:file_matches(files)
else
- print("No lg file. tex4ht run failed?")
+ log:warning("No lg file. tex4ht run failed?")
end
return return_codes
end
diff --git a/Master/texmf-dist/scripts/make4ht/make4ht-logging.lua b/Master/texmf-dist/scripts/make4ht/make4ht-logging.lua
new file mode 100755
index 00000000000..c1d2b24a577
--- /dev/null
+++ b/Master/texmf-dist/scripts/make4ht/make4ht-logging.lua
@@ -0,0 +1,105 @@
+-- logging system for make4ht
+-- inspired by https://github.com/rxi/log.lua
+local logging = {}
+
+local levels = {}
+-- level of bugs that should be shown
+local show_level = 1
+local max_width = 0
+
+logging.use_colors = true
+
+logging.modes = {
+ {name = "debug", color = 34},
+ {name = "info", color = 32},
+ {name = "status", color = 37},
+ {name = "warning", color = 33},
+ {name = "error", color = 31},
+ {name = "fatal", color = 35}
+}
+
+-- prepare table with mapping between mode names and corresponding levels
+
+function logging.prepare_levels(modes)
+ local modes = modes or logging.modes
+ logging.modes = modes
+ for level, mode in ipairs(modes) do
+ levels[mode.name] = level
+ mode.level = level
+ max_width = math.max(string.len(mode.name), max_width)
+ end
+end
+
+-- the logging level is set once
+function logging.set_level(name)
+ local level = levels[name] or 1
+ show_level = level
+end
+
+function logging.print_msg(header, message, color)
+ local color = color or 0
+ -- use format for collors depending on the use_colors option
+ local header = "[" .. header .. "]"
+ local color_format = logging.use_colors and string.format("\27[%im%%s\27[0m%%s", color) or "%s%s"
+ -- the padding is maximal mode name width + brackets + space
+ local padded_header = string.format("%-".. max_width + 3 .. "s", header)
+ print(string.format(color_format, padded_header, message))
+end
+
+--
+function logging.new(module)
+ local obj = {
+ module = module,
+ output = function(self, output)
+ -- used for printing of output of commands
+ if show_level <= (levels[debug] or 1) then
+ print(output)
+ end
+ end
+ }
+ obj.__index = obj
+ -- make a function for each mode
+ for _, mode in ipairs(logging.modes) do
+ local name = mode.name
+ local color = mode.color
+ obj[name] = function(self, ...)
+ -- max width is saved in logging.prepare_levels
+ if mode.level >= show_level then
+ -- support variable number of parameters
+ local table_with_holes = table.pack(...)
+ local table_without_holes = {}
+ -- trick used to support the nil values in the varargs
+ -- https://stackoverflow.com/a/7186820/2467963
+ for i= 1, table_with_holes.n do
+ table.insert(table_without_holes, tostring(table_with_holes[i]) or "")
+ end
+ local msg = table.concat(table_without_holes, "\t")
+ logging.print_msg(string.upper(name), string.format("%s: %s", self.module, msg), color)
+ end
+ end
+ end
+ return setmetatable({}, obj)
+
+end
+
+
+-- prepare default levels
+logging.prepare_levels()
+
+-- for _, mode in ipairs(logging.modes) do
+-- logging.print_msg(mode.name,"xxxx", mode.color)
+-- end
+
+-- local cls = logging.new("sample")
+-- cls:warning("hello")
+-- cls:error("world")
+-- cls:info("set new level")
+-- logging.set_level("error")
+-- cls:info("level set")
+-- cls:error("just print the error")
+
+
+return logging
+
+
+
diff --git a/Master/texmf-dist/scripts/make4ht/make4ht-xtpipes.lua b/Master/texmf-dist/scripts/make4ht/make4ht-xtpipes.lua
index 78014baff1c..3f5b51e07b8 100755
--- a/Master/texmf-dist/scripts/make4ht/make4ht-xtpipes.lua
+++ b/Master/texmf-dist/scripts/make4ht/make4ht-xtpipes.lua
@@ -1,5 +1,6 @@
local M = {}
+local log = logging.new "xtpipes"
-- find if tex4ht.jar exists in a path
local function find_tex4ht_jar(path)
local jar_file = path .. "/tex4ht/bin/tex4ht.jar"
@@ -38,7 +39,7 @@ end
function M.get_xtpipes(selfautoparent)
-- make pattern using TeX distro path
- local pattern = string.format("java -classpath %s/tex4ht/bin/tex4ht.jar xtpipes -i %s/tex4ht/xtpipes/ -o ${outputfile} ${filename}", selfautoparent, selfautoparent)
+ local pattern = string.format('java -classpath "%s/tex4ht/bin/tex4ht.jar" xtpipes -i "%s/tex4ht/xtpipes/" -o "${outputfile}" "${filename}"', selfautoparent, selfautoparent)
-- call xtpipes on a temporary file
local matchfunction = function(filename)
-- move the matched file to a temporary file, xtpipes will write it back to the original file
@@ -46,19 +47,19 @@ function M.get_xtpipes(selfautoparent)
local tmpfile = basename ..".tmp"
mkutils.mv(filename, tmpfile)
local command = pattern % {filename = tmpfile, outputfile = filename}
- print(command)
- local status = os.execute(command)
+ log:info("execute: " ..command)
+ local status = mkutils.execute(command)
if status > 0 then
-- if xtpipes failed to process the file, it may mean that it was bad-formed xml
-- we can try to make it well-formed using Tidy
- local tidy_command = "tidy -utf8 -xml -asxml -q -o ${filename} ${tmpfile}" % {tmpfile = tmpfile, filename = filename}
- print("xtpipes failed trying tidy")
- print(tidy_command)
+ local tidy_command = 'tidy -utf8 -xml -asxml -q -o "${filename}" "${tmpfile}"' % {tmpfile = tmpfile, filename = filename}
+ log:warning("xtpipes failed trying tidy")
+ log:debug(tidy_command)
local status = os.execute(tidy_command)
if status > 0 then
-- if tidy failed as well, just use the original file
-- it will probably produce corrupted ODT file though
- print("Tidy failed as well")
+ log:warning("Tidy failed as well")
mkutils.mv(tmpfile, filename)
end
end
diff --git a/Master/texmf-dist/scripts/make4ht/mkparams.lua b/Master/texmf-dist/scripts/make4ht/mkparams.lua
index 4db967f2706..eff8c99670b 100755
--- a/Master/texmf-dist/scripts/make4ht/mkparams.lua
+++ b/Master/texmf-dist/scripts/make4ht/mkparams.lua
@@ -1,6 +1,7 @@
local lapp = require "lapp-mk4"
local mkutils = require "mkutils"
local m = {} -- use ugly module system for new lua versions support
+local log = logging.new "mkparams"
-- these two variables will be used in the version number
-- progname will be set in get_args
@@ -9,25 +10,28 @@ m.progname = "make4ht"
m.version_number = "v0.1"
m.optiontext = [[
-${progname} - build system for tex4ht
+${progname} - build system for TeX4ht
Usage:
${progname} [options] filename ["tex4ht.sty op."] ["tex4ht op."] ["t4ht op"] ["latex op"]
Available options:
+ -a,--loglevel (default status) Set log level.
+ possible values: debug, info, status, warning, error, fatal
-b,--backend (default tex4ht) Backend used for xml generation.
possible values: tex4ht or lua4ht
-c,--config (default xhtml) Custom config file
-d,--output-dir (default nil) Output directory
-e,--build-file (default nil) If build file is different than `filename`.mk4
-f,--format (default html5) Output file format
- -h,-- help Display this message
+ -h,--help Display this message
+ -j,--jobname (default nil) Set the jobname
-l,--lua Use lualatex for document compilation
-m,--mode (default default) Switch which can be used in the makefile
- -n,--no-tex4ht Disable dvi file processing with tex4ht command
+ -n,--no-tex4ht Disable dvi file processing with the tex4ht command
-s,--shell-escape Enables running external programs from LaTeX
-u,--utf8 For output documents in utf8 encoding
- -x,--xetex Use xelatex for document compilation
-v,--version Display version number
+ -x,--xetex Use xelatex for document compilation
]]
-- test if the current command line argument should be passed to tex4ht, t4ht or latex
@@ -36,11 +40,12 @@ local function is_escapedargument(arg)
local ignored_options = {["-h"]=true, ["--help"]=true, ["-v"] = true, ["--version"]=true}
if ignored_options[arg] then return false end
-- in other cases, match if the argument starts with "-" character
- return arg:match("^%-")
+ return arg:match("^%-.+")
end
local function get_args(parameters, optiontext)
local parameters = parameters or {}
parameters.progname = parameters.progname or "make4ht"
+ parameters.issue_tracker = parameters.issue_tracker or "https://github.com/michal-h21/make4ht/issues"
parameters.postparams = parameters.postparams or ""
local optiontext = optiontext or m.optiontext
parameters.postfile = parameters.postfile or ""
@@ -54,7 +59,7 @@ Positional optional argumens:
Documentation: https://tug.org/applications/tex4ht/mn.html
Issue tracker for tex4ht bugs: https://puszcza.gnu.org.ua/bugs/?group=tex4ht
-Issue tracker for make4ht bugs: https://github.com/michal-h21/make4ht/issues
+Issue tracker for ${progname} bugs: ${issue_tracker}
]] .. parameters.postfile
-- we can pass arguments for tex4ht and t4ht after filename, but it will confuse lapp, thinking that these
-- options are for make4ht. this may result in execution error or wrong option parsing
@@ -88,6 +93,61 @@ local function get_format_extensions(format_string)
return format, extensions
end
+-- detect if user specified -jobname in arguments to the TeX engine
+-- or used the --jobname option for make4ht
+local function handle_jobname(input, args)
+ -- parameters to the TeX engine
+ local latex_params = {}
+ local latex_cli_params = args[4] or ""
+ -- use the jobname as input name if it is specified
+ local jobname = args.jobname ~="nil" and args.jobname or nil
+ if jobname or not latex_cli_params:match("%-jobname") then
+ -- prefer jobname over input
+ input = jobname or input
+ -- we must strip out directories from jobname when full path to document is given
+ input = input:match("([^%/^%\\]+)$")
+ -- input also cannot contain spaces, replace them with underscores
+ input = input:gsub("%s", "_")
+ table.insert(latex_params,"-jobname="..input)
+ else
+ -- when user specifies -jobname, we must change name of the input file,
+ -- in order to be able to process correct dvi file with tex4ht and t4ht
+ local newinput
+ -- first contains quotation character or first character of the name
+ local first, rest = latex_cli_params:match("%-jobname%s*=?%s*(.)(.*)")
+ if first=='"' then
+ newinput=rest:match('([^"]+)')
+ elseif first=="'" then
+ newinput=rest:match("([^']+)")
+ elseif type(first)== "string" then
+ -- if the jobname is unquoted, it cannot contain space
+ -- join the first character and rest
+ rest = first.. rest
+ newinput = rest:match("([^ ]+)")
+ end
+ if newinput then
+ input = newinput
+ end
+ end
+ --
+ table.insert(latex_params, latex_cli_params)
+ return latex_params, input
+end
+
+-- use standard input instead of file if the filename is just `-`
+-- return the filename and status if it is a tmp name
+local function handle_input_file(filename)
+ -- return the original file name if it isn't just dash
+ if filename ~= "-" then return filename, false end
+ -- generate the temporary name. the added extension is important
+ local tmp_name = os.tmpname()
+ local contents = io.read("*all")
+ local f = io.open(tmp_name, "w")
+ f:write(contents)
+ f:close()
+ return tmp_name, true
+end
+
local function process_args(args)
local function get_inserter(args,tb)
return function(key, value)
@@ -98,6 +158,14 @@ local function process_args(args)
end
end
+ -- set error log level
+ logging.set_level(args.loglevel)
+ -- the default LaTeX --interaction parameter
+ local interaction = "batchmode"
+ if args.loglevel == "debug" then
+ interaction = "errorstopmode"
+ end
+
if args.version ==true then
print(string.format("%s version %s", m.progname, m.version_number))
os.exit()
@@ -122,36 +190,12 @@ local function process_args(args)
local compiler = args.lua and "dvilualatex" or args.xetex and "xelatex --no-pdf" or "latex"
- local tex_file = args.filename
- local input = mkutils.remove_extension(args.filename)
- local latex_params = {}
+ local tex_file, is_tmp_file = handle_input_file(args.filename)
+ local input = mkutils.remove_extension(tex_file)
+ -- the output file name can be influneced using -jobname parameter passed to the TeX engine
+ local latex_params, input = handle_jobname(input, args)
local insert_latex = get_inserter(args,latex_params)
insert_latex("shell-escape","-shell-escape")
- local latex_cli_params = args[4] or ""
- if not latex_cli_params:match("%-jobname") then
- -- we must strip out directories from jobname when full path to document is given
- input = input:match("([^%/^%\\]+)$")
- -- input also cannot contain spaces, replace them with underscores
- input = input:gsub("%s", "_")
- table.insert(latex_params,"-jobname="..input)
- else
- -- when user specifies -jobname, we must change name of the input file,
- -- in order to be able to process correct dvi file with tex4ht and t4ht
- local newinput
- local first, rest = latex_cli_params:match("%-jobname=(.)(.*)")
- if first=='"' then
- newinput=rest:match('([^"]+)')
- elseif first=="'" then
- newinput=rest:match("([^']+)")
- elseif type(first)== "string" then
- rest = first.. rest
- newinput = rest:match("([^ ]+)")
- end
- if newinput then
- input = newinput
- end
- end
- table.insert(latex_params, latex_cli_params)
--table.insert(latex_params,args["shell-escape"] and "-shell-escape")
@@ -181,9 +225,9 @@ local function process_args(args)
tex4ht = args[2]
else
tex4ht = args.utf8 and " -cmozhtf -utf8" or ""
- if args.xetex then tex4ht = tex4ht .. " -.xdv" end
- -- tex4ht = tex4ht .. xdv
end
+ -- set the correct extension for tex4ht if xetex is used
+ if args.xetex then tex4ht = tex4ht .. " -.xdv" end
local t4ht = args[3] or ""
@@ -215,19 +259,21 @@ local function process_args(args)
,build_file = build_file
,output_format = outformat
,extensions = extensions
+ ,is_tmp_file = is_tmp_file
+ ,interaction = interaction
--,t4ht_dir_format=t4ht_dir_format
}
if outdir then parameters.outdir = outdir end
- print("Output dir: ",outdir)
- print("Compiler: ", compiler)
- print("Latex options: ", table.concat(latex_params," "))
- print("tex4ht.sty :",t4sty)
- print("tex4ht",tex4ht)
- print("build_file", build_file)
+ log:info("Output dir: "..outdir)
+ log:info("Compiler: "..compiler)
+ log:info("Latex options: ".. table.concat(latex_params," "))
+ log:info("tex4ht.sty: "..t4sty)
+ log:info("tex4ht: "..tex4ht)
+ log:info("build_file: ".. build_file)
if outformat~="nil" then
- print("Output format", outformat)
+ log:info("Output format: ".. outformat)
for _, ex in ipairs(extensions) do
- print("Extension", ex.type .. ex.name)
+ log:info("Extension: ".. ex.type .. ex.name)
end
end
return parameters
diff --git a/Master/texmf-dist/scripts/make4ht/mkutils.lua b/Master/texmf-dist/scripts/make4ht/mkutils.lua
index fd32c91e087..ba1cd6cbb9f 100755
--- a/Master/texmf-dist/scripts/make4ht/mkutils.lua
+++ b/Master/texmf-dist/scripts/make4ht/mkutils.lua
@@ -1,7 +1,10 @@
module(...,package.seeall)
+local log = logging.new("mkutils")
+
local make4ht = require("make4ht-lib")
local mkparams = require("mkparams")
+local indexing = require("make4ht-indexing")
--template engine
function interp(s, tab)
local tab = tab or {}
@@ -61,11 +64,11 @@ end
-- searching for converted images
function parse_lg(filename)
- print("Parse LG")
+ log:info("Parse LG")
local outputimages,outputfiles,status={},{},nil
local fonts, used_fonts = {},{}
if not file_exists(filename) then
- print("Cannot read log file: "..filename)
+ log:warning("Cannot read log file: "..filename)
else
local usedfiles={}
for line in io.lines(filename) do
@@ -114,7 +117,7 @@ local cp_func = os.type == "unix" and "cp" or "copy"
function cp(src,dest)
local command = string.format('%s "%s" "%s"', cp_func, src, dest)
if cp_func == "copy" then command = command:gsub("/",'\\') end
- print("Copy: "..command)
+ log:info("Copy: "..command)
os.execute(command)
end
@@ -123,7 +126,7 @@ function mv(src, dest)
local command = string.format('%s "%s" "%s"', mv_func, src, dest)
-- fix windows paths
if mv_func == "move" then command = command:gsub("/",'\\') end
- print("Move: ".. command)
+ log:info("Move: ".. command)
os.execute(command)
end
@@ -211,18 +214,32 @@ function copy(filename,outfilename)
if not used_dir[path] then
local to_create, msg = find_directories(parts)
if not to_create then
- print(msg)
+ log:warning(msg)
return false
end
used_dir[path] = true
local stat, msg = mkdirectories(to_create)
- if not stat then print(msg) end
+ if not stat then log:warning(msg) end
end
lfs.chdir(currdir)
cp(filename, path)
return true
end
+function execute(command)
+ local f = io.popen(command, "r")
+ local output = f:read("*all")
+ -- rc will contain return codes of the executed command
+ local rc = {f:close()}
+ -- the status code is on the third position
+ -- https://stackoverflow.com/a/14031974/2467963
+ local status = rc[3]
+ -- print the command line output only when requested through
+ -- log level
+ log:output(output)
+ return status, output
+end
+
-- find the zip command
function find_zip()
if io.popen("zip -v","r"):close() then
@@ -269,6 +286,7 @@ env.os = os
env.io = io
env.math = math
env.unicode = unicode
+env.logging = logging
-- it is necessary to use the settings table
@@ -317,57 +335,14 @@ env.Make = make4ht.Make
env.Make.params = env.settings
env.Make:add("test","test the variables: ${tex4ht_sty_par} ${htlatex} ${input} ${config}")
--- this function reads the LaTeX log file and tries to detect fatal errors in the compilation
-local function testlogfile(par)
- local logfile = par.input .. ".log"
- local f = io.open(logfile,"r")
- if not f then
- print("Make4ht: cannot open log file "..logfile)
- return 1
- end
- local len = f:seek("end")
- -- test only the end of the log file, no need to run search functions on everything
- local newlen = len - 1256
- -- but the value to seek must be greater than 0
- newlen = (newlen > 0) and newlen or 0
- f:seek("set", newlen)
- local text = f:read("*a")
- f:close()
- if text:match("No pages of output") or text:match("TeX capacity exceeded, sorry") then return 1 end
- return 0
-end
-
-
--- Make this function available in the build files
-Make.testlogfile = testlogfile
---env.Make:add("htlatex", "${htlatex} ${latex_par} '\\\makeatletter\\def\\HCode{\\futurelet\\HCode\\HChar}\\def\\HChar{\\ifx\"\\HCode\\def\\HCode\"##1\"{\\Link##1}\\expandafter\\HCode\\else\\expandafter\\Link\\fi}\\def\\Link#1.a.b.c.{\\g@addto@macro\\@documentclasshook{\\RequirePackage[#1,html]{tex4ht}\\let\\HCode\\documentstyle\\def\\documentstyle{\\let\\documentstyle\\HCode\\expandafter\\def\\csname tex4ht\\endcsname{#1,html}\\def\\HCode####1{\\documentstyle[tex4ht,}\\@ifnextchar[{\\HCode}{\\documentstyle[tex4ht]}}}\\makeatother\\HCode '${config}${tex4ht_sty_par}'.a.b.c.\\input ' ${input}")
-
--- template for calling LaTeX with tex4ht loaded
-Make.latex_command = "${htlatex} ${latex_par} '\\makeatletter"..
-"\\def\\HCode{\\futurelet\\HCode\\HChar}\\def\\HChar{\\ifx\"\\HCode"..
-"\\def\\HCode\"##1\"{\\Link##1}\\expandafter\\HCode\\else"..
-"\\expandafter\\Link\\fi}\\def\\Link#1.a.b.c.{\\g@addto@macro"..
-"\\@documentclasshook{\\RequirePackage[#1,html]{tex4ht}${packages}}"..
-"\\let\\HCode\\documentstyle\\def\\documentstyle{\\let\\documentstyle"..
-"\\HCode\\expandafter\\def\\csname tex4ht\\endcsname{#1,html}\\def"..
-"\\HCode####1{\\documentstyle[tex4ht,}\\@ifnextchar[{\\HCode}{"..
-"\\documentstyle[tex4ht]}}}\\makeatother\\HCode ${tex4ht_sty_par}.a.b.c."..
-"\\input \"\\detokenize{${tex_file}}\"'"
-
-env.Make:add("htlatex",function(par)
- local command = Make.latex_command
- if os.type == "windows" then
- command = command:gsub("'",'')
- end
- command = command % par
- print("LaTeX call: "..command)
- os.execute(command)
- return testlogfile(par)
-end
+local htlatex = require "make4ht-htlatex"
+env.Make:add("htlatex", htlatex.htlatex
,{correct_exit=0})
env.Make:add("latexmk", function(par)
+ local settings = get_filter_settings "htlatex" or {}
+ par.interaction = par.interaction or settings.interaction or "batchmode"
local command = Make.latex_command
par.expanded = command % par
-- quotes in latex_command must be escaped, they cause Latexmk error
@@ -407,13 +382,13 @@ function load_config(settings, config_name)
end
local f = io.open(config_name,"r")
if not f then
- print("Cannot open config file", config_name)
+ log:info("Cannot open config file", config_name)
return env
end
- print("Using build file", config_name)
+ log:info("Using build file", config_name)
local code = f:read("*all")
local fn, msg = run(code,env)
- if not fn then print(msg) end
+ if not fn then log:warning(msg) end
assert(fn)
-- reload extensions from command line arguments for the "format" parameter
for _,v in ipairs(saved_extensions) do
@@ -423,25 +398,49 @@ function load_config(settings, config_name)
end
env.Make:add("xindy", function(par)
- -- par.encoding = par.encoding or "utf8"
- -- par.language = par.language or "english"
- par.idxfile = par.idxfile or par.input .. ".idx"
- local modules = par.modules or {par.input}
+ local xindylog = logging.new "xindy"
+ local settings = get_filter_settings "xindy" or {}
+ par.encoding = settings.encoding or par.encoding or "utf8"
+ par.language = settings.language or par.language or "english"
+ local modules = settings.modules or par.modules or {}
local t = {}
for k,v in ipairs(modules) do
+ xindylog:debug("Loading module: " ..v)
t[#t+1] = "-M ".. v
end
par.moduleopt = table.concat(t, " ")
- local xindy_call = "xindy -L ${language} -C ${encoding} ${moduleopt} ${idxfile}" % par
- print(xindy_call)
- return os.execute(xindy_call)
-end, { language = "english", encoding = "utf8"})
+ return indexing.run_indexing_command("texindy -L ${language} -C ${encoding} ${moduleopt} -o ${indfile} ${newidxfile}", par)
+end, {})
+
+env.Make:add("makeindex", function(par)
+ local makeindxcall = "makeindex ${options} -t ${ilgfile} -o ${indfile} ${newidxfile}"
+ local settings = get_filter_settings "makeindex" or {}
+ par.options = settings.options or par.options or ""
+ par.ilgfile = par.input .. ".ilg"
+ local status = indexing.run_indexing_command(makeindxcall, par)
+ return status
+end, {})
+
+env.Make:add("xindex", function(par)
+ local xindex_call = "xindex -l ${language} ${options} -o ${indfile} ${newidxfile}"
+ local settings = get_filter_settings "xindex" or {}
+ par.options = settings.options or par.options or ""
+ par.language = settings.language or par.language or "en"
+ local status = indexing.run_indexing_command(xindex_call, par)
+ return status
+end, {})
+
+
local function find_lua_file(name)
local extension_path = name:gsub("%.", "/") .. ".lua"
return kpse.find_file(extension_path, "lua")
end
+-- for the BibLaTeX support
+env.Make:add("biber", "biber ${input}")
+env.Make:add("bibtex", "bibtex ${input}")
+
--- load the output format plugins
function load_output_format(format_name)
local format_library = "make4ht.formats."..format_name
@@ -532,10 +531,10 @@ function load_extensions(extensions, format)
if module_names[name] == true then
local extension = load_extension(name,format)
if extension then
- print("Load extension", name)
+ log:info("Load extension", name)
table.insert(extension_table, extension)
else
- print("Cannot load extension: ".. name)
+ log:warning("Cannot load extension: ".. name)
end
end
end