summaryrefslogtreecommitdiff
path: root/support/make4ht
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2023-02-25 03:01:09 +0000
committerNorbert Preining <norbert@preining.info>2023-02-25 03:01:09 +0000
commit81a9d839224eef4c2bd9bf68410b4049c61cdb14 (patch)
tree813b5a34a2548b16dbbcd271697c7bcf29342bde /support/make4ht
parentc283f3a6970d2bc9de3501415f5701277da68693 (diff)
CTAN sync 202302250301
Diffstat (limited to 'support/make4ht')
-rw-r--r--support/make4ht/README14
-rw-r--r--support/make4ht/changelog.tex177
-rw-r--r--support/make4ht/domfilters/make4ht-inlinecss.lua83
-rw-r--r--support/make4ht/domfilters/make4ht-joincharacters.lua2
-rw-r--r--support/make4ht/domfilters/make4ht-mathmlfixes.lua221
-rw-r--r--support/make4ht/extensions/make4ht-ext-inlinecss.lua16
-rw-r--r--support/make4ht/extensions/make4ht-ext-latexmk_build.lua38
-rw-r--r--support/make4ht/extensions/make4ht-ext-preprocess_input.lua21
-rw-r--r--support/make4ht/extensions/make4ht-ext-tidy.lua6
-rw-r--r--support/make4ht/formats/make4ht-jats.lua208
-rw-r--r--support/make4ht/formats/make4ht-odt.lua11
-rwxr-xr-xsupport/make4ht/make4ht10
-rw-r--r--support/make4ht/make4ht-doc.pdfbin154182 -> 156343 bytes
-rw-r--r--support/make4ht/make4ht-indexing.lua11
-rw-r--r--support/make4ht/mkutils.lua205
-rw-r--r--support/make4ht/readme.tex12
16 files changed, 888 insertions, 147 deletions
diff --git a/support/make4ht/README b/support/make4ht/README
index bdb5e173c3..0675e1d0ce 100644
--- a/support/make4ht/README
+++ b/support/make4ht/README
@@ -278,9 +278,13 @@ dvisvgm\_hashes
: efficient generation of SVG pictures using Dvisvgm. It can utilize
multiple processor cores and generates only changed images.
+inlinecss
+
+: load the `inlinecss` DOM filter.
+
join\_colors
-: load the `joincolors` domfilter for all HTML files.
+: load the `joincolors` DOM filter for all HTML files.
latexmk\_build
@@ -646,6 +650,11 @@ idcolons
: replace the colon (`:`) character in internal links and `id` attributes. They cause validation issues.
+inlinecss
+
+: remove CSS rules that target elements with unique attributes, such as color boxes, table rules, or inline math pictures,
+ and insert their properties as a inline `style` attribute in the HTML document.
+
joincharacters
: join consecutive `<span>` or `<mn>` elements. This DOM filter supersedes the `cleanspan` filter.
@@ -655,7 +664,8 @@ joincolors
: many `<span>` elements with unique `id` attributes are created when \LaTeX\ colors are being used in the document.
A CSS rule is added for each of these elements, which may result in
substantial growth of the CSS file. This filter replaces these rules with a
- common one for elements with the same color value.
+ common one for elements with the same color value. See also the `inlinecss` DOM filter and extension, which provides an
+ alternative using inline styles.
odtfonts
diff --git a/support/make4ht/changelog.tex b/support/make4ht/changelog.tex
index 1d579d4514..4516805f3a 100644
--- a/support/make4ht/changelog.tex
+++ b/support/make4ht/changelog.tex
@@ -3,7 +3,182 @@
\begin{itemize}
\item
- 2022/02/22
+ 2023/02/24
+
+ \begin{itemize}
+ \tightlist
+ \item
+ version \texttt{0.3k} released.
+ \end{itemize}
+\item
+ 2023/01/09
+
+ \begin{itemize}
+ \tightlist
+ \item
+ fixed detection of image file names in \texttt{mkutils.parse\_lg()}
+ \end{itemize}
+\item
+ 2022/11/25
+
+ \begin{itemize}
+ \tightlist
+ \item
+ reverted change of index page numbers, it was buggy
+ \item
+ test if the \texttt{.idx} file exists.
+ \end{itemize}
+\item
+ 2022/11/24
+
+ \begin{itemize}
+ \tightlist
+ \item
+ \texttt{make4ht-indexing}: fixed handling of numbers in index
+ entries text.
+ \end{itemize}
+\item
+ 2022/11/01
+
+ \begin{itemize}
+ \tightlist
+ \item
+ remove empty last rows in MathML tables.
+ \end{itemize}
+\item
+ 2022/10/21
+
+ \begin{itemize}
+ \tightlist
+ \item
+ added the \texttt{inlinecss} DOM filter and extension with the same
+ name.
+ \end{itemize}
+\item
+ 2022/09/29
+
+ \begin{itemize}
+ \tightlist
+ \item
+ the \texttt{join\_characters} DOM filter now shouldn't produce extra
+ \texttt{\textless{}span\textgreater{}} elements after white space.
+ \end{itemize}
+\item
+ 2022/09/16
+
+ \begin{itemize}
+ \tightlist
+ \item
+ use the \texttt{no\^{}} option to compile the \texttt{make4ht} HTML
+ docs, to prevent clash with the Doc package.
+ \end{itemize}
+\item
+ 2022/07/22
+
+ \begin{itemize}
+ \tightlist
+ \item
+ \texttt{mathmlfixes} DOM filter:
+
+ \begin{itemize}
+ \tightlist
+ \item
+ don't change \texttt{\textless{}mo\textgreater{}} to
+ \texttt{\textless{}mtext\textgreater{}} if the element contain the
+ \texttt{stretchy} attribute.
+ \item
+ add \texttt{\textless{}mtext\textgreater{}} to
+ \texttt{\textless{}mstyle\textgreater{}} if it contains only plain
+ text
+ \end{itemize}
+ \end{itemize}
+\item
+ 2022/07/08
+
+ \begin{itemize}
+ \tightlist
+ \item
+ configure elements used in \texttt{join\_characters} DOM filter.
+ \item
+ added support for the \texttt{mml:} prefix in \texttt{mathml\_fixes}
+ DOM filter.
+ \end{itemize}
+\item
+ 2022/06/28
+
+ \begin{itemize}
+ \tightlist
+ \item
+ handle \texttt{\textbackslash{}maketitle} in JATS.
+ \end{itemize}
+\item
+ 2022/06/24
+
+ \begin{itemize}
+ \tightlist
+ \item
+ handle internal and external links in the JATS output.
+ \item
+ better detection of empty paragraphs.
+ \end{itemize}
+\item
+ 2022/06/16
+
+ \begin{itemize}
+ \tightlist
+ \item
+ use DOM filters to fix JATS output.
+ \end{itemize}
+\item
+ 2022/04/22
+
+ \begin{itemize}
+ \tightlist
+ \item
+ use more explicit options for \texttt{latexmk}.
+ \end{itemize}
+\item
+ 2022/04/19
+
+ \begin{itemize}
+ \tightlist
+ \item
+ remove all \texttt{htlatex} calls from the build sequence when the
+ \texttt{latexmk\_build} extension is used.
+ \item
+ fixed other issues that caused spurious executions of
+ \texttt{latexmk}.
+ \end{itemize}
+\item
+ 2022/04/01
+
+ \begin{itemize}
+ \tightlist
+ \item
+ don't copy files to the output dir if it wasn't requested
+ \item
+ fixed copying of the ODT file to the output dir.
+ \end{itemize}
+\item
+ 2022/03/29
+
+ \begin{itemize}
+ \tightlist
+ \item
+ check if tidy return non-empty string in the \texttt{tidy}
+ extension.
+ \end{itemize}
+\item
+ 2022/03/24
+
+ \begin{itemize}
+ \tightlist
+ \item
+ don't use totally random names in the \texttt{preprocess\_input}
+ extension, in order to support images correctly.
+ \end{itemize}
+\item
+ 2022/03/22
\begin{itemize}
\tightlist
diff --git a/support/make4ht/domfilters/make4ht-inlinecss.lua b/support/make4ht/domfilters/make4ht-inlinecss.lua
new file mode 100644
index 0000000000..b086a2fc42
--- /dev/null
+++ b/support/make4ht/domfilters/make4ht-inlinecss.lua
@@ -0,0 +1,83 @@
+local cssquery = require "luaxml-cssquery"
+
+local log = logging.new("inlinecss")
+
+local cssrules = {}
+local cssobj = cssquery()
+
+local function parse_rule(line)
+ -- parse CSS selector and attributes
+ -- they are always on one line in the CSS file produced by TeX4ht
+ local selector, values = line:match("%s*(.-)%s*(%b{})")
+ if values then
+ values = values:sub(2,-2)
+ end
+ return selector, values
+end
+
+local function join_values(old, new)
+ -- correctly joins two attribute lists, depending on the ending
+ local separator = ";"
+ if not old then return new end
+ -- if old already ends with ;, then don't use semicolon as a separator
+ if old:match(";%s*$") then separator = "" end
+ return old .. separator .. new
+end
+
+local function parse_css(filename)
+ local css_file = io.open(filename, "r")
+ if not css_file then return nil, "cannot load css file: " .. (filename or "") end
+ local newlines = {}
+ for line in css_file:lines() do
+ -- match lines that contain # or =, as these can be id or attribute selectors
+ if line:match("[%#%=].-{") then
+ -- update attributes for the current selector
+ local selector, value = parse_rule(line)
+ local oldvalue = cssrules[selector]
+ cssrules[selector] = join_values(oldvalue, value)
+ else
+ newlines[#newlines+1] = line
+ end
+ end
+ -- we need to add css rules
+ for selector, value in pairs(cssrules) do
+ cssobj:add_selector(selector, function(dom) end, {value=value})
+ end
+ css_file:close()
+ -- write new version of the CSS file, without rules for ids and attributes
+ local css_file = io.open(filename, "w")
+ css_file:write(table.concat(newlines, "\n"))
+ css_file:close()
+ return true
+end
+
+local processed = false
+
+-- process the HTML file and insert inline CSS for id and attribute selectors
+return function(dom, par)
+ if not processed then
+ -- process the CSS file before everything else, but only once
+ processed = true
+ local css_file = par.input .. ".css"
+ local status, msg = parse_css(css_file)
+ if not status then log:warning(msg) end
+ end
+ -- loop over all elements in the current page
+ dom:traverse_elements(function(curr)
+ -- use CSS object to match if the current element
+ -- is matched by id attribute selector
+ local matched = cssobj:match_querylist(curr)
+ if #matched > 0 then
+ -- join possible already existing style attribute with values from the CSS file
+ local values = curr:get_attribute("style")
+ -- join values of all matched rules
+ for _,rule in ipairs(matched) do
+ values = join_values(values, rule.params.value)
+ end
+ curr:set_attribute("style", values)
+ end
+
+ end)
+ return dom
+end
+
diff --git a/support/make4ht/domfilters/make4ht-joincharacters.lua b/support/make4ht/domfilters/make4ht-joincharacters.lua
index 34737f921a..7f70cca3db 100644
--- a/support/make4ht/domfilters/make4ht-joincharacters.lua
+++ b/support/make4ht/domfilters/make4ht-joincharacters.lua
@@ -107,7 +107,7 @@ local function join_characters(obj,par)
-- we must create a new node
el:add_child_node(el:create_text_node(s))
next_el:remove_node()
- real_next = nil
+ -- real_next = nil
else
real_next = nil
end
diff --git a/support/make4ht/domfilters/make4ht-mathmlfixes.lua b/support/make4ht/domfilters/make4ht-mathmlfixes.lua
index 12754bedb9..7fa74f4632 100644
--- a/support/make4ht/domfilters/make4ht-mathmlfixes.lua
+++ b/support/make4ht/domfilters/make4ht-mathmlfixes.lua
@@ -5,17 +5,53 @@ local token = {"mi", "mn", "mo", "mtext", "mspace", "ms"}
local token_elements = {}
for _, tok in ipairs(token) do token_elements[tok] = true end
+-- helper functions to support MathML elements with prefixes (<mml:mi> etc).
+--
+local function get_element_name(el)
+ -- return element name and xmlns prefix
+ local name = el:get_element_name()
+ if name:match(":") then
+ local prefix, real_name = name:match("([^%:]+):?(.+)")
+ return real_name, prefix
+ else
+ return name
+ end
+end
+
+local function get_attribute(el, attr_name)
+ -- attributes can have the prefix, but sometimes they don't have it
+ -- so we need to catch both cases
+ local _, prefix = get_element_name(el)
+ prefix = prefix or ""
+ return el:get_attribute(attr_name) or el:get_attribute(prefix .. ":" .. attr_name)
+end
+
+local function get_new_element_name(name, prefix)
+ return prefix and prefix .. ":" .. name or name
+end
+
+local function update_element_name(el, name, prefix)
+ local newname = get_new_element_name(name, prefix)
+ el._name = newname
+end
+
+local function create_element(el, name, prefix)
+ return el:create_element(newname)
+end
+
local function is_token_element(el)
- return token_elements[el:get_element_name()]
+ local name, prefix = get_element_name(el)
+ return token_elements[name], prefix
end
local function fix_token_elements(el)
-- find token elements that are children of other token elements
if is_token_element(el) then
local parent = el:get_parent()
- if is_token_element(parent) then
+ local is_parent_token, prefix = is_token_element(parent)
+ if is_parent_token then
-- change top element in nested token elements to mstyle
- parent._name = "mstyle"
+ update_element_name(parent, "mstyle", prefix)
end
end
end
@@ -23,7 +59,8 @@ end
local function fix_nested_mstyle(el)
-- the <mstyle> element can be child of token elements
-- we must exterminate it
- if el:get_element_name() == "mstyle" then
+ local el_name = get_element_name(el)
+ if el_name == "mstyle" then
local parent = el:get_parent()
if is_token_element(parent) then
-- if parent doesn't have the mathvariant attribute copy it from <mstyle>
@@ -44,13 +81,13 @@ local function fix_mathvariant(el)
-- find if element has <mstyle> parent, and its value of mathvariant
if not x:is_element() then
return nil
- elseif x:get_element_name() == "mstyle" then
+ elseif get_element_name(x) == "mstyle" then
return x:get_attribute("mathvariant")
else
return find_mstyle(x:get_parent())
end
end
- if el:get_element_name() == "mi" then
+ if get_element_name(el) == "mi" then
-- process only <mi> that have mathvariant set
local oldmathvariant = el:get_attribute("mathvariant")
if oldmathvariant then
@@ -62,6 +99,74 @@ local function fix_mathvariant(el)
end
end
+local function contains_only_text(el)
+ -- detect if element contains only text
+ local elements = 0
+ local text = 0
+ local children = el:get_children() or {}
+ for _ , child in ipairs(children) do
+ if child:is_text() then text = text + 1
+ elseif child:is_element() then elements = elements + 1
+ end
+ end
+ return text > 0 and elements == 0
+end
+
+-- check if <mstyle> element contains direct text. in that case, add
+-- <mtext>
+local function fix_missing_mtext(el)
+ if el:get_element_name() == "mstyle" and contains_only_text(el) then
+ -- add child <mtext>
+ log:debug("mstyle contains only text: " .. el:get_text())
+ -- copy the current mode, change it's element name to mtext and add it as a child of <mstyle>
+ local copy = el:copy_node()
+ copy._name = "mtext"
+ copy._parent = el
+ el._children = {copy}
+ end
+end
+
+local function is_radical(el)
+ local radicals = {msup=true, msub=true, msubsup=true}
+ return radicals[el:get_element_name()]
+end
+
+local function get_mrow_child(el)
+ local get_first = function(x)
+ local children = x:get_children()
+ return children[1]
+ end
+ local first = get_first(el)
+ -- either return first child, and if the child is <mrow>, return it's first child
+ if first and first:is_element() then
+ if first:get_element_name() == "mrow" then
+ return get_first(first), first
+ else
+ return first
+ end
+ end
+end
+
+local function fix_radicals(el)
+ if is_radical(el) then
+ local first_child, mrow = get_mrow_child(el)
+ -- if the first child is only one character long, it is possible that there is a problem
+ if first_child and string.len(first_child:get_text()) == 1 then
+ local name = first_child:get_element_name()
+ local siblings = el:get_siblings()
+ local pos = el:find_element_pos()
+ -- it doesn't make sense to do any further processing if the element is at the beginning
+ if pos == 1 then return end
+ if name == "mo" then
+ for i = pos, 1,-1 do
+ end
+
+ end
+ end
+
+ end
+end
+
-- put <mrow> as child of <math> if it already isn't here
local allowed_top_mrow = {
math=true
@@ -73,24 +178,25 @@ local function top_mrow(math)
-- don't process elements that already are mrow
local parent = math:get_parent()
local parent_name
- if parent then parent_name = parent:get_element_name() end
- local current_name = math:get_element_name()
+ if parent then parent_name = get_element_name(parent) end
+ local current_name, prefix = get_element_name(math)
if #children < 2 or not allowed_top_mrow[current_name] or current_name == "mrow" or parent_name == "mrow" then return nil end
local mrow_count = 0
for _,v in ipairs(children) do
if v:is_element() and is_token_element(v) then
put_mrow = true
-- break
- elseif v:is_element() and v:get_element_name() == "mrow" then
+ elseif v:is_element() and get_element_name(v) == "mrow" then
mrow_count = mrow_count + 1
end
end
- if not put_mrow and math:get_element_name() == "math" and mrow_count == 0 then
+ if not put_mrow and get_element_name(math) == "math" and mrow_count == 0 then
-- put at least one <mrow> to each <math>
put_mrow = true
end
if put_mrow then
- local mrow = math:create_element("mrow")
+ local newname = get_new_element_name("mrow", prefix)
+ local mrow = math:create_element(newname)
for _, el in ipairs(children) do
mrow:add_child_node(el)
end
@@ -106,7 +212,9 @@ local function get_fence(el, attr, form)
local char = el:get_attribute(attr)
local mo
if char then
- mo = el:create_element("mo", {fence="true", form = form})
+ local name, prefix = get_element_name(el)
+ local newname = get_new_element_name("mo", prefix)
+ mo = el:create_element(newname, {fence="true", form = form})
mo:add_child_node(mo:create_text_node(char))
end
return mo
@@ -116,13 +224,15 @@ end
local function fix_mfenced(el)
-- TeX4ht uses in some cases <mfenced> element which is deprecated in MathML.
-- Firefox doesn't support it already.
- if el:get_element_name() == "mfenced" then
+ local name, prefix = get_element_name(el)
+ if name == "mfenced" then
-- we must replace it by <mrow><mo>start</mo><mfenced children...><mo>end</mo></mrow>
local open = get_fence(el, "open", "prefix")
local close = get_fence(el, "close", "postfix")
-- there can be also separator attribute, but it is not used in TeX4ht
-- change <mfenced> to <mrow> and remove all attributes
- el._name = "mrow"
+ local newname = get_new_element_name("mrow", prefix)
+ el._name = newname
el._attr = {}
-- open must be first child, close needs to be last
if open then el:add_child_node(open, 1) end
@@ -131,7 +241,7 @@ local function fix_mfenced(el)
end
local function is_fence(el)
- return el:get_element_name() == "mo" and el:get_attribute("fence") == "true"
+ return get_element_name(el) == "mo" and el:get_attribute("fence") == "true"
end
local function fix_mo_to_mfenced(el)
@@ -155,25 +265,27 @@ local function fix_mo_to_mfenced(el)
end
end
-- convert parent <mrow> to <mfenced>
- parent._name = "mfenced"
+ local _, prefix = get_element_name(parent)
+ local newname = get_new_element_name("mfenced", prefix)
+ parent._name = newname
parent._attr = {open = open, close = close}
end
end
local function fix_numbers(el)
-- convert <mn>1</mn><mo>.</mo><mn>3</mn> to <mn>1.3</mn>
- if el:get_element_name() == "mn" then
+ if get_element_name(el) == "mn" then
local n = el:get_sibling_node(1)
-- test if next element is <mo class="MathClass-punc">.</mo>
if n and n:is_element()
- and n:get_element_name() == "mo"
- and n:get_attribute("class") == "MathClass-punc"
+ and get_element_name(n) == "mo"
+ and get_attribute(n, "class") == "MathClass-punc"
and n:get_text() == "."
then
-- get next element and test if it is <mn>
local x = el:get_sibling_node(2)
if x and x:is_element()
- and x:get_element_name() == "mn"
+ and get_element_name(x) == "mn"
then
-- join numbers and set it as text content of the current element
local newnumber = el:get_text() .. "." .. x:get_text()
@@ -194,7 +306,7 @@ local function just_operators(list)
-- count <mo> and return true if list contains just them
local mo = 0
for _, x in ipairs(list) do
- if x:get_element_name() == "mo" then mo = mo + 1 end
+ if get_element_name(x) == "mo" then mo = mo + 1 end
end
return mo
end
@@ -205,18 +317,22 @@ local function fix_operators(x)
-- this fixes issues in LibreOffice with a^{*}
-- I hope it doesn't introduce different issues
-- process only <mo>
- if x:get_element_name() ~= "mo" then return nil end
+ local el_name, prefix = get_element_name(x)
+ if el_name ~= "mo" then return nil end
local siblings = x:get_siblings()
-- test if current element list contains only <mo>
if just_operators(siblings) == #siblings then
if #siblings == 1 then
- -- one <mo> translates to <mtext>
- x._name = "mtext"
- log:debug("changing one <mo> to <mtext>: " .. x:get_text())
- -- I think we should use <mi>, but LO incorrectly renders it in <msubsup>,
- -- even if we use the mathvariant="normal" attribute. <mtext> works, so
- -- we use that instead.
- -- x:set_attribute("mathvariant", "normal")
+ if not x:get_attribute("stretchy") then
+ -- one <mo> translates to <mtext>
+ local newname = get_new_element_name("mtext", prefix)
+ x._name = newname
+ log:debug("changing one <mo> to <mtext>: " .. x:get_text())
+ -- I think we should use <mi>, but LO incorrectly renders it in <msubsup>,
+ -- even if we use the mathvariant="normal" attribute. <mtext> works, so
+ -- we use that instead.
+ -- x:set_attribute("mathvariant", "normal")
+ end
else
-- multiple <mo> translate to <mtext>
local text = {}
@@ -231,7 +347,8 @@ local function fix_operators(x)
log:debug("changing <mo> to <mtext>: " .. newtext)
x:add_child_node(text_el)
-- change <mo> to <mtext>
- x._name = "mtext"
+ local newname = get_new_element_name("mtext", prefix)
+ x._name = newname
-- remove subsequent <mo>
for i = 2, #siblings do
siblings[i]:remove_node()
@@ -240,6 +357,47 @@ local function fix_operators(x)
end
end
+local function is_last_element(el)
+ local siblings = el:get_siblings()
+ -- return true only if the current element is the last in the parent's children
+ for i = #siblings, 1, -1 do
+ local curr = siblings[i]
+ if curr == el then
+ return true
+ elseif curr:is_element() then
+ return false
+ end
+ end
+ return false
+end
+
+local function is_empty_row(el)
+ -- empty row should contain only one <mtd>
+ local count = 0
+ if el:get_text():match("^%s*$") then
+ for _, child in ipairs(el:get_children()) do
+ if child:is_element() then count = count + 1 end
+ end
+ end
+ -- if there is one or zero childrens, then it is empty row
+ return count < 2
+end
+
+
+local function delete_last_empty_mtr(el)
+ -- arrays sometimes contain last empty row, which causes rendering issues,
+ -- so we should remove them
+ local el_name, prefix = get_element_name(el)
+ if el_name == "mtr"
+ and get_attribute(el, "class") == "array-row"
+ and is_last_element(el)
+ and is_empty_row(el)
+ then
+ el:remove_node()
+ end
+
+end
+
return function(dom)
dom:traverse_elements(function(el)
if settings.output_format ~= "odt" then
@@ -248,12 +406,15 @@ return function(dom)
else
fix_mo_to_mfenced(el)
end
+ fix_radicals(el)
fix_token_elements(el)
fix_nested_mstyle(el)
+ fix_missing_mtext(el)
fix_numbers(el)
fix_operators(el)
fix_mathvariant(el)
top_mrow(el)
+ delete_last_empty_mtr(el)
end)
return dom
end
diff --git a/support/make4ht/extensions/make4ht-ext-inlinecss.lua b/support/make4ht/extensions/make4ht-ext-inlinecss.lua
new file mode 100644
index 0000000000..105c29d3c3
--- /dev/null
+++ b/support/make4ht/extensions/make4ht-ext-inlinecss.lua
@@ -0,0 +1,16 @@
+local M = {}
+
+local filter = require "make4ht-domfilter"
+
+-- filters support only html formats
+function M.test(format)
+ if format:match("html") then return true end
+ return false
+end
+
+function M.modify_build(make)
+ local process = filter({"inlinecss"}, "inlinecss")
+ 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
index bf4dcdde5a..b9ed94b0dc 100644
--- a/support/make4ht/extensions/make4ht-ext-latexmk_build.lua
+++ b/support/make4ht/extensions/make4ht-ext-latexmk_build.lua
@@ -12,8 +12,31 @@ function M.modify_build(make)
first = pos
end
end
+ -- we need to save contents of the .tmp file, to prevent extra executions from latexmk
+ -- tex4ht command overwrites content that was set by LaTeX with it's own stuff
+ local tmp_file
+ make:add("save_tmp", function(par)
+ local f = io.open(par.input .. ".tmp", "r")
+ if f then
+ tmp_file = f:read("*all")
+ f:close()
+ end
+ return 0
+ end)
+ make:add("load_tmp", function(par)
+ if tmp_file then
+ local f = io.open(par.input .. ".tmp", "w")
+ if f then
+ f:write(tmp_file)
+ end
+ end
+ return 0
+ end)
-- if htlatex was found
if first then
+ -- handle tmp file
+ make:load_tmp {}
+ make:save_tmp {}
-- add dummy latexmk call to the build sequence
make:latexmk {}
-- replace name, command and type in the first htlatex
@@ -26,6 +49,21 @@ function M.modify_build(make)
-- remove the dummy latexmk
table.remove(build_seq)
end
+ -- remove htlatex calls from the build sequence, they are unnecessary
+ local new_build_seq = {}
+ for pos, v in ipairs(build_seq) do
+ if v.name ~= "htlatex" and v.name ~= "tex4ht" then
+ table.insert(new_build_seq, v)
+ elseif v.name == "tex4ht" then
+ -- insert save_tmp before tex4ht
+ table.insert(new_build_seq, build_seq[#build_seq])
+ -- remove save_tmp from the end
+ table.remove(build_seq)
+ -- and now insert tex4ht
+ table.insert(new_build_seq, v)
+ end
+ end
+ make.build_seq = new_build_seq
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
index 306c7bf772..763c25ea7e 100644
--- a/support/make4ht/extensions/make4ht-ext-preprocess_input.lua
+++ b/support/make4ht/extensions/make4ht-ext-preprocess_input.lua
@@ -6,7 +6,7 @@ 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}\''},
- render = { command = 'Rscript -e "library(rmarkdown); render(\'${tex_file}\', output_file=\'${tmp_file}\')"'}
+ render = { command = 'Rscript -e "library(rmarkdown); render(\'${tex_file}\', output_file=\'${tmp_file}\',output_format = \'latex_document\')"'}
}
local filetypes = {
rnw = {sequence = {"knitr"} },
@@ -17,6 +17,21 @@ local filetypes = {
rst = {sequence = {"pandoc"}, options = {input_format = "rst"}},
}
+local function get_temp_name(arg,curr, length)
+ -- we don't want to use the temp dir, because graphics would be then generated outside of
+ -- the directory of the source document. so we will make
+ local tmp_name = os.tmpname()
+ if pos == sequence then
+ -- base tmp_name on the input name in the last step of sequence
+ -- so the generated images won't have random names
+ tmp_name = arg.input .. "-preprocess_input"
+ else
+ tmp_name = tmp_name:match("([^/\\]+)$")
+ end
+ return tmp_name
+end
+
+
local function execute_sequence(sequence, arg, make)
-- keep track of all generated tmp files
@@ -25,8 +40,8 @@ local function execute_sequence(sequence, arg, make)
-- 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()
+ for pos, cmd_name in ipairs(sequence) do
+ local tmp_name = get_temp_name(arg,pos, #sequence)
temp_files[#temp_files+1] = tmp_name
-- make the temp file name accessible to the executed commands
arg.tmp_file = tmp_name
diff --git a/support/make4ht/extensions/make4ht-ext-tidy.lua b/support/make4ht/extensions/make4ht-ext-tidy.lua
index 8318a8b894..4bb0976b0d 100644
--- a/support/make4ht/extensions/make4ht-ext-tidy.lua
+++ b/support/make4ht/extensions/make4ht-ext-tidy.lua
@@ -44,9 +44,13 @@ function M.modify_build(make)
local command = "tidy ${options} ${filename}" % par
log:info("running tidy: ".. command)
-- os.execute(command)
- local run = io.popen(command, "r")
+ local run, msg = io.popen(command, "r")
local result = run:read("*all")
run:close()
+ if not result or result == "" then
+ log:warning("Cannot execute Tidy command")
+ return nil
+ end
result = close_tags(result)
local f = io.open(filename, "w")
f:write(result)
diff --git a/support/make4ht/formats/make4ht-jats.lua b/support/make4ht/formats/make4ht-jats.lua
index 13bcd86d41..41eabf8744 100644
--- a/support/make4ht/formats/make4ht-jats.lua
+++ b/support/make4ht/formats/make4ht-jats.lua
@@ -1,5 +1,168 @@
local M = {}
local xtpipeslib = require "make4ht-xtpipes"
+local domfilter = require "make4ht-domfilter"
+
+
+-- some elements need to be moved from the document flow to the document meta
+local article_meta
+local elements_to_move_to_meta = {}
+local function move_to_meta(el)
+ -- we don't move elements immediatelly, because it would prevent them from further
+ -- processing in the filter. so we save them in an array, and move them once
+ -- the full DOM was processed
+ table.insert(elements_to_move_to_meta, el)
+end
+
+local elements_to_move_to_title = {}
+local function move_to_title_group(el)
+ -- there can be only one title and subtitle
+ local name = el:get_element_name()
+ if not elements_to_move_to_title[name] then
+ elements_to_move_to_title[name] = el
+ end
+end
+
+local elements_to_move_to_contribs = {}
+local function move_to_contribs(el)
+ table.insert(elements_to_move_to_contribs, el)
+end
+
+
+
+local function process_moves()
+ if article_meta then
+ if elements_to_move_to_title["article-title"]
+ and #article_meta:query_selector("title_group") == 0 then -- don't move anything if user added title_group from a config file
+ local title_group = article_meta:create_element("title_group")
+ for _, name in ipairs{ "article-title", "subtitle" } do
+ local v = elements_to_move_to_title[name]
+ if v then
+ title_group:add_child_node(v:copy_node())
+ v:remove_node()
+ end
+ end
+ article_meta:add_child_node(title_group)
+ end
+ if #elements_to_move_to_contribs > 0 then
+ local contrib_group = article_meta:create_element("contrib-group")
+ for _, el in ipairs(elements_to_move_to_contribs) do
+ contrib_group:add_child_node(el:copy_node())
+ el:remove_node()
+ end
+ article_meta:add_child_node(contrib_group)
+ end
+ for _, el in ipairs(elements_to_move_to_meta) do
+ -- move elemnt's copy, and remove the original
+ article_meta:add_child_node(el:copy_node())
+ el:remove_node()
+ end
+ end
+end
+
+local function has_no_text(el)
+ -- detect if element contains only whitespace
+ if el:get_text():match("^%s*$") then
+ --- if it contains any elements, it has text
+ for _, child in ipairs(el:get_children()) do
+ if child:is_element() then return false end
+ end
+ return true
+ end
+ return false
+end
+
+local function is_xref_id(el)
+ return el:get_element_name() == "xref" and el:get_attribute("id") and el:get_attribute("rid") == nil and has_no_text(el)
+end
+-- set id to parent element for <xref> that contain only id
+local function xref_to_id(el)
+ local parent = el:get_parent()
+ -- set id only if it doesn't exist yet
+ if parent:get_attribute("id") == nil then
+ parent:set_attribute("id", el:get_attribute("id"))
+ el:remove_node()
+ end
+end
+
+local function make_text(el)
+ local text = el:get_text():gsub("^%s*", ""):gsub("%s*$", "")
+ local text_el = el:create_text_node(text)
+ el._children = {text_el}
+end
+
+local function is_empty_par(el)
+ return el:get_element_name() == "p" and has_no_text(el)
+end
+
+local function handle_links(el, params)
+ -- we must distinguish between internal links in the document, and external links
+ -- to websites etc. these needs to be changed to the <ext-link> element.
+ local link = el:get_attribute("rid")
+ if link then
+ -- try to remove \jobname.xml from the beginning of the link
+ -- if the rest starts with #, then it is an internal link
+ local local_link = link:gsub("^" .. params.input .. ".xml", "")
+ if local_link:match("^%#") then
+ el:set_attribute("rid", local_link)
+ else
+ -- change element to ext-link for extenal links
+ el._name = "ext-link"
+ el:set_attribute("rid", nil)
+ el:set_attribute("xlink:href", link)
+ end
+ end
+end
+
+local function handle_maketitle(el)
+ -- <maketitle> is special element produced by TeX4ht from LaTeX's \maketitle
+ -- we need to pick interesting info from there, and move it to the header
+ local function is_empty(selector)
+ return #article_meta:query_selector(selector) == 0
+ end
+ -- move <aff> to <contrib>
+ local affiliations = {}
+ for _, aff in ipairs(el:query_selector("aff")) do
+ local id = aff:get_attribute("id")
+ if id then
+ for _,mark in ipairs(aff:query_selector("affmark")) do mark:remove_node() end
+ affiliations[id] = aff:copy_node()
+ end
+ end
+ if is_empty("contrib") then
+ for _, contrib in ipairs(el:query_selector("contrib")) do
+ for _, affref in ipairs(contrib:query_selector("affref")) do
+ local id = affref:get_attribute("rid") or ""
+ -- we no longer need this node
+ affref:remove_node()
+ local linked_affiliation = affiliations[id]
+ if linked_affiliation then
+ contrib:add_child_node(linked_affiliation)
+ end
+ end
+ for _, string_name in ipairs(contrib:query_selector("string-name")) do
+ make_text(string_name)
+ end
+ move_to_contribs(contrib:copy_node())
+ -- we need to remove it from here, even though we remove <maketitle> later
+ -- we got doubgle contributors without that
+ contrib:remove_node()
+ end
+ end
+ if is_empty("pub-date") then
+ for _, date in ipairs(el:query_selector("date")) do
+ date._name = "pub-date"
+ for _, s in ipairs(date:query_selector("string-date")) do
+ make_text(s)
+ end
+ move_to_meta(date:copy_node())
+ end
+ end
+ el:remove_node()
+end
+
+
+
+
function M.prepare_parameters(settings, extensions)
settings.tex4ht_sty_par = settings.tex4ht_sty_par ..",jats"
@@ -11,4 +174,49 @@ function M.prepare_extensions(extensions)
return extensions
end
+function M.modify_build(make)
+ filter_settings("joincharacters", {charclasses = {italic=true, bold=true}})
+
+ local process = domfilter {
+ function(dom, params)
+ dom:traverse_elements(function(el)
+ -- some elements need special treatment
+ local el_name = el:get_element_name()
+ if is_xref_id(el) then
+ xref_to_id(el)
+ elseif el_name == "article-meta" then
+ -- save article-meta element for further processig
+ article_meta = el
+ elseif el_name == "article-title" then
+ move_to_title_group(el)
+ elseif el_name == "subtitle" then
+ move_to_title_group(el)
+ elseif el_name == "abstract" then
+ move_to_meta(el)
+ elseif el_name == "string-name" then
+ make_text(el)
+ elseif el_name == "contrib" then
+ move_to_contribs(el)
+ elseif is_empty_par(el) then
+ -- remove empty paragraphs
+ el:remove_node()
+ elseif el_name == "xref" then
+ handle_links(el, params)
+ elseif el_name == "maketitle" then
+ handle_maketitle(el)
+ elseif el_name == "div" and el:get_attribute("class") == "maketitle" then
+ el:remove_node()
+ end
+
+ end)
+ -- move elements that are marked for move
+ process_moves()
+ return dom
+ end, "joincharacters","mathmlfixes", "tablerows","booktabs"
+ }
+ local charclasses = {["mml:mi"] = true, ["mml:mn"] = true , italic = true, bold=true, roman = true, ["mml:mtext"] = true, mi=true, mn=true}
+ make:match("xml$", process, {charclasses = charclasses})
+ return make
+end
+
return M
diff --git a/support/make4ht/formats/make4ht-odt.lua b/support/make4ht/formats/make4ht-odt.lua
index 3f0ee3aaa8..7511ed481d 100644
--- a/support/make4ht/formats/make4ht-odt.lua
+++ b/support/make4ht/formats/make4ht-odt.lua
@@ -291,6 +291,9 @@ function M.modify_build(make)
local fixentities = filter {"entities-to-unicode", remove_xtpipes}
make:match("4oo", fixentities)
make:match("4om", fixentities)
+ -- we must handle outdir. make4ht copies the ODT file before it was packed, so
+ -- we will copy it again after packing later in this format file
+ local outdir = make.params["outdir"]
-- 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
@@ -305,7 +308,7 @@ function M.modify_build(make)
local lastfile = escape_file(lgfiles[#lgfiles]) .."$"
-- make match for the last file
-- odt packing will be done here
- make:match(lastfile, function()
+ make:match(lastfile, function(filename, par)
local groups = prepare_output_files(make.lgfile.files)
local basename = groups.odt[1]
local odtname = basename .. ".odt"
@@ -367,6 +370,12 @@ function M.modify_build(make)
end)
odt:pack()
+ if outdir and outdir ~= "" then
+ local filename = odt.name
+ local outfilename = outdir .. "/" .. filename
+ log:info("Copying ODT file to the output dir: " .. outfilename)
+ mkutils.copy(filename,outfilename)
+ end
end)
end
executed = true
diff --git a/support/make4ht/make4ht b/support/make4ht/make4ht
index 7d579fafea..f635895677 100755
--- a/support/make4ht/make4ht
+++ b/support/make4ht/make4ht
@@ -29,7 +29,7 @@ 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.3l"
+local version = "v0.3m"
mkparams.version_number = version
local args = mkparams.get_args()
@@ -120,7 +120,13 @@ make:match("tmp$", function(filename,params)
make:match(".*",function(filename,par)
local outdir = '' --par["outdir"] and par["outdir"] .."/" or ''
- if par['outdir'] ~= "" then outdir = par['outdir'] .. '/' end
+ if par['outdir'] ~= "" then
+ outdir = par['outdir'] .. '/'
+ else
+ -- don't run unnecessary copy without output dir
+ log:info("No output directory")
+ return true
+ end
log:info("outdir: "..outdir)
local outfilename = outdir .. filename
mkutils.copy(filename,outfilename)
diff --git a/support/make4ht/make4ht-doc.pdf b/support/make4ht/make4ht-doc.pdf
index bf3b9a4795..207f7135a8 100644
--- a/support/make4ht/make4ht-doc.pdf
+++ b/support/make4ht/make4ht-doc.pdf
Binary files differ
diff --git a/support/make4ht/make4ht-indexing.lua b/support/make4ht/make4ht-indexing.lua
index eb9c9b5017..746c062cb3 100644
--- a/support/make4ht/make4ht-indexing.lua
+++ b/support/make4ht/make4ht-indexing.lua
@@ -80,7 +80,7 @@ local parse_idx = function(content)
elseif line:match("^\\indexentry") then
-- replace the page number with the current
-- index entry number
- local result = line:gsub("{[0-9]+}", "{"..current_entry .."}")
+ local result = line:gsub("{[0-9]+}$", "{"..current_entry .."}")
buffer[#buffer+1] = get_utf8(result)
else
buffer[#buffer+1] = line
@@ -96,11 +96,14 @@ local fix_idx_pages = function(content, idxobj)
local entries = idxobj.map
for line in content:gmatch("([^\n]+)") do
local line = line:gsub("(%s*\\%a+.-%,)(.+)$", function(start,rest)
+ -- there is a problem when index term itself contains numbers, like Bible verses (1:2),
+ -- because they will be detected as page numbers too. I cannot find a good solution
+ -- that wouldn't break something else.
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{}"
+ return "\\Link[" .. entry.file .."]{".. entry.dest .."}{}" .. page .."\\EndLink{}"
else
return page
end
@@ -148,6 +151,7 @@ end
local prepare_tmp_idx = function(par)
par.idxfile = get_idxname(par)
+ if not par.idxfile or not mkutils.file_exists(par.idxfile) then return nil, "Cannot load idx file " .. (par.idxfile or "''") end
-- construct the .ind name, based on the .idx name
par.indfile = par.indfile or par.idxfile:gsub("idx$", "ind")
load_enc()
@@ -166,6 +170,7 @@ local splitindex = function(par)
local idxfiles = {}
local buffer
local idxfile = get_idxname(par)
+ if not idxfile or not mkutils.file_exists(idxfile) then return nil, "Cannot load idx file " .. (idxfile or "''") end
for line in io.lines(idxfile) do
local file = line:match("indexentry%[(.-)%]")
if file then
@@ -198,7 +203,7 @@ local function run_indexing_command (command, par)
local cmd_name = command:match("^[%a]+") or "indexing"
local xindylog = logging.new(cmd_name)
-- support split index
- local subindexes = splitindex(par)
+ local subindexes = splitindex(par) or {}
if #subindexes > 0 then
-- call the command again on all files produced by splitindex
for _, subindex in ipairs(subindexes) do
diff --git a/support/make4ht/mkutils.lua b/support/make4ht/mkutils.lua
index 6bcc4787c3..f7636b9d2a 100644
--- a/support/make4ht/mkutils.lua
+++ b/support/make4ht/mkutils.lua
@@ -7,17 +7,17 @@ local mkparams = require("mkparams")
local indexing = require("make4ht-indexing")
--template engine
function interp(s, tab)
- local tab = tab or {}
- return (s:gsub('($%b{})', function(w) return tab[w:sub(3, -2)] or w end))
+ local tab = tab or {}
+ return (s:gsub('($%b{})', function(w) return tab[w:sub(3, -2)] or w end))
end
--print( interp("${name} is ${value}", {name = "foo", value = "bar"}) )
function addProperty(s,prop)
- if prop ~=nil then
- return s .." "..prop
- else
- return s
- end
+ if prop ~=nil then
+ return s .." "..prop
+ else
+ return s
+ end
end
getmetatable("").__mod = interp
getmetatable("").__add = addProperty
@@ -39,27 +39,27 @@ function merge(t1, t2)
end
function string:split(sep)
- local sep, fields = sep or ":", {}
- local pattern = string.format("([^%s]+)", sep)
- self:gsub(pattern, function(c) fields[#fields+1] = c end)
- return fields
+ local sep, fields = sep or ":", {}
+ local pattern = string.format("([^%s]+)", sep)
+ self:gsub(pattern, function(c) fields[#fields+1] = c end)
+ return fields
end
function remove_extension(path)
- local found, len, remainder = string.find(path, "^(.*)%.[^%.]*$")
- if found then
- return remainder
- else
- return path
- end
+ local found, len, remainder = string.find(path, "^(.*)%.[^%.]*$")
+ if found then
+ return remainder
+ else
+ return path
+ end
end
--
-- check if file exists
function file_exists(file)
- local f = io.open(file, "rb")
- if f then f:close() end
- return f ~= nil
+ local f = io.open(file, "rb")
+ if f then f:close() end
+ return f ~= nil
end
-- check if Lua module exists
@@ -90,18 +90,18 @@ function parse_lg(filename)
else
local usedfiles={}
for line in io.lines(filename) do
- --- needs --- pokus.idv[1] ==> pokus0x.png ---
+ --- needs --- pokus.idv[1] ==> pokus0x.png ---
-- line:gsub("needs --- (.+?)[([0-9]+) ==> ([%a%d%p%.%-%_]*)",function(name,page,k) table.insert(outputimages,k)end)
- line:gsub("needs %-%-%- (.+)%[([0-9]+)%] ==> ([%a%d%p%.%-%_]*)",
- function(file,page,output)
- local rec = {
- source = file,
- page=page,
- output = output
- }
- table.insert(outputimages,rec)
- end
- )
+ line:gsub("needs %-%-%- (.+)%[([0-9]+)%] ==> (.*) %-%-%-",
+ function(file,page,output)
+ local rec = {
+ source = file,
+ page=page,
+ output = output
+ }
+ table.insert(outputimages,rec)
+ end
+ )
line:gsub("File: (.*)", function(k)
if not usedfiles[k] then
table.insert(outputfiles,k)
@@ -137,20 +137,20 @@ function cp(src,dest)
-- try to find file using kpse library if it cannot be found
src = kpse.find_file(src) or src
end
- local command = string.format('%s "%s" "%s"', cp_func, src, dest)
- if cp_func == "copy" then command = command:gsub("/",'\\') end
- log:info("Copy: "..command)
+ local command = string.format('%s "%s" "%s"', cp_func, src, dest)
+ if cp_func == "copy" then command = command:gsub("/",'\\') end
+ log:info("Copy: "..command)
if not file_exists(src) then
log:error("File " .. src .. " doesn't exist")
end
- os.execute(command)
+ os.execute(command)
end
function mv(src, dest)
local mv_func = os.type == "unix" and "mv " or "move "
- local command = string.format('%s "%s" "%s"', mv_func, 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
+ if mv_func == "move" then command = command:gsub("/",'\\') end
log:info("Move: ".. command)
os.execute(command)
end
@@ -163,61 +163,61 @@ end
local used_dir = {}
function prepare_path(path)
- --local dirs = path:split("/")
- local dirs = {}
- if path:match("^/") then dirs = {""}
- elseif path:match("^~") then
- local home = os.getenv "HOME"
- dirs = home:split "/"
- path = path:gsub("^~/","")
- table.insert(dirs,1,"")
- end
- if path:match("/$")then path = path .. " " end
- for _,d in pairs(path:split "/") do
- table.insert(dirs,d)
- end
- table.remove(dirs,#dirs)
- return dirs,table.concat(dirs,"/")
+ --local dirs = path:split("/")
+ local dirs = {}
+ if path:match("^/") then dirs = {""}
+ elseif path:match("^~") then
+ local home = os.getenv "HOME"
+ dirs = home:split "/"
+ path = path:gsub("^~/","")
+ table.insert(dirs,1,"")
+ end
+ if path:match("/$")then path = path .. " " end
+ for _,d in pairs(path:split "/") do
+ table.insert(dirs,d)
+ end
+ table.remove(dirs,#dirs)
+ return dirs,table.concat(dirs,"/")
end
-- Find which part of path already exists
-- and which directories have to be created
function find_directories(dirs, pos)
- local pos = pos or #dirs
- -- we tried whole path and no dir exist
- if pos < 1 then return dirs end
- local path = ""
- -- in the case of unix absolute path, empty string is inserted in dirs
- if pos == 1 and dirs[pos] == "" then
- path = "/"
- else
- path = table.concat(dirs,"/", 1,pos) .. "/"
- end
- if not lfs.chdir(path) then -- recursion until we succesfully changed dir
- -- or there are no elements in the dir table
- return find_directories(dirs,pos - 1)
+ local pos = pos or #dirs
+ -- we tried whole path and no dir exist
+ if pos < 1 then return dirs end
+ local path = ""
+ -- in the case of unix absolute path, empty string is inserted in dirs
+ if pos == 1 and dirs[pos] == "" then
+ path = "/"
+ else
+ path = table.concat(dirs,"/", 1,pos) .. "/"
+ end
+ if not lfs.chdir(path) then -- recursion until we succesfully changed dir
+ -- or there are no elements in the dir table
+ return find_directories(dirs,pos - 1)
elseif pos ~= #dirs then -- if we succesfully changed dir
- -- and we have dirs to create
- local p = {}
- for i = pos+1, #dirs do
- table.insert(p, dirs[i])
- end
- return p
+ -- and we have dirs to create
+ local p = {}
+ for i = pos+1, #dirs do
+ table.insert(p, dirs[i])
+ end
+ return p
else -- whole path exists
- return {}
+ return {}
end
end
function mkdirectories(dirs)
- if type(dirs) ~="table" then
- return false, "mkdirectories: dirs is not table"
- end
- for _,d in ipairs(dirs) do
- local stat,msg = lfs.mkdir(d)
- if not stat then return false, "makedirectories error: "..msg end
- lfs.chdir(d)
- end
- return true
+ if type(dirs) ~="table" then
+ return false, "mkdirectories: dirs is not table"
+ end
+ for _,d in ipairs(dirs) do
+ local stat,msg = lfs.mkdir(d)
+ if not stat then return false, "makedirectories error: "..msg end
+ lfs.chdir(d)
+ end
+ return true
end
function copy_filter(src,dest, filter)
@@ -233,22 +233,22 @@ end
function copy(filename,outfilename)
- local currdir = lfs.currentdir()
- if filename == outfilename then return true end
- local parts, path = prepare_path(outfilename)
- if not used_dir[path] then
- local to_create, msg = find_directories(parts)
- if not to_create then
- log:warning(msg)
- return false
- end
- used_dir[path] = true
- local stat, msg = mkdirectories(to_create)
- if not stat then log:warning(msg) end
- end
- lfs.chdir(currdir)
- cp(filename, path)
- return true
+ local currdir = lfs.currentdir()
+ if filename == outfilename then return true end
+ local parts, path = prepare_path(outfilename)
+ if not used_dir[path] then
+ local to_create, msg = find_directories(parts)
+ if not to_create then
+ log:warning(msg)
+ return false
+ end
+ used_dir[path] = true
+ local stat, msg = mkdirectories(to_create)
+ if not stat then log:warning(msg) end
+ end
+ lfs.chdir(currdir)
+ cp(filename, path)
+ return true
end
function execute(command)
@@ -373,11 +373,14 @@ env.Make:add("httex", htlatex.httex, {
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
+ local command = Make.latex_command
+ -- add " %O " after the engine name. it should be filled by latexmk
+ command = command:gsub("%s", " %%O ", 1)
par.expanded = command % par
-- quotes in latex_command must be escaped, they cause Latexmk error
par.expanded = par.expanded:gsub('"', '\\"')
- local newcommand = 'latexmk -latex="${expanded}" -dvi ${tex_file}' % par
+ local newcommand = 'latexmk -pdf- -ps- -auxdir=. -outdir=. -latex="${expanded}" -dvi -jobname=${input} ${tex_file}' % par
+ log:info("LaTeX call: " .. newcommand)
os.execute(newcommand)
return Make.testlogfile(par)
end, {correct_exit= 0})
@@ -406,7 +409,7 @@ env.Make:add("tex4ht",function(par)
log:info("executing: " .. command)
return execute(command)
end
- , nil, 1)
+, nil, 1)
env.Make:add("t4ht","t4ht ${t4ht_par} \"${input}.${ext}\"",{ext="dvi"},1)
env.Make:add("clean", function(par)
@@ -439,7 +442,7 @@ env.Make:add("clean", function(par)
end
Make:match("tmp$", function()
-- remove temporary and auxilary files
- for _,ext in ipairs {"aux", "xref", "tmp", "4tc", "4ct", "idv", "lg","dvi", "log"} do
+ for _,ext in ipairs {"aux", "xref", "tmp", "4tc", "4ct", "idv", "lg","dvi", "log", "ncx"} do
remove_file(main_name .. "." .. ext)
end
end)
diff --git a/support/make4ht/readme.tex b/support/make4ht/readme.tex
index db45e582d5..98a0712899 100644
--- a/support/make4ht/readme.tex
+++ b/support/make4ht/readme.tex
@@ -358,8 +358,10 @@ It supports also Plain \TeX, use for example \texttt{tex} or
\item[dvisvgm\_hashes]
efficient generation of SVG pictures using Dvisvgm. It can utilize
multiple processor cores and generates only changed images.
+\item[inlinecss]
+load the \texttt{inlinecss} DOM filter.
\item[join\_colors]
-load the \texttt{joincolors} domfilter for all HTML files.
+load the \texttt{joincolors} DOM filter for all HTML files.
\item[latexmk\_build]
use \href{https://ctan.org/pkg/latexmk?lang=en}{Latexmk} for the
\LaTeX~compilation.
@@ -724,6 +726,10 @@ put all inline elements which are direct children of the
\item[idcolons]
replace the colon (\texttt{:}) character in internal links and
\texttt{id} attributes. They cause validation issues.
+\item[inlinecss]
+remove CSS rules that target elements with unique attributes, such as
+color boxes, table rules, or inline math pictures, and insert their
+properties as a inline \texttt{style} attribute in the HTML document.
\item[joincharacters]
join consecutive \texttt{\textless{}span\textgreater{}} or
\texttt{\textless{}mn\textgreater{}} elements. This DOM filter
@@ -733,7 +739,9 @@ many \texttt{\textless{}span\textgreater{}} elements with unique
\texttt{id} attributes are created when \LaTeX~colors are being used in
the document. A CSS rule is added for each of these elements, which may
result in substantial growth of the CSS file. This filter replaces these
-rules with a common one for elements with the same color value.
+rules with a common one for elements with the same color value. See also
+the \texttt{inlinecss} DOM filter and extension, which provides an
+alternative using inline styles.
\item[odtfonts]
fix styles for fonts that were wrongly converted by \texttt{Xtpipes} in
the ODT format.